NeuroNetworksBook/Include/realization/neuronnet.mqh
super.admin 4a9222852c convert
2025-05-30 16:12:34 +02:00

895 lines
61 KiB
MQL5

//+------------------------------------------------------------------+
//| NeuronNet.mqh |
//| Copyright 2021, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link "https://www.mql5.com"
//+------------------------------------------------------------------+
//| Подключаем библиотеки |
//+------------------------------------------------------------------+
#include "arraylayers.mqh"
#include "positionencoder.mqh"
#include "lossfunction.mqh"
//+------------------------------------------------------------------+
//| Class CNet |
//| Назначение: Базовій диспетчерский класс организации работы |
//| нейронной сети |
//+------------------------------------------------------------------+
class CNet : public CObject
{
protected:
bool m_bTrainMode;
CArrayLayers *m_cLayers;
CMyOpenCL *m_cOpenCL;
bool m_bOpenCL;
double m_dNNLoss;
int m_iLossSmoothFactor;
CPositionEncoder *m_cPositionEncoder;
bool m_bPositionEncoder;
CLossFunction *m_cLossFunction;
double m_adLambda[2];
double m_dLearningRate;
double m_adBeta[2];
public:
CNet(void);
~CNet(void);
//--- Методы создания объекта
bool Create(CArrayObj *descriptions);
bool Create(CArrayObj *descriptions, double learning_rate,
double beta1, double beta2);
bool Create(CArrayObj *descriptions, ENUM_LOSS_FUNCTION loss_function,
double lambda1, double lambda2);
bool Create(CArrayObj *descriptions, double learning_rate, double beta1,
double beta2, ENUM_LOSS_FUNCTION loss_function, double lambda1,
double lambda2);
//--- Организация работы с OpenCL
void UseOpenCL(bool value);
bool UseOpenCL(void) const { return(m_bOpenCL); }
bool InitOpenCL(void);
//--- Методы работы с позиционным колированием
void UsePositionEncoder(bool value);
bool UsePositionEncoder(void) const { return(m_bPositionEncoder); }
//--- Организация основных алгоритмов работы модели
bool FeedForward(const CBufferDouble *inputs);
bool Backpropagation(CBufferDouble *target);
bool UpdateWeights(uint batch_size = 1);
bool GetResults(CBufferDouble *&result);
void SetLearningRates(double learning_rate, double beta1 = 0.9,
double beta2 = 0.999);
//--- Методы функции потерь
bool LossFunction(ENUM_LOSS_FUNCTION loss_function, double lambda1 = 0,
double lambda2 = 0);
ENUM_LOSS_FUNCTION LossFunction(void) const { return(m_cLossFunction.LossFunction());}
ENUM_LOSS_FUNCTION LossFunction(double &lambda1, double &lambda2);
double GetRecentAverageLoss(void) const { return(m_dNNLoss); }
void LossSmoothFactor(int value) { m_iLossSmoothFactor = value;}
int LossSmoothFactor(void) const { return(m_iLossSmoothFactor);}
//--- Управление режимом работы модели
bool TrainMode(void) const { return m_bTrainMode; }
void TrainMode(bool mode);
//--- Методы работы с файлами
virtual bool Save(string file_name = NULL);
virtual bool Save(const int file_handle);
virtual bool Load(string file_name = NULL, bool common = false);
virtual bool Load(const int file_handle);
//--- Метод идентификации объекта
virtual int Type(void) const { return(defNeuronNet); }
//--- Получение указателей на внутренние объекты
virtual CBufferDouble *GetGradient(uint layer) const;
virtual CBufferDouble *GetWeights(uint layer) const;
virtual CBufferDouble *GetDeltaWeights(uint layer) const;
virtual int GetGPTUnits(void);
};
//+------------------------------------------------------------------+
//| Конструктор класса |
//+------------------------------------------------------------------+
CNet::CNet(void) : m_bTrainMode(false),
m_bOpenCL(false),
m_bPositionEncoder(false),
m_dNNLoss(-1),
m_iLossSmoothFactor(1000),
m_dLearningRate(3.0e-4),
m_cLossFunction(NULL)
{
ArrayInitialize(m_adLambda, 0);
ArrayInitialize(m_adBeta, 0);
m_cLayers = new CArrayLayers();
m_cOpenCL = new CMyOpenCL();
m_cPositionEncoder = new CPositionEncoder();
}
//+------------------------------------------------------------------+
//| Деструктор класса |
//+------------------------------------------------------------------+
CNet::~CNet(void)
{
if(m_cLayers)
delete m_cLayers;
if(m_cOpenCL)
delete m_cOpenCL;
if(m_cPositionEncoder)
delete m_cPositionEncoder;
if(m_cLossFunction)
delete m_cLossFunction;
}
//+------------------------------------------------------------------+
//| Метод инициализации класса |
//+------------------------------------------------------------------+
bool CNet::Create(CArrayObj *descriptions)
{
//--- Блок контролей
if(!descriptions)
return false;
//--- Проверяем количество создаваемых слоёв
int total = descriptions.Total();
if(total < 2)
return false;
//--- Инициализируем объеты OpenCL
if(m_bOpenCL)
m_bOpenCL = InitOpenCL();
if(!m_cLayers.SetOpencl(m_cOpenCL))
m_bOpenCL = false;
//--- Организовываем цикл для создания нейронных слоёв
for(int i = 0; i < total; i++)
{
CLayerDescription *temp = descriptions.At(i);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(i == 0)
{
if(temp.type != defNeuronBase)
return false;
temp.window = 0;
}
else
{
CLayerDescription *prev = descriptions.At(i - 1);
if(temp.window <= 0 || temp.window > prev.count || temp.type == defNeuronBase)
{
switch(prev.type)
{
case defNeuronConv:
case defNeuronProof:
temp.window = prev.count * prev.window_out;
break;
default:
temp.window = prev.count;
break;
}
switch(temp.type)
{
case defNeuronAttention:
case defNeuronMHAttention:
case defNeuronGPT:
break;
default:
temp.step = 0;
}
}
}
if(!m_cLayers.CreateElement(i, temp))
return false;
}
//--- Инициализируем объекты позиционного кодирования
if(m_bPositionEncoder)
{
if(!m_cPositionEncoder)
{
m_cPositionEncoder = new CPositionEncoder();
if(!m_cPositionEncoder)
m_bPositionEncoder = false;
return true;
}
CLayerDescription *temp = descriptions.At(0);
if(!m_cPositionEncoder.InitEncoder(temp.count, temp.window))
UsePositionEncoder(false);
}
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод инициализации класса |
//+------------------------------------------------------------------+
bool CNet::Create(CArrayObj *descriptions,
double learning_rate,
double beta1, double beta2,
ENUM_LOSS_FUNCTION loss_function,double lambda1, double lambda2)
{
if(!Create(descriptions))
return false;
SetLearningRates(learning_rate, beta1, beta2);
if(!LossFunction(loss_function, lambda1, lambda2))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод инициализации класса |
//+------------------------------------------------------------------+
bool CNet::Create(CArrayObj *descriptions,ENUM_LOSS_FUNCTION loss_function,double lambda1,double lambda2)
{
if(!Create(descriptions))
return false;
if(!LossFunction(loss_function, lambda1, lambda2))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод инициализации класса |
//+------------------------------------------------------------------+
bool CNet::Create(CArrayObj *descriptions,
double learning_rate,
double beta1, double beta2)
{
if(!Create(descriptions))
return false;
SetLearningRates(learning_rate, beta1, beta2);
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод прямого прохода |
//+------------------------------------------------------------------+
bool CNet::FeedForward(const CBufferDouble *inputs)
{
//--- Блок контролей
if(!inputs)
{
PrintFormat("%s - %d", __FUNCTION__, __LINE__);
return false;
}
CNeuronBase *InputLayer = m_cLayers.At(0);
if(!InputLayer)
{
PrintFormat("%s - %d", __FUNCTION__, __LINE__);
return false;
}
CBufferDouble *Inputs = InputLayer.GetOutputs();
if(!Inputs)
{
PrintFormat("%s - %d", __FUNCTION__, __LINE__);
return false;
}
if(Inputs.Total() != inputs.Total())
{
PrintFormat("%s - %d", __FUNCTION__, __LINE__);
return false;
}
//--- Переносим исходные данные в нейронный слой
Inputs.m_mMatrix = inputs.m_mMatrix;
//--- Применяем позиционное кодированиеи
if(m_bPositionEncoder && !m_cPositionEncoder.AddEncoder(Inputs))
{
PrintFormat("%s - %d", __FUNCTION__, __LINE__);
return false;
}
if(m_bOpenCL)
Inputs.BufferCreate(m_cOpenCL);
//--- Организовываем цикл с полным перебором всех нейронных слоёв
//--- и вызовом метода прямого прохода для каждого из них
CNeuronBase *PrevLayer = InputLayer;
int total = m_cLayers.Total();
for(int i = 1; i < total; i++)
{
CNeuronBase *Layer = m_cLayers.At(i);
if(!Layer)
{
PrintFormat("%s - %d Layer %d", __FUNCTION__, __LINE__, i);
return false;
}
if(!Layer.FeedForward(PrevLayer))
{
PrintFormat("%s - %d Layer %d", __FUNCTION__, __LINE__, i);
return false;
}
PrevLayer = Layer;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод организации обратного прохода |
//+------------------------------------------------------------------+
bool CNet::Backpropagation(CBufferDouble *target)
{
//--- Блок контролей
if(!target)
return false;
int total = m_cLayers.Total();
CNeuronBase *Output = m_cLayers.At(total - 1);
if(!Output)
return false;
//--- Расчет значения функции потерь
double loss = m_cLossFunction.Calculate(Output.GetOutputs(),target);
if(loss == DBL_MAX)
return false;
m_dNNLoss = (m_dNNLoss < 0 ? loss : m_dNNLoss + (loss - m_dNNLoss) / m_iLossSmoothFactor);
//--- Расчет градиента ошибки на выходе нейронной сети
if(m_cOpenCL)
{
if(!target.BufferCreate(m_cOpenCL))
return false;
}
if(!Output.CalcOutputGradient(target))
{
return false;
}
target.BufferFree();
//--- Организовываем цикл с перебором всех нейронных слоёв в обратном порядке
for(int i = total - 2; i >= 0; i--)
{
CNeuronBase *temp = m_cLayers.At(i);
if(!temp)
return false;
//--- Вызываем метода распределения градиента ошибки через скрытый слой
if(!Output.CalcHiddenGradient(temp))
return false;
//--- Вызываем метод распределения градиента ошибки до матрицы весов
if(!Output.CalcDeltaWeights(temp))
return false;
Output = temp;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод обновления матриц весовых коэффициентов |
//+------------------------------------------------------------------+
bool CNet::UpdateWeights(uint batch_size = 1)
{
//--- Блок контролей
if(batch_size <= 0)
return false;
//--- Организовываем цикл перебора всех скрытых слоёв
int total=m_cLayers.Total();
for(int i = 1; i < total; i++)
{
//--- Проверяем действительность указателя на объект нейронного слоя
CNeuronBase *temp = m_cLayers.At(i);
if(!temp)
return false;
//--- Вызываем метод обновления матрицы весов внутреннего слоя
if(!temp.UpdateWeights(batch_size, m_dLearningRate, m_adBeta, m_adLambda))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод получения результата прямого прохода |
//+------------------------------------------------------------------+
bool CNet::GetResults(CBufferDouble *&result)
{
int total = m_cLayers.Total();
CNeuronBase *temp = m_cLayers.At(total - 1);
if(!temp)
return false;
CBufferDouble *output=temp.GetOutputs();
if(!output)
return false;
if(!result)
{
result = new CBufferDouble();
if(!result)
return false;
}
//if(!result.m_mMatrix.Init(output.m_mMatrix.Rows(),output.m_mMatrix.Cols()))
// {
// delete result;
// return false;
// }
//if(m_cOpenCL)
// if(!output.BufferRead())
// return false;
result.m_mMatrix=output.m_mMatrix;
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод сохранение элементов класса в файл |
//+------------------------------------------------------------------+
bool CNet::Save(string file_name = NULL)
{
//--- Блок контролей
if(file_name == NULL || file_name == "")
file_name = defFileName;
//--- Окрываем файл для записи
int handle = FileOpen(file_name, FILE_WRITE | FILE_BIN);
//--- Вызываем метод сохранения класса по хендлу файла
bool result = Save(handle);
//--- Закрываем открытый файл
FileClose(handle);
//---
return result;
}
//+------------------------------------------------------------------+
//| Метод сохранение элементов класса в файл |
//+------------------------------------------------------------------+
bool CNet::Save(const int file_handle)
{
//--- Блок контролей
if(file_handle == INVALID_HANDLE || !m_cLossFunction || !m_cLayers)
return false;
//--- Сохраняем константы
if(!FileWriteInteger(file_handle, (int)m_bOpenCL) ||
!FileWriteDouble(file_handle, m_dNNLoss) ||
!FileWriteInteger(file_handle, m_iLossSmoothFactor) ||
!FileWriteInteger(file_handle, (int)m_bPositionEncoder) ||
!FileWriteDouble(file_handle, m_dLearningRate) ||
!FileWriteArray(file_handle, m_adBeta, 0) ||
!FileWriteArray(file_handle, m_adLambda, 0) ||
!FileWriteInteger(file_handle, (int)m_cLossFunction.LossFunction()))
return false;
//--- Сохраняем объект позиционного кодирования при необходимости
if(m_bPositionEncoder)
{
if(CheckPointer(m_cPositionEncoder) == POINTER_INVALID ||
!m_cPositionEncoder.Save(file_handle))
return false;
}
//--- Вызываем метод сохранения данных динамического массива нейронных слоёв
return m_cLayers.Save(file_handle);
}
//+------------------------------------------------------------------+
//| Метод восстановления класса из сохранённых данных |
//+------------------------------------------------------------------+
bool CNet::Load(string file_name = NULL, bool common = false)
{
//--- Блок контролей
string path = TerminalInfoString(TERMINAL_COMMONDATA_PATH);
if(!FileIsExist(file_name, (common ? FILE_COMMON : 0)))
file_name = defFileName;
//--- Открываем файл и вызываем метод загрузки данных по хендлу файла
int handle = FileOpen(file_name, FILE_READ | FILE_BIN | FILE_SHARE_READ | (common ? FILE_COMMON : 0));
bool result = Load(handle);
FileClose(handle);
//---
return result;
}
//+------------------------------------------------------------------+
//| Метод восстановления класса из сохранённых данных |
//+------------------------------------------------------------------+
bool CNet::Load(const int file_handle)
{
//--- Блок контролей
if(file_handle == INVALID_HANDLE)
return false;
//--- Считываем константы
m_bOpenCL = (bool)FileReadInteger(file_handle);
m_dNNLoss = FileReadDouble(file_handle);
m_iLossSmoothFactor = FileReadInteger(file_handle);
m_bPositionEncoder = (bool)FileReadInteger(file_handle);
m_dLearningRate = FileReadDouble(file_handle);
if(FileReadArray(file_handle, m_adBeta, 0) < 2 ||
FileReadArray(file_handle, m_adLambda, 0) < 2)
return false;
ENUM_LOSS_FUNCTION loss=(ENUM_LOSS_FUNCTION) FileReadInteger(file_handle);
if(!LossFunction(loss,0,0))
{
Print("Error, unknown loss function: ",EnumToString(loss));
return false;
}
//--- Загружаем объект позиционного кодирования
if(m_bPositionEncoder)
{
if(!m_cPositionEncoder)
{
m_cPositionEncoder = new CPositionEncoder();
if(!m_cPositionEncoder)
return false;
}
if(!m_cPositionEncoder.Load(file_handle))
return false;
}
//--- Инициализируем объект работы с OpenCL
if(m_bOpenCL)
{
if(!InitOpenCL())
m_bOpenCL = false;
}
else
if(!!m_cOpenCL)
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
}
//--- Инициализируем и загружаем данные динамического массива нейронных слоёв
if(m_cLayers)
delete m_cLayers;
m_cLayers = new CArrayLayers(file_handle);
if(!m_cLayers)
return false;
if(m_bOpenCL)
m_cLayers.SetOpencl(m_cOpenCL);
//---
return m_cLayers.Load(file_handle);
}
//+------------------------------------------------------------------+
//| Метод инициализации объектов работы с OpenCL |
//+------------------------------------------------------------------+
bool CNet::InitOpenCL(void)
{
//--- Удаляем созданные ранее объекты OpenCL
if(!!m_cOpenCL)
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
}
//--- Создаём новый объект для работы с OpenCL
m_cOpenCL = new CMyOpenCL();
if(!m_cOpenCL)
return false;
//--- Инициализируем объект работы с OpenCL
if(!m_cOpenCL.Initialize(cl_program, true))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.SetKernelsCount(29))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.SetBuffersCount(10))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
//--- Инициализируем кернелы OpenCL
if(!m_cOpenCL.KernelCreate(def_k_PerceptronFeedForward, "PerceptronFeedForward"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_Normalize, "Normalize"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_CalcOutputGradient, "CalcOutputGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_DeActivateGradient, "DeActivateGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_CalcHiddenGradient, "CalcHiddenGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_CalcDeltaWeights, "CalcDeltaWeights"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_SGDUpdate, "SGDUpdate"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_MomentumUpdate, "MomentumUpdate"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_AdaGradUpdate, "AdaGradUpdate"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_RMSPropUpdate, "RMSPropUpdate"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_AdaDeltaUpdate, "AdaDeltaUpdate"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_AdamUpdate, "AdamUpdate"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_ProofFeedForward, "ProofFeedForward"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_ProofHiddenGradients, "ProofCalcHiddenGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_ConvolutionFeedForward, "ConvolutionFeedForward"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_ConvolutionHiddenGradients, "ConvolutionCalcHiddenGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_ConvolutionDeltaWeights, "ConcolutionCalcDeltaWeights"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_LSTMFeedForward, "LSTMFeedForward"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_LSTMHiddenGradients, "LSTMCalcHiddenGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_AttentionFeedForward, "AttentionFeedForward"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_AttentionScoreGradients, "AttentionCalcScoreGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_AttentionHiddenGradients, "AttentionCalcHiddenGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_GPTFeedForward, "GPTFeedForward"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_GPTScoreGradients, "GPTCalcScoreGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_GPTHiddenGradients, "GPTCalcHiddenGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_BatchNormFeedForward, "BatchNormFeedForward"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_BatchNormCalcHiddenGradient, "BatchNormCalcHiddenGradient"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_BatchNormCalcDeltaWeights, "BatchNormCalcDeltaWeights"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
if(!m_cOpenCL.KernelCreate(def_k_MaskMult, "MaskMult"))
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод передачи указателя на объект OpenCL до всех |
//| внутренних объектов |
//+------------------------------------------------------------------+
void CNet::UseOpenCL(bool value)
{
if(!value)
{
if(CheckPointer(m_cOpenCL) == POINTER_INVALID)
{
m_bOpenCL = value;
return;
}
m_cOpenCL.Shutdown();
delete m_cOpenCL;
if(CheckPointer(m_cLayers) != POINTER_INVALID)
m_cLayers.SetOpencl(m_cOpenCL);
m_bOpenCL = value;
return;
}
//---
if(CheckPointer(m_cOpenCL) != POINTER_INVALID)
{
m_cOpenCL.Shutdown();
delete m_cOpenCL;
}
m_bOpenCL = InitOpenCL();
if(CheckPointer(m_cLayers) != POINTER_INVALID)
m_cLayers.SetOpencl(m_cOpenCL);
return;
}
//+------------------------------------------------------------------+
//| Метод установки параметров обучения |
//+------------------------------------------------------------------+
void CNet::SetLearningRates(double learning_rate, double beta1 = 0.900000, double beta2 = 0.999000)
{
m_dLearningRate = learning_rate;
m_adBeta[0] = beta1;
m_adBeta[1] = beta2;
}
//+------------------------------------------------------------------+
//| Метод установки функции потерь |
//+------------------------------------------------------------------+
bool CNet::LossFunction(ENUM_LOSS_FUNCTION loss_function,double lambda1=0.000000,double lambda2 = 0.000000)
{
//--- сохраним параметры функции потерь
m_adLambda[0]=lambda1;
m_adLambda[1]=lambda2;
//--- удаляем старую функцию
if(m_cLossFunction)
{
delete m_cLossFunction;
m_cLossFunction=NULL;
}
//--- создаём новую функцию
switch(loss_function)
{
case LOSS_MSE:
m_cLossFunction=new CLoss_MSE();
break;
case LOSS_MAE:
m_cLossFunction=new CLoss_MAD();
break;
case LOSS_BCE:
m_cLossFunction=new CLoss_BCE();
break;
default:
break;
}
//--- проверим что функция потерь создана
return(m_cLossFunction!=NULL);
}
//+------------------------------------------------------------------+
//| Метод получениия указателя на буфер градиентов по номеру слоя |
//+------------------------------------------------------------------+
CBufferDouble *CNet::GetGradient(uint layer) const
{
if(layer >= (uint)m_cLayers.Total())
return NULL;
//---
CNeuronBase *l = m_cLayers.At(layer);
return l.GetGradients();
}
//+------------------------------------------------------------------+
//| Метод получения указателя на матрицу весов по номеру слоя |
//+------------------------------------------------------------------+
CBufferDouble *CNet::GetWeights(uint layer) const
{
if(layer >= (uint)m_cLayers.Total())
return NULL;
//---
CNeuronBase *l = m_cLayers.At(layer);
return l.GetWeights();
}
//+------------------------------------------------------------------+
//| Метод получения указателя на буфер накопленных градиентов |
//| ошибки на уровне матрицы весов по номеру слоя |
//+------------------------------------------------------------------+
CBufferDouble *CNet::GetDeltaWeights(uint layer)const
{
if(layer >= (uint)m_cLayers.Total())
return NULL;
//---
CNeuronBase *l = m_cLayers.At(layer);
return l.GetDeltaWeights();
}
//+------------------------------------------------------------------+
//| Установка режима работы модели |
//+------------------------------------------------------------------+
void CNet::TrainMode(bool mode)
{
m_bTrainMode = mode;
int total = m_cLayers.Total();
for(int i = 0; i < total; i++)
{
if(CheckPointer(m_cLayers.At(i)) == POINTER_INVALID)
continue;
CNeuronBase *temp = m_cLayers.At(i);
temp.TrainMode(mode);
}
}
//+------------------------------------------------------------------+
//| Метод получения глубины используемых блоков GPT |
//+------------------------------------------------------------------+
//int CNet::GetGPTUnits(void)
// {
// int result = 0;
// if(CheckPointer(m_cLayers) == POINTER_INVALID)
// return result;
// int total = m_cLayers.Total();
// for(int i = 0; i < total; i++)
// {
// if(CheckPointer(m_cLayers.At(i)) == POINTER_INVALID)
// continue;
// if(m_cLayers.At(i).Type() == defNeuronGPT)
// {
// CNeuronGPT *temp = m_cLayers.At(i);
// result += temp.GetUnits() * temp.GetLayers();
// }
// if(m_cLayers.At(i).Type() == defNeuronLSTM)
// {
// CNeuronLSTM *temp = m_cLayers.At(i);
// result += temp.GetDepth();
// }
// }
////---
// return result;
// }
//+------------------------------------------------------------------+
//| Метод устоновки флага использования позиционного кодирования |
//+------------------------------------------------------------------+
void CNet::UsePositionEncoder(bool value)
{
m_bPositionEncoder = value;
if(!m_bPositionEncoder)
{
if(CheckPointer(m_cPositionEncoder) != POINTER_INVALID)
delete m_cPositionEncoder;
return;
}
//---
if(CheckPointer(m_cPositionEncoder) == POINTER_INVALID)
m_cPositionEncoder = new CPositionEncoder();
if(CheckPointer(m_cLayers) == POINTER_INVALID || m_cLayers.Total() < 1)
return;
CNeuronBase *temp = m_cLayers.At(0);
if(CheckPointer(temp) == POINTER_INVALID)
return;
if(!m_cPositionEncoder.InitEncoder(1, temp.GetOutputs().Total()))
UsePositionEncoder(false);
//---
return;
}
//+------------------------------------------------------------------+