//+------------------------------------------------------------------+ //| 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(CArrayDouble *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) { ArrayInitialize(m_adLambda, 0); ArrayInitialize(m_adBeta, 0); m_cLayers = new CArrayLayers(); m_cOpenCL = new CMyOpenCL(); m_cPositionEncoder = new CPositionEncoder(); m_cLossFunction = new CLossFunction(); } //+------------------------------------------------------------------+ //| Деструктор класса | //+------------------------------------------------------------------+ CNet::~CNet(void) { if(CheckPointer(m_cLayers) != POINTER_INVALID) delete m_cLayers; if(CheckPointer(m_cOpenCL) != POINTER_INVALID) delete m_cOpenCL; if(CheckPointer(m_cPositionEncoder) != POINTER_INVALID) delete m_cPositionEncoder; if(CheckPointer(m_cLossFunction) != POINTER_INVALID) delete m_cLossFunction; } //+------------------------------------------------------------------+ //| Метод инициализации класса | //+------------------------------------------------------------------+ bool CNet::Create(CArrayObj *descriptions) { //--- Блок контролей if(CheckPointer(descriptions) == POINTER_INVALID) 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(CheckPointer(m_cPositionEncoder) == POINTER_INVALID) { m_cPositionEncoder = new CPositionEncoder(); if(CheckPointer(m_cPositionEncoder) == POINTER_INVALID) 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(CArrayDouble *inputs) { //--- Блок контролей if(CheckPointer(inputs) == POINTER_INVALID) { PrintFormat("%s - %d", __FUNCTION__, __LINE__); return false; } CNeuronBase *InputLayer = m_cLayers.At(0); if(CheckPointer(InputLayer) == POINTER_INVALID) { PrintFormat("%s - %d", __FUNCTION__, __LINE__); return false; } CBufferDouble *Inputs = InputLayer.GetOutputs(); if(CheckPointer(Inputs) == POINTER_INVALID) { PrintFormat("%s - %d", __FUNCTION__, __LINE__); return false; } if(Inputs.Total() != inputs.Total()) { PrintFormat("%s - %d", __FUNCTION__, __LINE__); return false; } //--- Переносим исходные данные в нейронный слой if(!Inputs.AssignArray(inputs)) { PrintFormat("%s - %d", __FUNCTION__, __LINE__); return false; } //--- Применяем позиционное кодированиеи 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(CheckPointer(Layer) == POINTER_INVALID) { 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(CheckPointer(target) == POINTER_INVALID) return false; int total = m_cLayers.Total(); CNeuronBase *Output = m_cLayers.At(total - 1); if(CheckPointer(Output) == POINTER_INVALID) return false; //--- Расчет значения функции потерь double loss = m_cLossFunction.CaclFunction(Output.GetOutputs(), target); if(loss == DBL_MAX) return false; m_dNNLoss = (m_dNNLoss < 0 ? loss : m_dNNLoss + (loss - m_dNNLoss) / m_iLossSmoothFactor); //--- Расчет градиента ошибки на выходе нейронной сети if(!Output.CalcOutputGradient(target)) { return false; } //--- Организовываем цикл с перебором всех нейронных слоёв в обратном порядке for(int i = total - 2; i >= 0; i--) { CNeuronBase *temp = m_cLayers.At(i); if(CheckPointer(temp) == POINTER_INVALID) 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(CheckPointer(temp) == POINTER_INVALID) 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(CheckPointer(temp) == POINTER_INVALID) return false; if(CheckPointer(result) == POINTER_INVALID) { result = new CBufferDouble(); if(CheckPointer(result) == POINTER_INVALID) return false; } if(!result.AssignArray(temp.GetOutputs())) return false; //--- 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 || CheckPointer(m_cLossFunction) == POINTER_INVALID || CheckPointer(m_cLayers) == POINTER_INVALID) 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(m_bPositionEncoder) { if(CheckPointer(m_cPositionEncoder) == POINTER_INVALID) { m_cPositionEncoder = new CPositionEncoder(); if(CheckPointer(m_cPositionEncoder) == POINTER_INVALID) return false; } if(!m_cPositionEncoder.Load(file_handle)) return false; } //--- Инициализируем объект функции потерь if(CheckPointer(m_cLossFunction) == POINTER_INVALID) { m_cLossFunction = new CLossFunction(); if(CheckPointer(m_cLossFunction) == POINTER_INVALID) return false; } m_cLossFunction.LossFunction(loss); //--- Инициализируем объект работы с OpenCL if(m_bOpenCL) { if(!InitOpenCL()) m_bOpenCL = false; } else if(CheckPointer(m_cOpenCL) != POINTER_INVALID) { m_cOpenCL.Shutdown(); delete m_cOpenCL; } //--- Инициализируем и загружаем данные динамического массива нейронных слоёв if(CheckPointer(m_cLayers) != POINTER_INVALID) delete m_cLayers; m_cLayers = new CArrayLayers(file_handle); if(CheckPointer(m_cLayers) == POINTER_INVALID) return false; if(m_bOpenCL) m_cLayers.SetOpencl(m_cOpenCL); //--- return m_cLayers.Load(file_handle); } //+------------------------------------------------------------------+ //| Метод инициализации объектов работы с OpenCL | //+------------------------------------------------------------------+ bool CNet::InitOpenCL(void) { //--- Удаляем созданные ранее объекты OpenCL if(CheckPointer(m_cOpenCL) != POINTER_INVALID) { m_cOpenCL.Shutdown(); delete m_cOpenCL; } //--- Создаём новый объект для работы с OpenCL m_cOpenCL = new CMyOpenCL(); if(CheckPointer(m_cOpenCL) == POINTER_INVALID) 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) { if(CheckPointer(m_cLossFunction) == POINTER_INVALID) { m_cLossFunction = new CLossFunction(); if(CheckPointer(m_cLossFunction) == POINTER_INVALID) return false; } m_cLossFunction.LossFunction(loss_function); m_adLambda[0] = lambda1; m_adLambda[1] = lambda2; return true; } //+------------------------------------------------------------------+ //| Метод получениия указателя на буфер градиентов по номеру слоя | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+