254 lines
20 KiB
MQL5
254 lines
20 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| NeuronDropout.mqh |
|
|
//| Copyright 2021, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2021, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com"
|
|
//+------------------------------------------------------------------+
|
|
//| Подключаем библиотеки |
|
|
//+------------------------------------------------------------------+
|
|
#include "neuronbase.mqh"
|
|
//+------------------------------------------------------------------+
|
|
//| Class CNeuronDropout |
|
|
//| Назначение: Класс реализации метода Dropout |
|
|
//+------------------------------------------------------------------+
|
|
class CNeuronDropout : public CNeuronBase
|
|
{
|
|
protected:
|
|
double m_dOutProbability;
|
|
int m_iOutNumber;
|
|
double m_dInitValue;
|
|
|
|
CBufferDouble *m_cDropOutMultiplier;
|
|
|
|
public:
|
|
CNeuronDropout(void);
|
|
~CNeuronDropout(void);
|
|
//---
|
|
virtual bool Init(CLayerDescription *description);
|
|
virtual bool FeedForward(CNeuronBase *prevLayer);
|
|
virtual bool CalcHiddenGradient(CNeuronBase *prevLayer);
|
|
virtual bool CalcDeltaWeights(CNeuronBase *prevLayer) { return true; }
|
|
virtual bool UpdateWeights(int batch_size, double learningRate,
|
|
double &Beta[], double &Lambda[])
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//--- Методы работы с файлами
|
|
virtual bool Save(const int file_handle);
|
|
virtual bool Load(const int file_handle);
|
|
//--- Метод идентификации объекта
|
|
virtual int Type(void) const { return(defNeuronDropout); }
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Конструктор класса |
|
|
//+------------------------------------------------------------------+
|
|
CNeuronDropout::CNeuronDropout(void) : m_dInitValue(1.0),
|
|
m_dOutProbability(0),
|
|
m_iOutNumber(0)
|
|
{
|
|
m_cDropOutMultiplier = new CBufferDouble();
|
|
m_bTrain = false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Деструктор класса |
|
|
//+------------------------------------------------------------------+
|
|
CNeuronDropout::~CNeuronDropout(void)
|
|
{
|
|
if(CheckPointer(m_cDropOutMultiplier) != POINTER_INVALID)
|
|
delete m_cDropOutMultiplier;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Метод инициализации класса |
|
|
//+------------------------------------------------------------------+
|
|
bool CNeuronDropout::Init(CLayerDescription *description)
|
|
{
|
|
//--- Блок контролей
|
|
if(!CheckPointer(description) == POINTER_INVALID ||
|
|
description.count != description.window)
|
|
return false;
|
|
description.window = 0;
|
|
if(!CNeuronBase::Init(description))
|
|
return false;
|
|
//--- Расчёт коэффициентов
|
|
m_dOutProbability = MathMin(description.probability, 0.9);
|
|
if(m_dOutProbability < 0)
|
|
return false;
|
|
m_iOutNumber = (int)(m_cOutputs.Total() * m_dOutProbability);
|
|
m_dInitValue = 1.0 / (1.0 - m_dOutProbability);
|
|
if(CheckPointer(m_cDropOutMultiplier) == POINTER_INVALID)
|
|
{
|
|
m_cDropOutMultiplier = new CBufferDouble();
|
|
if(CheckPointer(m_cDropOutMultiplier) == POINTER_INVALID)
|
|
return false;
|
|
}
|
|
//--- Инициируем буфер маскирования
|
|
if(!m_cDropOutMultiplier.BufferInit(m_cOutputs.Rows(), m_cOutputs.Cols(), m_dInitValue))
|
|
return false;
|
|
m_bTrain = true;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Метод прямого прохода |
|
|
//+------------------------------------------------------------------+
|
|
bool CNeuronDropout::FeedForward(CNeuronBase *prevLayer)
|
|
{
|
|
//--- Блок контролей
|
|
if(!prevLayer || !prevLayer.GetOutputs() || !m_cOutputs || !m_cDropOutMultiplier)
|
|
return false;
|
|
//--- Провеверка флага режима работы
|
|
if(!m_bTrain)
|
|
{
|
|
m_cOutputs.m_mMatrix = prevLayer.GetOutputs().m_mMatrix;
|
|
if(m_cOpenCL && !m_cOutputs.BufferWrite())
|
|
return false;
|
|
return true;
|
|
}
|
|
//--- Генерируем тензор маскирования данных
|
|
uint total = m_cOutputs.Total();
|
|
if(!m_cDropOutMultiplier.m_mMatrix.Fill(m_dInitValue))
|
|
return false;
|
|
for(int i = 0; i < m_iOutNumber; i++)
|
|
{
|
|
int pos = (int)(MathRand() * MathRand() / MathPow(32767.0, 2) * total);
|
|
if(m_cDropOutMultiplier.m_mMatrix.Flat(pos) == 0)
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
if(!m_cDropOutMultiplier.m_mMatrix.Flat(pos, 0))
|
|
return false;
|
|
}
|
|
//--- Разветвление алгоритма в зависимости от устройста выполнениия операций
|
|
if(!m_cOpenCL)
|
|
{
|
|
m_cOutputs.m_mMatrix = prevLayer.GetOutputs().m_mMatrix * m_cDropOutMultiplier.m_mMatrix;
|
|
}
|
|
else // Блок OpenCL
|
|
{
|
|
//--- Создание буферов данных
|
|
CBufferDouble *inputs = prevLayer.GetOutputs();
|
|
if(inputs.GetIndex() < 0)
|
|
return false;
|
|
if(m_cDropOutMultiplier.GetIndex() < 0 && !m_cDropOutMultiplier.BufferCreate(m_cOpenCL))
|
|
return false;
|
|
if(m_cOutputs.GetIndex() < 0)
|
|
return false;
|
|
//--- Передача параметров кернелу
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_MaskMult, def_mask_inputs, inputs.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_MaskMult, def_mask_mask, m_cDropOutMultiplier.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_MaskMult, def_mask_outputs, m_cOutputs.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_MaskMult, def_mask_total, total))
|
|
return false;
|
|
//--- Постановка в очередь выполнения
|
|
int off_set[] = {0};
|
|
int NDRange[] = { (int)(total + 3) / 4};
|
|
if(!m_cOpenCL.Execute(def_k_MaskMult, 1, off_set, NDRange))
|
|
return false;
|
|
//--- Получение результатов
|
|
if(!m_cOutputs.BufferRead())
|
|
return false;
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Метод распределения градиента через скрытый слой |
|
|
//+------------------------------------------------------------------+
|
|
bool CNeuronDropout::CalcHiddenGradient(CNeuronBase *prevLayer)
|
|
{
|
|
//--- Блок контролей
|
|
if(CheckPointer(prevLayer) == POINTER_INVALID ||
|
|
CheckPointer(prevLayer.GetGradients()) == POINTER_INVALID ||
|
|
CheckPointer(m_cGradients) == POINTER_INVALID ||
|
|
CheckPointer(m_cDropOutMultiplier) == POINTER_INVALID)
|
|
return false;
|
|
//--- Провеверка флага режима работы
|
|
if(!m_bTrain)
|
|
{
|
|
prevLayer.GetGradients().m_mMatrix = m_cGradients.m_mMatrix;
|
|
if(m_cOpenCL && !prevLayer.GetGradients().BufferWrite())
|
|
return false;
|
|
}
|
|
//--- Разветвление алгоритма в зависимости от устройста выполнениия операций
|
|
uint total = m_cOutputs.Total();
|
|
if(CheckPointer(m_cOpenCL) == POINTER_INVALID)
|
|
{
|
|
prevLayer.GetGradients().m_mMatrix = m_cGradients.m_mMatrix * m_cDropOutMultiplier.m_mMatrix;
|
|
}
|
|
else // Блок OpenCL
|
|
{
|
|
//--- Создание буферов данных
|
|
CBufferDouble *prev = prevLayer.GetGradients();
|
|
if(prev.GetIndex() < 0)
|
|
return false;
|
|
if(m_cDropOutMultiplier.GetIndex() < 0)
|
|
return false;
|
|
if(m_cGradients.GetIndex() < 0)
|
|
return false;
|
|
//--- Передача параметров кернелу
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_MaskMult, def_mask_inputs, m_cGradients.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_MaskMult, def_mask_mask, m_cDropOutMultiplier.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_MaskMult, def_mask_outputs, prev.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_MaskMult, def_mask_total, total))
|
|
return false;
|
|
//--- Постановка в очередь выполнения
|
|
int off_set[] = {0};
|
|
int NDRange[] = { (int)(total + 3) / 4 };
|
|
if(!m_cOpenCL.Execute(def_k_MaskMult, 1, off_set, NDRange))
|
|
return false;
|
|
//--- Получение результатов
|
|
if(!prev.BufferRead())
|
|
return false;
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Метод сохранения элементов класса в файл |
|
|
//+------------------------------------------------------------------+
|
|
bool CNeuronDropout::Save(const int file_handle)
|
|
{
|
|
//--- Вызов метода родительского класса
|
|
if(!CNeuronBase::Save(file_handle))
|
|
return false;
|
|
//--- Сохраняем константу вероятности "выкидывания" элементов
|
|
if(FileWriteDouble(file_handle, m_dOutProbability) <= 0)
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Метод восстановления класса из сохранённых данных |
|
|
//+------------------------------------------------------------------+
|
|
bool CNeuronDropout::Load(const int file_handle)
|
|
{
|
|
//--- Вызов метода родительского класса
|
|
if(!CNeuronBase::Load(file_handle))
|
|
return false;
|
|
//--- Считывание и восстановление констант
|
|
m_dOutProbability = FileReadDouble(file_handle);
|
|
m_iOutNumber = (int)(m_cOutputs.Total() * m_dOutProbability);
|
|
m_dInitValue = 1.0 / (1.0 - m_dOutProbability);
|
|
//--- Инициализация буфера маскированиия данных
|
|
if(CheckPointer(m_cDropOutMultiplier) == POINTER_INVALID)
|
|
{
|
|
m_cDropOutMultiplier = new CBufferDouble();
|
|
if(CheckPointer(m_cDropOutMultiplier) == POINTER_INVALID)
|
|
return false;
|
|
}
|
|
if(!m_cDropOutMultiplier.BufferInit(m_cOutputs.Rows(),m_cOutputs.Cols(), m_dInitValue))
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|