Original_NNB/MQL5/Include/NeuroNetworksBook/realization/neuronproof.mqh
super.admin e81e22b7b8 convert
2025-05-30 16:15:14 +02:00

399 lines
34 KiB
MQL5

//+------------------------------------------------------------------+
//| NeuronProof.mqh |
//| Copyright 2021, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link "https://www.mql5.com"
//+------------------------------------------------------------------+
//| Подключаем библиотеки |
//+------------------------------------------------------------------+
#include "neuronbase.mqh"
#include <Math\Stat\Math.mqh>
//+------------------------------------------------------------------+
//| Class CNeuronProof |
//| Назначение: Класс организации работы подвыборочного слоя |
//+------------------------------------------------------------------+
class CNeuronProof : public CNeuronBase
{
protected:
uint m_iWindow; //Размер окна на входе нейронного слоя
uint m_iStep; //Размер шага входного окна
uint m_iNeurons; //Размер выхода одного фильтра
uint m_iWindowOut; //Количество фильтров/
ENUM_ACTIVATION m_eActivation; //Функция активации
public:
CNeuronProof(void);
~CNeuronProof(void) {};
//---
virtual bool Init(CLayerDescription *description);
virtual bool FeedForward(CNeuronBase *prevLayer);
virtual bool CalcOutputGradient(CBufferDouble *target) { return false;}
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 CBufferDouble *GetWeights(void) const { return(NULL); }
virtual CBufferDouble *GetDeltaWeights(void) const { return(NULL); }
virtual uint GetNeurons(void) const { return m_iNeurons; }
//--- Методы работы с файлами
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
//--- Метод идентификации объекта
virtual int Type(void) const { return(defNeuronProof); }
};
//+------------------------------------------------------------------+
//| Конструктор класса |
//+------------------------------------------------------------------+
CNeuronProof::CNeuronProof(void) : m_eActivation(ACT_MAX_POOLING),
m_iWindow(2),
m_iStep(1),
m_iWindowOut(1),
m_iNeurons(0)
{
}
//+------------------------------------------------------------------+
//| Метод инициализации класса |
//+------------------------------------------------------------------+
bool CNeuronProof::Init(CLayerDescription *description)
{
//--- Блок контролей
if(CheckPointer(description) == POINTER_INVALID || description.type != Type() ||
description.count <= 0)
return false;
//--- Сохраняем константы
m_iWindow = description.window;
m_iStep = description.step;
m_iWindowOut = description.window_out;
m_iNeurons = description.count;
if(m_iWindow <= 0 || m_iStep <= 0 || m_iWindowOut <= 0 || m_iNeurons <= 0)
return false;
//--- Проверка функции потерь
switch(description.activation)
{
case ACT_AVERAGE_POOLING:
case ACT_MAX_POOLING:
m_eActivation = description.activation;
break;
default:
return false;
break;
}
//--- Инициализируем буфер результатов
if(CheckPointer(m_cOutputs) == POINTER_INVALID)
{
m_cOutputs = new CBufferDouble();
if(CheckPointer(m_cOutputs) == POINTER_INVALID)
return false;
}
if(!m_cOutputs.BufferInit(m_iNeurons * m_iWindowOut, 0))
return false;
//--- Инициализируем буфер градиентов ошибки
if(CheckPointer(m_cGradients) == POINTER_INVALID)
{
m_cGradients = new CBufferDouble();
if(CheckPointer(m_cGradients) == POINTER_INVALID)
return false;
}
if(!m_cGradients.BufferInit(m_iNeurons * m_iWindowOut, 0))
return false;
//---
m_eOptimization = None;
//--- Удаляем не используемые объекты
if(CheckPointer(m_cActivation) != POINTER_INVALID)
delete m_cActivation;
if(CheckPointer(m_cWeights) != POINTER_INVALID)
delete m_cWeights;
if(CheckPointer(m_cDeltaWeights) != POINTER_INVALID)
delete m_cDeltaWeights;
for(int i = 0; i < 2; i++)
if(CheckPointer(m_cMomenum[i]) != POINTER_INVALID)
delete m_cMomenum[i];
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод прямого прохода |
//+------------------------------------------------------------------+
bool CNeuronProof::FeedForward(CNeuronBase *prevLayer)
{
//--- Блок контролей
if(CheckPointer(prevLayer) == POINTER_INVALID ||
CheckPointer(m_cOutputs) == POINTER_INVALID ||
CheckPointer(prevLayer.GetOutputs()) == POINTER_INVALID)
return false;
CBufferDouble *input_data = prevLayer.GetOutputs();
//--- Разветвление алгоритма в зависимости от устройста выполнениия операций
if(CheckPointer(m_cOpenCL) == POINTER_INVALID)
{
uint input_total = input_data.Total();
uint output_total = m_cOutputs.Total();
uint input_neurons = input_total;
if(prevLayer.Type() == defNeuronConv || prevLayer.Type() == defNeuronProof)
{
CNeuronProof *temp = prevLayer;
input_neurons = temp.GetNeurons();
}
double array[];
if(ArrayResize(array, m_iWindow) < 0)
return false;
for(uint f = 0; f < m_iWindowOut; f++)
{
uint shift_inp = f * input_neurons;
uint shift_out = f * m_iNeurons;
if(shift_inp >= input_total)
{
for(uint i = shift_out; i < output_total; i++)
m_cOutputs.Update(i, 0);
break;
}
for(uint o = 0; o < m_iNeurons; o++)
{
uint shift = o * m_iStep;
for(uint i = 0; i < m_iWindow; i++)
array[i] = ((shift_inp + shift + i) >= input_total || (shift + i) >= input_neurons ? 0 :
input_data.At(shift_inp + shift + i));
switch(m_eActivation)
{
case ACT_MAX_POOLING:
m_cOutputs.Update(shift_out + o, array[ArrayMaximum(array)]);
break;
case ACT_AVERAGE_POOLING:
m_cOutputs.Update(shift_out + o, MathMean(array));
break;
default:
return false;
}
}
}
}
else // Блок работы с OpenCL
{
//--- Создание и загрузка содержимое буферов в контекст OpenCL
if(input_data.GetIndex() < 0 && !input_data.BufferCreate(m_cOpenCL))
return false;
if(m_cOutputs.GetIndex() < 0 && !m_cOutputs.BufferCreate(m_cOpenCL))
return false;
//--- Передача параметров в кернел
if(!m_cOpenCL.SetArgumentBuffer(def_k_ProofFeedForward, def_prff_inputs, input_data.GetIndex()))
return false;
if(!m_cOpenCL.SetArgumentBuffer(def_k_ProofFeedForward, def_prff_outputs, m_cOutputs.GetIndex()))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofFeedForward, def_prff_inputs_total, input_data.Total()))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofFeedForward, def_prff_window, m_iWindow))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofFeedForward, def_prff_step, m_iStep))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofFeedForward, def_prff_window_out, m_iWindowOut))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofFeedForward, def_prff_activation, (int)m_eActivation))
return false;
//--- Постановка кернела в очередь на выполнение
uint input_neurons = input_data.Total();
if(prevLayer.Type() == defNeuronConv || prevLayer.Type() == defNeuronProof)
{
CNeuronProof *temp = prevLayer;
input_neurons = temp.GetNeurons();
}
if(!m_cOpenCL.SetArgument(def_k_ProofFeedForward, def_prff_input_neurons, input_neurons))
return false;
int off_set[] = {0};
int NDRange[] = {(int)m_iNeurons};
if(!m_cOpenCL.Execute(def_k_ProofFeedForward, 1, off_set, NDRange))
return false;
//--- Загрузка результатов расчёта
if(!m_cOutputs.BufferRead())
return false;
input_data.BufferFree();
}
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод распределения градиента ошибки через скрытый слой |
//+------------------------------------------------------------------+
bool CNeuronProof::CalcHiddenGradient(CNeuronBase *prevLayer)
{
//--- Блок контролей
if(CheckPointer(prevLayer) == POINTER_INVALID ||
CheckPointer(m_cOutputs) == POINTER_INVALID ||
CheckPointer(m_cGradients) == POINTER_INVALID ||
CheckPointer(prevLayer.GetOutputs()) == POINTER_INVALID ||
CheckPointer(prevLayer.GetGradients()) == POINTER_INVALID)
return false;
CBufferDouble *input_data = prevLayer.GetOutputs();
CBufferDouble *input_gradient = prevLayer.GetGradients();
if(!input_gradient.BufferInit(input_data.Total(), 0))
return false;
//--- Разветвление алгоритма в зависимости от устройста выполнениия операций
if(CheckPointer(m_cOpenCL) == POINTER_INVALID)
{
uint input_total = input_data.Total();
uint output_total = m_cOutputs.Total();
uint input_neurons = input_total;
if(prevLayer.Type() == defNeuronConv || prevLayer.Type() == defNeuronProof)
{
CNeuronProof *temp = prevLayer;
input_neurons = temp.GetNeurons();
}
for(uint f = 0; f < m_iWindowOut; f++)
{
uint shift_inp = f * input_neurons;
uint shift_out = f * m_iNeurons;
if(shift_inp >= input_total)
break;
for(uint o = 0; o < m_iNeurons; o++)
{
uint shift = o * m_iStep;
double out = m_cOutputs.At(shift_out + o);
double gradient = m_cGradients.At(shift_out + o);
switch(m_eActivation)
{
case ACT_MAX_POOLING:
for(uint i = 0; i < m_iWindow; i++)
{
if((shift_inp + shift + i) >= input_total || (shift + i) >= input_neurons)
break;
if(input_data.At(shift_inp + shift + i) == out)
{
input_gradient.Update(shift_inp + shift + i,
input_gradient.At(shift_inp + shift + i) + gradient);
break;
}
}
break;
case ACT_AVERAGE_POOLING:
gradient /= (double)m_iWindow;
for(uint i = 0; i < m_iWindow; i++)
{
if((shift_inp + shift + i) >= input_total || (shift + i) >= input_neurons)
break;
input_gradient.Update(shift_inp + shift + i,
input_gradient.At(shift_inp + shift + i) + gradient);
}
break;
default:
return false;
}
}
}
}
else // Блок работы с OpenCL
{
//--- Создание и загрузка содержимое буферов в контекст OpenCL
if(input_data.GetIndex() < 0 && !input_data.BufferCreate(m_cOpenCL))
return false;
if(m_cOutputs.GetIndex() < 0 && !m_cOutputs.BufferCreate(m_cOpenCL))
return false;
if(input_gradient.GetIndex() < 0 && !input_gradient.BufferCreate(m_cOpenCL))
return false;
if(m_cGradients.GetIndex() < 0 && !m_cGradients.BufferCreate(m_cOpenCL))
return false;
//--- Передача параметров в кернел
if(!m_cOpenCL.SetArgumentBuffer(def_k_ProofHiddenGradients, def_prhgr_inputs, input_data.GetIndex()))
return false;
if(!m_cOpenCL.SetArgumentBuffer(def_k_ProofHiddenGradients, def_prhgr_outputs, m_cOutputs.GetIndex()))
return false;
if(!m_cOpenCL.SetArgumentBuffer(def_k_ProofHiddenGradients, def_prhgr_gradients, m_cGradients.GetIndex()))
return false;
if(!m_cOpenCL.SetArgumentBuffer(def_k_ProofHiddenGradients, def_prhgr_gradient_inputs, input_gradient.GetIndex()))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofHiddenGradients, def_prhgr_inputs_total, input_data.Total()))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofHiddenGradients, def_prhgr_window, m_iWindow))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofHiddenGradients, def_prhgr_step, m_iStep))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofHiddenGradients, def_prhgr_window_out, m_iWindowOut))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofHiddenGradients, def_prhgr_activation, (int)m_eActivation))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofHiddenGradients, def_prhgr_neurons, m_iNeurons))
return false;
if(!m_cOpenCL.SetArgument(def_k_ProofHiddenGradients, def_prhgr_outputs_total, m_cOutputs.Total()))
return false;
//--- Постановка кернела в очередь на выполнене
uint input_neurons = input_data.Total();
if(prevLayer.Type() == defNeuronConv || prevLayer.Type() == defNeuronProof)
{
CNeuronProof *temp = prevLayer;
input_neurons = temp.GetNeurons();
}
int off_set[] = {0};
int NDRange[] = {(int)input_neurons};
if(!m_cOpenCL.Execute(def_k_ProofHiddenGradients, 1, off_set, NDRange))
return false;
//--- Загрузка результатов
if(!input_gradient.BufferRead())
return false;
//--- Очистка памяти контекста OpenCL
input_data.BufferFree();
m_cOutputs.BufferFree();
m_cGradients.BufferFree();
}
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод сохранения элементов касса в файл |
//+------------------------------------------------------------------+
bool CNeuronProof::Save(const int file_handle)
{
//--- Блок контролей
if(file_handle == INVALID_HANDLE)
return false;
//--- Сохраняем константы
if(FileWriteInteger(file_handle, Type()) <= 0)
return false;
if(FileWriteInteger(file_handle, (int)m_iWindow) <= 0)
return false;
if(FileWriteInteger(file_handle, (int)m_iStep) <= 0)
return false;
if(FileWriteInteger(file_handle, (int)m_iWindowOut) <= 0)
return false;
if(FileWriteInteger(file_handle, (int)m_iNeurons) <= 0)
return false;
if(FileWriteInteger(file_handle, (int)m_eActivation) <= 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| Метод восстановления работы класса из файла |
//+------------------------------------------------------------------+
bool CNeuronProof::Load(const int file_handle)
{
//--- Блок контролей
if(file_handle == INVALID_HANDLE)
return false;
//--- Загружаем константы
m_iWindow = (uint)FileReadInteger(file_handle);
m_iStep = (uint)FileReadInteger(file_handle);
m_iWindowOut = (uint)FileReadInteger(file_handle);
m_iNeurons = (uint)FileReadInteger(file_handle);
m_eActivation = (ENUM_ACTIVATION)FileReadInteger(file_handle);
//--- Инициализтируем и загружаем буфер результатов
if(CheckPointer(m_cOutputs) == POINTER_INVALID)
{
m_cOutputs = new CBufferDouble();
if(CheckPointer(m_cOutputs) == POINTER_INVALID)
return false;
}
if(!m_cOutputs.BufferInit(m_iNeurons * m_iWindowOut, 0))
return false;
//--- Инициализируем и загружаем буфер градиентов ошибки
if(CheckPointer(m_cGradients) == POINTER_INVALID)
{
m_cGradients = new CBufferDouble();
if(CheckPointer(m_cGradients) == POINTER_INVALID)
return false;
}
if(!m_cGradients.BufferInit(m_iNeurons * m_iWindowOut, 0))
return false;
//---
return true;
}
//+------------------------------------------------------------------+