Warrior_EA/references/MQL5/Experts/NeuroNet_DNG/NeuroNet.mqh
2026-10-05 21:58:23 -04:00

17714 lines
1.5 MiB
MQL5

/// \file
/// \brief NeuroNet.mqh
/// Library for creating Neural network for use in MQL5 experts
/// \author [DNG](https://www.mql5.com/en/users/dng)
/// \copyright Copyright 2019, DNG
//+------------------------------------------------------------------+
///\mainpage NeuronNet
/// Library for creating Neural network for use in MQL5 experts.
/// - \ref const
/// - \ref enums
/// - \ref ObjectTypes
/// - \ref group1
/// - [<b>Class Hierarchy</b>](hierarchy.html)
/// - [<b>Files</b>](files.html)
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, DNG"
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Include standart libraries
//+------------------------------------------------------------------+
#include <Arrays\ArrayFloat.mqh>
#include <Arrays\ArrayInt.mqh>
#include <Arrays\ArrayObj.mqh>
#include <OpenCL\OpenCL.mqh>
namespace Math
{
#include <Math\Stat\Normal.mqh>
}
//+------------------------------------------------------------------+
// Defines
//+------------------------------------------------------------------+
///\defgroup const Global constants
///@{
#define lr 3.0e-4f ///<learning rate
#define momentum 0.99f ///<momentum for SGD optimization
#define WeightsMultiplier 1.0f
//---
/** First momentum multiplier of Adam optimization*/
#define b1 0.9f
/** Second momentum multiplier of Adam optimization*/
#define b2 0.999f
/// Pseudo-random sequence generator
#define xor128 rnd_t=(rnd_x^(rnd_x<<11)); \
rnd_x=rnd_y; \
rnd_y=rnd_z; \
rnd_z=rnd_w; \
rnd_w=(rnd_w^(rnd_w>>19))^(rnd_t^(rnd_t>>8))
///@}
//---
uint rnd_x = MathRand(), rnd_y = MathRand(), rnd_z = MathRand(), rnd_w = MathRand(), rnd_t = 0;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template<typename T1, typename T2>
T2 pow(T1 a, T2 b)
{
return (T2)MathPow((T2)a, b);
}
//+------------------------------------------------------------------+
///\defgroup ObjectTypes Defines Object types identified
///Used to identify classes in a library
///@{
//+------------------------------------------------------------------+
///\defgroup arr Arrays
///Used to identify array classes
///\{
#define defArrayConnects 0x7782 ///<Array of connections \details Identified class #CArrayCon
#define defLayer 0x7787 ///<Layer of neurons \details Identified class #CLayer
#define defArrayLayer 0x7788 ///<Array of layers \details Identified class #CArrayLayer
#define defNet 0x7790 ///<Neuron Net \details Identified class #CNet
///\}
///\defgroup cpu CPU
///Used to identify classes with CPU calculation
///\{
#define defConnect 0x7781 ///<Connection \details Identified class #CConnection
#define defNeuronBase 0x7783 ///<Neuron base type \details Identified class #CNeuronBase
#define defNeuron 0x7784 ///<Full connected neuron \details Identified class #CNeuron
#define defNeuronConv 0x7785 ///<Convolution neuron \details Identified class #CNeuronConv
#define defNeuronProof 0x7786 ///<Proof neuron \details Identified class #CNeuronProof
#define defNeuronLSTM 0x7791 ///<LSTM Neuron \details Identified class #CNeuronLSTM
///\}
///\defgroup gpu GPU
///Used to identify classes with GPU calculation
///\{
#define defBufferDouble 0x7882 ///<Data Buffer OpenCL \details Identified class #CBufferFloat
#define defNeuronBaseOCL 0x7883 ///<Neuron Base OpenCL \details Identified class #CNeuronBaseOCL
#define defNeuronConvOCL 0x7885 ///<Conolution neuron OpenCL \details Identified class #CNeuronConvOCL
#define defNeuronProofOCL 0x7886 ///<Proof neuron OpenCL \details Identified class #CNeuronProofOCL
#define defNeuronAttentionOCL 0x7887 ///<Attention neuron OpenCL \details Identified class #CNeuronAttentionOCL
#define defNeuronMHAttentionOCL 0x7888 ///<Multi-Head Attention neuron OpenCL \details Identified class #CNeuronMHAttentionOCL
#define defNeuronMLMHAttentionOCL 0x7889 ///<Multilayer multi-headed attention neuron OpenCL \details Identified class #CNeuronMLMHAttentionOCL
#define defNeuronDropoutOCL 0x7890 ///<Dropout neuron OpenCL \details Identified class #CNeuronDropoutOCL
#define defNeuronBatchNormOCL 0x7891 ///<Batchnorm neuron OpenCL \details Identified class #CNeuronBatchNormOCL
#define defNeuronVAEOCL 0x7892 ///<VAE neuron OpenCL \details Identified class #CVAE
#define defNeuronLSTMOCL 0x7893 ///<LSTM Neuron \details Identified class #CNeuronLSTMOCL
#define defNeuronSoftMaxOCL 0x7894 ///<SoftMax layer \details Identified class #CNeuronSoftMaxOCL
#define defNeuronFQF 0x7895 ///<FQF layer \details Identified class #CNeuronFQF
#define defNeuronMLMHSparseAttentionOCL 0x7896 ///<Multilayer multi-headed sparse attention neuron OpenCL \details Identified class #CNeuronMLMHAttentionOCL
#define defNeuronMultiModels 0x7897 ///<Neuron Base MultiModels OpenCL \details Identified class #CNeuronMultiModels
#define defNeuronConcatenate 0x7898
#define defNeuronSoftActorCritic 0x7899
#define defNeuronEmbeddingOCL 0x7900
#define defNeuronPEOCL 0x7901
#define defNeuronTransposeOCL 0x7902
#define defNeuronMH2AttentionOCL 0x7903
#define defNeuronCGConvOCL 0x7904
#define defNeuronMFTOCL 0x7905
#define defNeuronXCiTOCL 0x7906
#define defNeuronDOTOCL 0x7907
#define defNeuronFAQOCL 0x7908
#define defNeuronCrossAttenOCL 0x7909
///\}
///@}
//+------------------------------------------------------------------+
///\defgroup group1 Defines for OpenCL kernels identified
/// Used as indexes when calling functions OpenCL.
///@{
///\defgroup neuron_base Neuron Base
/// Describes the process for the Neuron Base.
///\details Detailed description on [the link.](https://www.mql5.com/en/articles/8435#para4)
///@{
///\defgroup neuron_base_ff Feed Forward proccess kernel
/// Describes the forward path process for the Neuron Base.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8435#para41">the link.</A>
///@{
#define def_k_FeedForward 0 ///< Index of #FeedForward kernel
#define def_k_ff_matrix_w 0 ///< Weights matrix (m+1)*n, where m - number of neurons in layer and n - number of outputs (neurons in next layer)
#define def_k_ff_matrix_i 1 ///< Inputs tesor
#define def_k_ff_matrix_o 2 ///< Output tensor
#define def_k_ff_inputs 3 ///< Number of inputs
#define def_k_ff_activation 4 ///< Activation type (#ENUM_ACTIVATION)
///@}
///\defgroup neuron_base_gr Gradients Calculation kernels
/// Describes the process of gradients calculation for the Neuron Base.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8435#para42">the link.</A>
///@{
#define def_k_CalcOutputGradient 1 ///< Index of Output gradients calculation kernel (#CalcOutputGradient)
#define def_k_cog_matrix_t 0 ///< Target tensor
#define def_k_cog_matrix_o 1 ///< Output tensor
#define def_k_cog_matrix_ig 2 ///< Tensor of gradients at previous layer
#define def_k_cog_activation 3 ///< Activation type (#ENUM_ACTIVATION)
#define def_k_cog_error 4 ///< Error
//---
#define def_k_CalcHiddenGradient 2 ///< Index of Hidden gradients calculation kernel (#CalcHiddenGradient)
#define def_k_chg_matrix_w 0 ///< Weights matrix (m+1)*n, where m - number of neurons in previous layer and n - number of neurons in current layer
#define def_k_chg_matrix_g 1 ///< Tensor of gradients at current layer
#define def_k_chg_matrix_o 2 ///< Output tensor
#define def_k_chg_matrix_ig 3 ///< Tensor of gradients at previous layer
#define def_k_chg_outputs 4 ///< Number of outputs
#define def_k_chg_activation 5 ///< Activation type (#ENUM_ACTIVATION)
///@}
///\defgroup neuron_base_opt Updating Weights Calculation kernel
/// Describes the process of optimization weights for the Neuron Base.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8435#para43">the link.</A>
/// For Adam optimization look <A HREF="https://www.mql5.com/en/articles/8598#para31">the link.</A>
///@{
#define def_k_UpdateWeightsMomentum 3 ///< Index SGD optomization Update weights kernel (#UpdateWeightsMomentum)
#define def_k_uwm_matrix_w 0 ///< SGD Weights matrix (m+1)*n, where m - number of neurons in previous layer and n - number of neurons in current layer
#define def_k_uwm_matrix_g 1 ///< SGD Tensor of gradients at current layer
#define def_k_uwm_matrix_i 2 ///< SGD Inputs tesor
#define def_k_uwm_matrix_dw 3 ///< SGD Matrix of delta weights in last correction
#define def_k_uwm_inputs 4 ///< SGD Number of inputs
#define def_k_uwm_learning_rates 5 ///< SGD Learning rates
#define def_k_uwm_momentum 6 ///< SGD Momentum multiplier
//---
#define def_k_UpdateWeightsAdam 4 ///< Index Adam optomization Update weights kernel (#UpdateWeightsAdam)
#define def_k_uwa_matrix_w 0 ///< Adam Weights matrix (m+1)*n, where m - number of neurons in previous layer and n - number of neurons in current layer
#define def_k_uwa_matrix_g 1 ///< Adam Tensor of gradients at current layer
#define def_k_uwa_matrix_i 2 ///< Adam Inputs tesor
#define def_k_uwa_matrix_m 3 ///< Adam Matrix of first momentum
#define def_k_uwa_matrix_v 4 ///< Adam Matrix of seconfd momentum
#define def_k_uwa_inputs 5 ///< Adam Number of inputs
#define def_k_uwa_l 6 ///< Adam Learning rates
#define def_k_uwa_b1 7 ///< Adam First momentum multiplier
#define def_k_uwa_b2 8 ///< Adam Second momentum multiplier
//---
#define def_k_UpdateWeightsLS 28 ///< Index Least Squares optomization Update weights kernel (#UpdateWeightsLS)
#define def_k_uwls_matrix_w 0 ///< Least Squares Weights matrix (m+1)*n, where m - number of neurons in previous layer and n - number of neurons in current layer
#define def_k_uwls_matrix_g 1 ///< Least Squares Tensor of gradients at current layer
#define def_k_uwls_matrix_i 2 ///< Least Squares Inputs tesor
#define def_k_uwls_matrix_xg 3 ///< Least Squares Matrix of summ x*g
#define def_k_uwls_matrix_xx 4 ///< Least Squares Matrix of summ x*x
#define def_k_uwls_inputs 5 ///< Least Squares Number of inputs
#define def_k_uwls_l 6 ///< Least Squares Learning rates
#define def_k_uwls_update 7 ///< Least Squares Update flag
///@}
///@}
//---
///\defgroup neuron_proof Pooling layer's neuron
/// Describes the process for the Neuron of pooling layer.
///@{
///\defgroup neuron_proof_ff Pooling layer's neuron Feed Forward
/// Describes the feed forward process for the Neuron of pooling layer.
///@{
#define def_k_FeedForwardProof 5 ///< Index of the kernel of the Pooling neuron for Feed forward process (#FeedForwardProof)
#define def_k_ffp_matrix_i 0 ///< Inputs tesor
#define def_k_ffp_matrix_o 1 ///< Output tensor
#define def_k_ffp_inputs 2 ///< Number of inputs
#define def_k_ffp_window 3 ///< Size of input window
#define def_k_ffp_step 4 ///< Step size
///@}
//---
///\defgroup neuron_proof_gr Pooling layer's neuron Gradients Calculation kernels
/// Describes the gradient calculation process for the Neuron of pooling layer.
///@{
#define def_k_CalcInputGradientProof 6 ///< Index of the kernel of the Pooling neuron to transfer gradient to previous layer (#CalcInputGradientProof)
#define def_k_cigp_matrix_i 0 ///< Inputs tesor
#define def_k_cigp_matrix_g 1 ///< Tensor of gradients at current layer
#define def_k_cigp_matrix_o 2 ///< Output tensor
#define def_k_cigp_matrix_ig 3 ///< Tensor of gradients at previous layer
#define def_k_cigp_outputs 4 ///< Number of outputs
#define def_k_cigp_window 5 ///< Size of input window
#define def_k_cigp_step 6 ///< Step size
///@}
///@}
//---
///\defgroup neuron_conv Convolution layer's neuron
/// Describes the process for the Neuron of convolution layer.
///@{
///\defgroup neuron_conv_ff Convolution layer's neuron Feed Forward
/// Describes the feed forward process for the Neuron of convolution layer.
///@{
#define def_k_FeedForwardConv 7 ///< Index of the kernel of the convolution neuron for Feed forward process (#FeedForwardConv)
#define def_k_ffc_matrix_w 0 ///< Weights matrix (m+1)*n, where m - input window and n - output window
#define def_k_ffc_matrix_i 1 ///< Inputs tesor
#define def_k_ffc_matrix_o 2 ///< Output tensor
#define def_k_ffc_inputs 3 ///< Number of inputs
#define def_k_ffc_step 4 ///< Step size
#define def_k_ffc_window_in 5 ///< Size of input window
#define def_k_ffс_window_out 6 ///< Size of output window
#define def_k_ffc_activation 7 ///< Activation type (#ENUM_ACTIVATION)
///@}
//---
///\defgroup neuron_conv_gr Convolution layer's neuron Gradients Calculation kernels
/// Describes the gradient calculation process for the Neuron of convolution layer.
///@{
#define def_k_CalcHiddenGradientConv 8 ///< Index of the kernel of the convolution neuron to transfer gradient to previous layer (#CalcHiddenGradientConv)
#define def_k_chgc_matrix_w 0 ///< Weights matrix (m+1)*n, where m - input window and n - output window
#define def_k_chgc_matrix_g 1 ///< Tensor of gradients at current layer
#define def_k_chgc_matrix_o 2 ///< Output tensor
#define def_k_chgc_matrix_ig 3 ///< Tensor of gradients at previous layer
#define def_k_chgc_outputs 4 ///< Number of outputs
#define def_k_chgc_step 5 ///< Step size
#define def_k_chgc_window_in 6 ///< Size of input window
#define def_k_chgc_window_out 7 ///< Size of output window
#define def_k_chgc_activation 8 ///< Activation type (#ENUM_ACTIVATION)
#define def_k_chgc_shift_out 9 ///< Activation type (#ENUM_ACTIVATION)
///@}
//---
///\defgroup neuron_conv_opt Convolution layer's neuron Update weights kernels
/// Describes the optimization process for the Neuron of convolution layer.
///@{
#define def_k_UpdateWeightsConvMomentum 9 ///< Index of the kernel of the convolution neuron to update weights SGD (#UpdateWeightsConvMomentum)
#define def_k_uwcm_matrix_w 0 ///< Weights matrix (m+1)*n, where m - input window and n - output window
#define def_k_uwcm_matrix_g 1 ///< Tensor of gradients at current layer
#define def_k_uwcm_matrix_i 2 ///< Inputs tesor
#define def_k_uwcm_matrix_dw 3 ///< Matrix of delta weights in last correction
#define def_k_uwcm_inputs 4 ///< Number of inputs
#define def_k_uwcm_learning_rates 5 ///< Learning rates
#define def_k_uwcm_momentum 6 ///< Momentum multiplier
#define def_k_uwcm_window_in 7 ///< Size of input window
#define def_k_uwcm_window_out 8 ///< Size of output window
#define def_k_uwcm_step 9 ///< Step size
//---
#define def_k_UpdateWeightsConvAdam 10 ///< Index of the kernel of the convolution neuron to update weights Adam (#UpdateWeightsConvAdam)
#define def_k_uwca_matrix_w 0 ///< Weights matrix (m+1)*n, where m - input window and n - output window
#define def_k_uwca_matrix_g 1 ///< Tensor of gradients at current layer
#define def_k_uwca_matrix_i 2 ///< Inputs tesor
#define def_k_uwca_matrix_m 3 ///< Matrix of first momentum
#define def_k_uwca_matrix_v 4 ///< Matrix of seconfd momentum
#define def_k_uwca_inputs 5 ///< Number of inputs
#define def_k_uwca_l 6 ///< Learning rates
#define def_k_uwca_b1 7 ///< First momentum multiplier
#define def_k_uwca_b2 8 ///< Second momentum multiplier
#define def_k_uwca_window_in 9 ///< Size of input window
#define def_k_uwca_window_out 10 ///< Size of output window
#define def_k_uwca_step 11 ///< Step size
//---
#define def_k_UpdateWeightsConvLS 29 ///< Index of the kernel of the convolution neuron to update weights Least Squares(#UpdateWeightsConvLS)
#define def_k_uwcls_matrix_w 0 ///< Weights matrix (m+1)*n, where m - input window and n - output window
#define def_k_uwcls_matrix_g 1 ///< Tensor of gradients at current layer
#define def_k_uwcls_matrix_i 2 ///< Inputs tesor
#define def_k_uwcls_matrix_xg 3 ///< Matrix of first momentum
#define def_k_uwcls_matrix_xx 4 ///< Matrix of seconfd momentum
#define def_k_uwcls_inputs 5 ///< Number of inputs
#define def_k_uwcls_l 6 ///< Learning rates
#define def_k_uwcls_update 7 ///< Update flag
#define def_k_uwcls_window_in 8 ///< Size of input window
#define def_k_uwcls_window_out 9 ///< Size of output window
#define def_k_uwcls_step 10 ///< Step size
///@}
///@}
//---
///\defgroup neuron_atten Attention layer's neuron
/// Describes the process for the Neuron of attention layer.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8765#para4">the link.</A>
///@{
///\defgroup neuron_atten_ff Attention layer's neuron Feed Forward
/// Describes the feed forward process for the Neuron of attention layer.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8765#para43">the link.</A>
///@{
#define def_k_AttentionScore 11 ///< Index of the kernel of the attention neuron to calculate score matrix (#AttentionScore)
#define def_k_as_querys 0 ///< Matrix of Querys
#define def_k_as_keys 1 ///< Matriz of Keys
#define def_k_as_score 2 ///< Matrix of Scores
#define def_k_as_dimension 3 ///< Dimension of Key
#define def_k_as_mask 4 ///< 1 - calc only previous units, 0 - calc all
//---
#define def_k_AttentionOut 12 ///< Index of the Attention Neuron Output calculation kernel (#AttentionOut)
#define def_k_aout_scores 0 ///< Matrix of Scores
#define def_k_aout_values 1 ///< Matrix of Values
#define def_k_aout_inputs 2 ///< Inputs tesor
#define def_k_aout_out 3 ///< Output tesor
//---
#define def_k_MatrixSum 13 ///< Index of the kernel for calculation Sum of 2 matrix with multiplyer (#SumMatrix)
#define def_k_sum_matrix1 0 ///< First matrix
#define def_k_sum_matrix2 1 ///< Second matrix
#define def_k_sum_matrix_out 2 ///< Output matrix
#define def_k_sum_dimension 3 ///< Dimension of matrix
#define def_k_sum_multiplyer 4 ///< Multiplyer for output
#define def_k_sum_shift_in1 5
#define def_k_sum_shift_in2 6
#define def_k_sum_shift_out 7
//---
#define def_k_Matrix5Sum 19 ///< Index of the kernel for calculation Sum of 2 matrix with multiplyer (#SumMatrix)
#define def_k_sum5_matrix1 0 ///< First matrix
#define def_k_sum5_matrix2 1 ///< Second matrix
#define def_k_sum5_matrix3 2 ///< Third matrix
#define def_k_sum5_matrix4 3 ///< Fourth matrix
#define def_k_sum5_matrix5 4 ///< Fifth matrix
#define def_k_sum5_matrix_out 5 ///< Output matrix
#define def_k_sum5_dimension 6 ///< Dimension of matrix
#define def_k_sum5_multiplyer 7 ///< Multiplyer for output
//---
#define def_k_MHAttentionScore 20 ///< Index of the kernel of the multi-heads attention neuron to calculate score matrix (#MHAttentionScore)
#define def_k_mhas_qkv 0 ///< Matrix of Queries, Keys, Values
#define def_k_mhas_score 1 ///< Matrix of Scores
#define def_k_mhas_dimension 2 ///< Dimension of Key
#define def_k_mhas_mask 3 ///< 1 - calc only previous units, 0 - calc all
//---
#define def_k_MHAttentionOut 21 ///< Index of the kernel of the multi-heads attention neuron to calculate multi-heads out matrix (#MHAttentionOut)
#define def_k_mhao_score 0 ///< Matrix of Scores
#define def_k_mhao_qkv 1 ///< Matrix of Queries, Keys, Values
#define def_k_mhao_out 2 ///< Matrix of Outputs
#define def_k_mhao_dimension 3 ///< Dimension of Key
//---
#define def_k_ConcatenateMatrix 17 ///< Index of the Multi Head Attention Neuron Concatenate Output kernel (#ConcatenateBuffers)
#define def_k_conc_input1 0 ///< Matrix of Buffer 1
#define def_k_conc_window1 1 ///< Window of Buffer 1
#define def_k_conc_input2 2 ///< Matrix of Buffer 2
#define def_k_conc_window2 3 ///< Window of Buffer 2
#define def_k_conc_input3 4 ///< Matrix of Buffer 3
#define def_k_conc_window3 5 ///< Window of Buffer 3
#define def_k_conc_input4 6 ///< Matrix of Buffer 4
#define def_k_conc_window4 7 ///< Window of Buffer 4
#define def_k_conc_out 8 ///< Output tesor
///@}
//---
///\defgroup neuron_atten_gr Attention layer's neuron Gradients Calculation
/// Describes the gradients calculation process for the Neuron of attention layer.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8765#para44">the link.</A>
///@{
#define def_k_AttentionGradients 14 ///< Index of the kernel for gradients calculation process (#AttentionInsideGradients)
#define def_k_ag_querys 0 ///< Matrix of Querys
#define def_k_ag_querys_g 1 ///< Matrix of Querys' Gradients
#define def_k_ag_keys 2 ///< Matrix of Keys
#define def_k_ag_keys_g 3 ///< Matrix of Keys' Gradients
#define def_k_ag_values 4 ///< Matrix of Values
#define def_k_ag_values_g 5 ///< Matrix of Values' Gradients
#define def_k_ag_scores 6 ///< Matrix of Scores
#define def_k_ag_gradient 7 ///< Matrix of Gradients from previous iteration
//---
#define def_k_DeconcatenateMatrix 18 ///< Index of the Multi Head Attention Neuron Deconcatenate Output kernel (#DeconcatenateBuffers)
#define def_k_dconc_output1 0 ///< Matrix of Buffer 1
#define def_k_dconc_window1 1 ///< Window of Buffer 1
#define def_k_dconc_output2 2 ///< Matrix of Buffer 2
#define def_k_dconc_window2 3 ///< Window of Buffer 2
#define def_k_dconc_output3 4 ///< Matrix of Buffer 3
#define def_k_dconc_window3 5 ///< Window of Buffer 3
#define def_k_dconc_output4 6 ///< Matrix of Buffer 4
#define def_k_dconc_window4 7 ///< Window of Buffer 4
#define def_k_dconc_inputs 8 ///< Input tesor
//---
#define def_k_MHAttentionGradients 22 ///< Index of the kernel for gradients calculation process (#AttentionInsideGradients)
#define def_k_mhag_qkv 0 ///< Matrix of Queries, Keys, Values
#define def_k_mhag_qkv_g 1 ///< Matrix of Gradients to Queries, Keys, Values
#define def_k_mhag_score 2 ///< Matrix of Scores
#define def_k_mhag_score_g 3 ///< Matrix of Scores Gradients
#define def_k_mhag_gradient 4 ///< Matrix of Gradients from previous iteration
#define def_k_mhag_dimension 5 ///< Dimension of Key
//---
#define def_k_Dropout 23 ///< Index of the kernel for Dropout process (#Dropout)
#define def_k_dout_input 0 ///< Inputs Tensor
#define def_k_dout_map 1 ///< Map Tensor
#define def_k_dout_out 2 ///< Out Tensor
#define def_k_dout_dimension 3 ///< Dimension of Inputs
///@}
///@}
//---
///\defgroup neuron_norm Kernels of matrix normalization process
/// Describes the process of matrix normalization.
///\details Detailed description on <A HREF="https://arxiv.org/abs/1607.06450">the link.</A>
///@{
#define def_k_Normilize 15 ///< Index of the kernel for matrix normalization (#Normalize)
#define def_k_norm_buffer 0 ///< In/Out Matrix
#define def_k_norm_dimension 1 ///< Dimension of matrix
//---
#define def_k_NormilizeWeights 16 ///< Index of the kernel for weights matrix normalization (#NormalizeWeights)
//---
#define def_k_BatchFeedForward 24 ///< Index of the kernel for Batch Normalization Feed Forward process (#CNeuronBathcNormOCL)
#define def_k_bff_inputs 0 ///< Inputs data tenzor
#define def_k_bff_options 1 ///< Tenzor of variables
#define def_k_bff_output 2 ///< Tenzor of output data
#define def_k_bff_batch 3 ///< Batch size
#define def_k_bff_optimization 4 ///< Optimization type
#define def_k_bff_activation 5 ///< Activation type
//---
#define def_k_CalcHiddenGradientBatch 25 ///< Index of the Kernel of the Batch neuron to transfer gradient to previous layer (#CNeuronBathcNormOCL)
#define def_k_bchg_options 0 ///<[in] Options matrix m*(7 or 9), where m - Number of neurons in previous layer
#define def_k_bchg_matrix_g 1 ///<[in] Tensor of gradients at current layer
#define def_k_bchg_matrix_i 2 ///<[in] Tensor of previous layer output
#define def_k_bchg_matrix_ig 3 ///<[out] Tensor of gradients at previous layer
#define def_k_bchg_activation 4 ///< Activation type (#ENUM_ACTIVATION)
#define def_k_bchg_batch 5 ///< Batch size
#define def_k_bchg_optimization 6 ///< Optimization type
//---
#define def_k_UpdateBatchOptionsMomentum 26 ///< Index of the kernel for Describe the process of SGD optimization options for the Batch normalization Neuron (#CNeuronBatchNormOCL).
#define def_k_buom_options 0 ///<[in] Options matrix m*(7 or 9), where m - Number of neurons in previous layer
#define def_k_buom_matrix_g 1 ///<[in] Tensor of gradients at current layer
#define def_k_buom_learning_rates 2 ///< Learning rates
#define def_k_buom_momentum 3 ///< Momentum multiplier
//---
#define def_k_UpdateBatchOptionsAdam 27 ///< Index of the kernel for Describe the process of Adam optimization options for the Batch normalization Neuron (#CNeuronBatchNormOCL).
#define def_k_buoa_options 0 ///<[in] Options matrix m*(7 or 9), where m - Number of neurons in previous layer
#define def_k_buoa_matrix_g 1 ///<[in] Tensor of gradients at current layer
#define def_k_buoa_l 2 ///< Learning rates
#define def_k_buoa_b1 3 ///< First momentum multiplier
#define def_k_buoa_b2 4 ///< Second momentum multiplier
///@}
///\defgroup VAE neuron Kernels of Variant Aoutoencodre
/// Describes the process of Variant Aoutoencodre.
///@{
#define def_k_VAEFeedForward 30
#define def_k_vaeff_inputs 0
#define def_k_vaeff_random 1
#define def_k_vaeff_outputd 2
//---
#define def_k_VAECalcHiddenGradient 31
#define def_k_vaehg_input 0
#define def_k_vaehg_inp_grad 1
#define def_k_vaehg_random 2
#define def_k_vaehg_gradient 3
#define def_k_vaehg_kld_mult 4
///@}
///\defgroup LSTM neuron Kernels of RNN unit
/// Describes the process of RNN.
///@{
#define def_k_LSTM_FeedForward 32
#define def_k_lstmff_inputs 0
#define def_k_lstmff_inputs_size 1
#define def_k_lstmff_weights 2
#define def_k_lstmff_concatenated 3
#define def_k_lstmff_memory 4
#define def_k_lstmff_outputs 5
//---
#define def_k_LSTM_ConcatenatedGradient 33
#define def_k_lstmcg_gradient 0
#define def_k_lstmcg_concatenated_gradient 1
#define def_k_lstmcg_memory 2
#define def_k_lstmcg_concatenated 3
//---
#define def_k_LSTM_HiddenGradient 34
#define def_k_lstmhg_concatenated_gradient 0
#define def_k_lstmhg_inputs_gradient 1
#define def_k_lstmhg_weights_gradient 2
#define def_k_lstmhg_hidden_state 3
#define def_k_lstmhg_inputs 4
#define def_k_lstmhg_weeights 5
#define def_k_lstmhg_output 6
#define def_k_lstmhg_hidden_size 7
#define def_k_lstmhg_inputs_size 8
//---
#define def_k_LSTM_UpdateWeightsAdam 35
#define def_k_lstmuw_weights 0
#define def_k_lstmuw_weights_gradient 1
#define def_k_lstmuw_matrix_m 2
#define def_k_lstmuw_matrix_v 3
#define def_k_lstmuw_l 4
#define def_k_lstmuw_b1 5
#define def_k_lstmuw_b2 6
///@}
///\defgroup SoftMax activation Kernels
///@{
#define def_k_SoftMax_FeedForward 36
#define def_k_softmaxff_inputs 0
#define def_k_softmaxff_outputs 1
#define def_k_softmaxff_total 2
//---
#define def_k_SoftMax_HiddenGradient 37
#define def_k_softmaxhg_outputs 0
#define def_k_softmaxhg_output_gr 1
#define def_k_softmaxhg_input_gr 2
//---
#define def_k_SoftMax_OutputGradient 38
#define def_k_softmaxog_outputs 0
#define def_k_softmaxog_targets 1
#define def_k_softmaxog_output_gr 2
///@}
///\defgroup SoftMax activation Kernels
///@{
#define def_k_FQF_Cosine 39
#define def_k_fqf_cosine_softmax 0
#define def_k_fqf_cosine_outputs 1
//---
#define def_k_FQF_Output 40
#define def_k_fqfout_quantiles 0
#define def_k_fqfout_delta_taus 1
#define def_k_fqfout_output 2
#define def_k_fqfout_total 3
//---
#define def_k_FQF_OutputGradient 41
#define def_k_fqfoutgr_quantiles 0
#define def_k_fqfoutgr_taus 1
#define def_k_fqfoutgr_output_gr 2
#define def_k_fqfoutgr_quantiles_gr 3
#define def_k_fqfoutgr_taus_gr 4
//---
#define def_k_FQF_QuantileGradient 42
#define def_k_fqfqgr_state_enbeding 0
#define def_k_fqfqgr_taus_embedding 1
#define def_k_fqfqgr_quantiles_gr 2
#define def_k_fqfqgr_state_gr 3
#define def_k_fqfqgr_taus_gr 4
//---
#define def_k_FQF_CosineGradient 43
#define def_k_fqfcosgr_softmax 0
#define def_k_fqfcosgr_output_gr 1
#define def_k_fqfcosgr_softmax_gr 2
//---
//---
#define def_k_MHSparseAttentionScore 44 ///< Index of the kernel of the multi-heads sparse attention neuron to calculate score matrix (#MHSparseAttentionScore)
#define def_k_mhas_sparse 3 ///< less than 1.0 сoefficient of sparse
//---
#define def_k_MHSparseAttentionOut 45 ///< Index of the kernel of the multi-heads sparse attention neuron to calculate multi-heads out matrix (#MHSparseAttentionOut)
//---
#define def_k_FFMultiModels 46 ///< Index of the kernel of the multi-models neuron to calculate feed forward
#define def_k_HGMultiModels 47 ///< Index of the kernel of the multi-models neuron to calculate hiden gradient
#define def_k_chg_model 6 ///< Number of model to calculate
#define def_k_UWMultiModels 48 ///< Index of the kernel of the multi-models neuron to update weights
#define def_k_uwa_model 9 ///< Number of model to update
///@}
///@}
#define def_k_ConcatFeedForward 49 ///< Index of #FeedForward kernel
#define def_k_cff_matrix_w 0 ///< Weights matrix (m+1)*n, where m - number of neurons in layer and n - number of outputs (neurons in next layer)
#define def_k_cff_matrix_i1 1 ///< Inputs tesor
#define def_k_cff_matrix_i2 2 ///< Inputs tesor
#define def_k_cff_matrix_o 3 ///< Output tensor
#define def_k_cff_inputs1 4 ///< Number of inputs
#define def_k_cff_inputs2 5 ///< Number of inputs
#define def_k_cff_activation 6 ///< Activation type (#ENUM_ACTIVATION)
//---
#define def_k_ConcatCalcHiddenGradient 50 ///< Index of Hidden gradients calculation kernel (#CalcHiddenGradient)
#define def_k_cchg_matrix_w 0 ///< Weights matrix (m+1)*n, where m - number of neurons in previous layer and n - number of neurons in current layer
#define def_k_cchg_matrix_g 1 ///< Tensor of gradients at current layer
#define def_k_cchg_matrix_o1 2 ///< Output tensor
#define def_k_cchg_matrix_o2 3 ///< Output tensor
#define def_k_cchg_matrix_ig1 4 ///< Tensor of gradients at previous layer
#define def_k_cchg_matrix_ig2 5 ///< Tensor of gradients at previous layer
#define def_k_cchg_outputs 6 ///< Number of outputs
#define def_k_cchg_inputs1 7 ///< Number of inputs1
#define def_k_cchg_inputs2 8 ///< Number of inputs2
#define def_k_cchg_activation1 9 ///< Activation type (#ENUM_ACTIVATION)
#define def_k_cchg_activation2 10 ///< Activation type (#ENUM_ACTIVATION)
//---
#define def_k_ConcatUpdWeightsMomentum 51 ///< Index SGD optomization Update weights kernel (#UpdateWeightsMomentum)
#define def_k_cuwm_matrix_w 0 ///< SGD Weights matrix (m+1)*n, where m - number of neurons in previous layer and n - number of neurons in current layer
#define def_k_cuwm_matrix_g 1 ///< SGD Tensor of gradients at current layer
#define def_k_cuwm_matrix_i1 2 ///< SGD Inputs tensor
#define def_k_cuwm_matrix_i2 3 ///< SGD Inputs tensor
#define def_k_cuwm_matrix_dw 4 ///< SGD Matrix of delta weights in last correction
#define def_k_cuwm_inputs1 5 ///< SGD Number of inputs
#define def_k_cuwm_inputs2 6 ///< SGD Number of inputs
#define def_k_cuwm_learning_rates 7 ///< SGD Learning rates
#define def_k_cuwm_momentum 8 ///< SGD Momentum multiplier
//---
#define def_k_ConcatUpdWeightsAdam 52 ///< Index Adam optomization Update weights kernel (#UpdateWeightsAdam)
#define def_k_cuwa_matrix_w 0 ///< Adam Weights matrix (m+1)*n, where m - number of neurons in previous layer and n - number of neurons in current layer
#define def_k_cuwa_matrix_g 1 ///< Adam Tensor of gradients at current layer
#define def_k_cuwa_matrix_i1 2 ///< Adam Inputs tensor
#define def_k_cuwa_matrix_i2 3 ///< Adam Inputs tensor
#define def_k_cuwa_matrix_m 4 ///< Adam Matrix of first momentum
#define def_k_cuwa_matrix_v 5 ///< Adam Matrix of seconfd momentum
#define def_k_cuwa_inputs1 6 ///< Adam Number of inputs
#define def_k_cuwa_inputs2 7 ///< Adam Number of inputs
#define def_k_cuwa_l 8 ///< Adam Learning rates
#define def_k_cuwa_b1 9 ///< Adam First momentum multiplier
#define def_k_cuwa_b2 10 ///< Adam Second momentum multiplier
//---
#define def_k_SoftUpdate 53
#define def_k_su_target 0
#define def_k_su_source 1
#define def_k_su_tau 2
//---
#define def_k_SoftUpdateAdam 54
#define def_k_sua_target 0
#define def_k_sua_source 1
#define def_k_sua_matrix_m 2
#define def_k_sua_matrix_v 3
#define def_k_sua_tau 4
#define def_k_sua_b1 5
#define def_k_sua_b2 6
//---
#define def_k_SAC_AlphaLogProbs 55
#define def_k_sac_alp_outputs 0
#define def_k_sac_alp_quantiles 1
#define def_k_sac_alp_probs 2
#define def_k_sac_alp_alphas 3
#define def_k_sac_alp_log_probs 4
#define def_k_sac_alp_random 5
#define def_k_sac_alp_count_quants 6
#define def_k_sac_alp_activation 7
//---
#define def_k_SAC_AlphaGradients 56
#define def_k_sac_alg_outputs 0
#define def_k_sac_alg_gradient 1
#define def_k_sac_alg_log_probs 2
#define def_k_sac_alg_alphas_grad 3
#define def_k_sac_alg_activation 4
//---
#define def_k_SAC_OutputGradient 57
#define def_k_sacoutgr_quantiles 0
#define def_k_sacoutgr_taus 1
#define def_k_sacoutgr_output_gr 2
#define def_k_sacoutgr_quantiles_gr 3
#define def_k_sacoutgr_taus_gr 4
#define def_k_sacoutgr_outputs 5
#define def_k_sacoutgr_count_quants 6
#define def_k_sacoutgr_activation 7
//---
#define def_k_SAC_CalcLogProbs 58
#define def_k_sacclp_outputs 0
#define def_k_sacclp_quantiles 1
#define def_k_sacclp_probs 2
#define def_k_sacclp_alphas 3
#define def_k_sacclp_log_probs 4
#define def_k_sacclp_count_quants 5
#define def_k_sacclp_activation 6
//---
#define def_k_Embedding 59
#define def_k_emb_inputs 0
#define def_k_emb_outputs 1
#define def_k_emb_weights 2
#define def_k_emb_windows 3
#define def_k_emb_std 4
#define def_k_emb_stack_size 5
//---
#define def_k_EmbeddingHiddenGradient 60
#define def_k_ehg_inputs_gradient 0
#define def_k_ehg_outputs_gradient 1
#define def_k_ehg_weights 2
#define def_k_ehg_windows 3
#define def_k_ehg_std 4
#define def_k_ehg_window_out 5
//---
#define def_k_EmbeddingUpdateWeightsAdam 61
#define def_k_euw_weights 0
#define def_k_euw_gradient 1
#define def_k_euw_inputs 2
#define def_k_euw_matrix_m 3
#define def_k_euw_matrix_v 4
#define def_k_euw_windows 5
#define def_k_euw_std 6
#define def_k_euw_window_out 7
#define def_k_euw_learning_rate 8
#define def_k_euw_b1 9
#define def_k_euw_b2 10
//---
#define def_k_Transpose 62
#define def_k_tr_matrix_in 0
#define def_k_tr_matrix_out 1
//---
#define def_k_MH2AttentionOut 63
#define def_k_mh2ao_q 0 ///< Matrix of Queries
#define def_k_mh2ao_kv 1 ///< Matrix of Keys, Values
#define def_k_mh2ao_score 2 ///< Matrix of Scores
#define def_k_mh2ao_out 3 ///< Matrix of Outputs
#define def_k_mh2ao_dimension 4 ///< Dimension of Key
//---
#define def_k_MH2AttentionInsideGradients 64
#define def_k_mh2aig_q 0 ///< Matrix of Queries
#define def_k_mh2aig_qg 1 ///< Matrix of Queries gradient
#define def_k_mh2aig_kv 2 ///< Matrix of Keys, Values
#define def_k_mh2aig_kvg 3 ///< Matrix of Keys, Values gradient
#define def_k_mh2aig_score 4 ///< Matrix of Scores
#define def_k_mh2aig_outg 5 ///< Matrix of Outputs gradient
#define def_k_mh2aig_kunits 6 ///< Size of Key
//---
#define def_k_CGConv_HiddenGradient 65
#define def_k_cgc_matrix_g 0 ///<[in] Tensor of gradients at current layer
#define def_k_cgc_matrix_f 1 ///<[in] Previous layer Output tensor
#define def_k_cgc_matrix_s 2 ///<[in] Previous layer Output tensor
#define def_k_cgc_matrix_fg 3 ///<[out] Tensor of gradients at previous layer
#define def_k_cgc_matrix_sg 4 ///<[out] Tensor of gradients at previous layer
#define def_k_cgc_activationf 5 ///< Activation type (#ENUM_ACTIVATION)
#define def_k_cgc_activations 6 ///< Activation type (#ENUM_ACTIVATION)
//---
#define def_k_XCiTFeedForward 66
#define def_k_XCiTff_qkv 0
#define def_k_XCiTff_score 1
#define def_k_XCiTff_out 2
//---
#define def_k_XCiTInsideGradients 67
#define def_k_XCiTig_qkv 0
#define def_k_XCiTig_qkv_g 1
#define def_k_XCiTig_scores 2
#define def_k_XCiTig_gradient 3
//---
#define def_k_DOTFeedForward 68
#define def_k_dot_qkv 0
#define def_k_dot_score 1
#define def_k_dot_rpb 2
#define def_k_dot_out 3
//---
#define def_k_DOTInsideGradients 69
#define def_k_dotg_qkv 0
#define def_k_dotg_qkv_g 1
#define def_k_dotg_scores 2
#define def_k_dotg_rpb 3
#define def_k_dotg_rpb_g 4
#define def_k_dotg_gradient 5
//---
#define def_k_RPBUpdateAdam 70
#define def_k_rpbw_rpb 0
#define def_k_rpbw_gradient 1
#define def_k_rpbw_matrix_m 2
#define def_k_rpbw_matrix_v 3
#define def_k_rpbw_b1 4
#define def_k_rpbw_b2 5
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#resource "NeuroNet.cl" as string cl_program
///\defgroup enums ENUM
///@{
//+------------------------------------------------------------------+
/// Enum of activation formula used
//+------------------------------------------------------------------+
enum ENUM_ACTIVATION
{
None = -1, ///< Without activation formula
TANH, ///< Use \f$tanh(x)\f$ for activation neuron
SIGMOID, ///< Use \f$\frac{1}{1+e^x}\f$ for activation neuron
LReLU ///< For activation neuron use LReLU \f[\left\{ \begin{array} a x>=0, \ x \\x<0, \ 0.01*x \end{array} \right.\f]
};
//+------------------------------------------------------------------+
/// Enum of optimization method used
//+------------------------------------------------------------------+
enum ENUM_OPTIMIZATION
{
SGD, ///< Stochastic gradient descent
ADAM, ///< Adam
LS ///< Least Squares
};
///@}
//+------------------------------------------------------------------+
///\class CConnection
///\brief Class of connection to anothe neuron
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/7447#para51">the link.</A>
//+------------------------------------------------------------------+
class CConnection : public CObject
{
public:
float weight; ///< Current weight
float deltaWeight; ///< last delta of weight used in SGD optimization
float mt; ///< First moment in Adam optimization
float vt; ///< Second moment in Adam optimization
/** Constructor @param[in] w initial weight */ CConnection(float w) { weight = w; deltaWeight = 0; mt = 0; vt = 0; }
/** Destructor */ ~CConnection() {};
//--- methods for working with files
virtual bool Save(int const file_handle); ///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle); ///< Load method @param[in] file_handle handle of file @return logical result of operation
virtual int Type(void) const { return defConnect; } ///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CConnection::Save(int file_handle)
{
if(file_handle == INVALID_HANDLE)
return false;
//---
if(FileWriteDouble(file_handle, weight) <= 0)
return false;
if(FileWriteDouble(file_handle, deltaWeight) <= 0)
return false;
if(FileWriteDouble(file_handle, mt) <= 0)
return false;
if(FileWriteDouble(file_handle, vt) <= 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CConnection::Load(int file_handle)
{
if(file_handle == INVALID_HANDLE)
return false;
//---
weight = (float)FileReadDouble(file_handle);
deltaWeight = (float)FileReadDouble(file_handle);
mt = (float)FileReadDouble(file_handle);
vt = (float)FileReadDouble(file_handle);
//---
return true;
}
//+------------------------------------------------------------------+
///\class CArrayCon
///\brief Array of connections to anothe neuron
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/7447#para51">the link.</A>
//+------------------------------------------------------------------+
class CArrayCon : public CArrayObj
{
public:
/** Constructor */
CArrayCon(void) {};
/** Destructor */ ~CArrayCon(void) {};
//---
virtual bool CreateElement(int const index); ///< Method for cearing new element by index @param[in] index Index of new element @return logical result of operation
virtual void IncreaseTotal() { m_data_total++; } ///< Increase number of elements in array
virtual int Type(void) const { return defArrayConnects; } ///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CArrayCon::CreateElement(int index)
{
if(index < 0 || index >= m_data_max)
return false;
//---
xor128;
float weigh = (float)(rnd_w / UINT_MAX - 0.5);
m_data[index] = new CConnection(weigh / 100);
if(!CheckPointer(m_data[index]) != POINTER_INVALID)
return false;
//---
return (true);
}
//+------------------------------------------------------------------+
///\class CLayer
/// Class of neurons collection in one layer of Neural Net.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/7447#para53">the link.</A>
//+------------------------------------------------------------------+
class CLayer;
//+------------------------------------------------------------------+
///\class CNeuronBase
/// The base class of neuron.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/7447#para52">the link.</A>
//+------------------------------------------------------------------+
class CNeuronBase : public CObject
{
protected:
float outputVal; ///< Output value
float prevVal; ///< Previous output value
uint m_myIndex; ///< Index of neuron in layer
float gradient; ///< Current gradient of neuron
CArrayCon *Connections; ///< Array of connections with neurons in next layer
ENUM_ACTIVATION activation; ///< Activation type (#ENUM_ACTIVATION)
ENUM_OPTIMIZATION optimization; ///< Optimization method (#ENUM_OPTIMIZATION)
int t; ///< Count of iterations
//---
virtual bool feedForward(CLayer *prevLayer) { return false; } ///< Feed Forward method.@param prevLayer Pointer to previos layer.
virtual bool calcHiddenGradients(CLayer *&nextLayer) { return false; } ///< Method to transfer gradient to previous layer. @param nextLayer Pointer to next layer.
virtual bool updateInputWeights(CLayer *&prevLayer) { return false; } ///< Method for updating weights.@param prevLayer Pointer to previos layer.
virtual float activationFunction(float x); ///< Method to calculate activation function.@param x Input data. @return Result of activation function.
virtual float SigmoidFunction(float x) { return (float)MathPow(1 + exp(-x), -1); } ///< Calculating Sigmoid \f$\frac{1}{1+e^x}\f$.@param x Input data.@return Result of calculation
virtual float TanhFunction(float x) { return (float)tanh(x); } ///< Calculating \f$tanh(x)\f$.@param x Input data.@return Result of calculation
virtual CLayer *getOutputLayer(void) { return NULL; } ///< Method for getting a pointer to the resulting neural layer. Not used in fully connected neural networks.@return Pointer to layer.
public:
/** Constructor */
CNeuronBase(void);
/** Destructor */~CNeuronBase(void);
virtual bool Init(uint numOutputs, uint myIndex, ENUM_OPTIMIZATION optimization_type); ///< Method of initialization class.@param numOutputs Number of connections to next layer.@param myIndex Index of neuron in layer.@param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
virtual void SetActivationFunction(ENUM_ACTIVATION value) { activation = value; } ///< Set the type of activation function (#ENUM_ACTIVATION)
//---
//static float lr;
static float alpha; ///< Multiplier to momentum in SGD optimization
//---
virtual void setOutputVal(float val) { prevVal = outputVal; outputVal = val; } ///< Set the output value
virtual float getOutputVal() { return outputVal; } ///< Return result of feed forward operations.@return Output value
virtual float getPrevVal() { return prevVal; } ///< Return result of feed forward operations at previous iteration.@return Previous output value
virtual void setGradient(float val) { gradient = val; } ///< Set gradient value to neuron.
virtual float getGradient() { return gradient; } ///< Return gradient of neuron.@return Gradient
virtual CArrayCon *getConnections() { return Connections;} ///< Method to get access to array of connections.@return Pointer to connections array
virtual float activationFunctionDerivative(float x); ///< Calculate derivative of activation function.@param[in] x Input data@return Derivative
virtual float SigmoidFunctionDerivative(float x) { return x * (1 - x); } ///< Calculate derivative of Sigmoid function.@param x Input data@return Derivative
virtual float TanhFunctionDerivative(float x) { return (1 + x) * (1 - x); } ///< Calculate derivative of \f$tanh(x)\f$.@param x Input data@return Derivative
//---
virtual bool feedForward(CObject *&SourceObject); ///< Dispatch method for defining the subroutine for Feed Forward process.@param SourceObject Pointer to previos layer.
virtual bool calcHiddenGradients(CObject *&TargetObject); ///< Dispatch method for defining the subroutine for transfer gradient to previous layer.@param TargetObject Pointer to next layer.
virtual bool updateInputWeights(CObject *&SourceObject); ///< Dispatch method for defining the subroutine for updating weights.@param SourceObject Pointer to previos layer.
//---
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle)///< Load method @param[in] file_handle handle of file @return logical result of operation
{
activation = (ENUM_ACTIVATION)FileReadInteger(file_handle, INT_VALUE);
optimization = (ENUM_OPTIMIZATION)FileReadInteger(file_handle, INT_VALUE);
t = (ENUM_OPTIMIZATION)FileReadInteger(file_handle, INT_VALUE);
return(Connections.Load(file_handle));
}
//---
virtual int Type(void) const { return defNeuronBase; }///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//float CNeuronBase::lr=0.0000001; // net learning rate
float CNeuronBase::alpha = (float)0.8; // momentum
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronBase::CNeuronBase(void) :
outputVal(1),
gradient(0),
activation(TANH),
t(1),
optimization(SGD)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronBase::~CNeuronBase(void)
{
if(CheckPointer(Connections) != POINTER_INVALID)
delete Connections;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBase::Init(uint numOutputs, uint myIndex, ENUM_OPTIMIZATION optimization_type)
{
if(CheckPointer(Connections) == POINTER_INVALID)
{
Connections = new CArrayCon();
if(CheckPointer(Connections) == POINTER_INVALID)
return false;
}
//---
if(Connections.Reserve(fmax(numOutputs, 1)))
for(uint c = 0; c < numOutputs; c++)
{
if(!Connections.CreateElement(c))
return false;
Connections.IncreaseTotal();
}
//---
m_myIndex = myIndex;
optimization = optimization_type;
return true;
}
//+------------------------------------------------------------------+
///\class CNeuron
/// Class of neuron for full connected layers.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/7447#para52">the link.</A>
//+------------------------------------------------------------------+
class CNeuron : public CNeuronBase
{
private:
virtual bool feedForward(CLayer *prevLayer); ///< Feed Forward method.@param prevLayer Pointer to previos layer.
virtual bool calcHiddenGradients(CLayer *&nextLayer); ///< Method to transfer gradient to previous layer. @param nextLayer Pointer to next layer.
virtual bool updateInputWeights(CLayer *&prevLayer); ///< Method for updating weights.@param prevLayer Pointer to previos layer.
public:
/** Constructor */
CNeuron(void) {};
/** Destructor */~CNeuron(void) { Connections.Shutdown(); }
//---
virtual bool calcOutputGradients(float targetVals); ///< Method of output gradients calculation.@param targetVals Traget value
virtual float sumDOW(CLayer *&nextLayer) ; ///< A method for collecting gradients from the next layer.@param[in] nextLayer Pointer to next layer@return Total gradient to neuron.
virtual int Type(void) const { return defNeuron; } ///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuron::updateInputWeights(CLayer *&prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
float lt = (float)(lr * sqrt(1 - pow(b2, t)) / (1 - pow(b1, t)));
int total = prevLayer.Total();
for(int n = 0; n < total && !IsStopped(); n++)
{
CNeuron *neuron = prevLayer.At(n);
CConnection *con = neuron.Connections.At(m_myIndex);
if(CheckPointer(con) == POINTER_INVALID)
continue;
if(optimization == SGD)
con.weight += con.deltaWeight = (gradient != 0 ? lr * neuron.getOutputVal() * gradient : 0) + (con.deltaWeight != 0 ? alpha*con.deltaWeight : 0);
else
{
con.mt = b1 * con.mt + (1 - b1) * gradient;
con.vt = (float)(b2 * con.vt + (1 - b2) * pow(gradient, 2) + 0.00000001);
con.weight += con.deltaWeight = (float)(lt * con.mt / sqrt(con.vt));
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
float CNeuron::sumDOW(CLayer *&nextLayer)
{
float sum = 0.0;
int total = nextLayer.Total() - 1;
for(int n = 0; n < total; n++)
{
CConnection *con = Connections.At(n);
if(CheckPointer(con) == POINTER_INVALID)
continue;
float weight = con.weight;
if(weight != 0)
{
CNeuron *neuron = nextLayer.At(n);
sum += weight * neuron.gradient;
}
}
return sum;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuron::calcHiddenGradients(CLayer *&nextLayer)
{
float targetVal = sumDOW(nextLayer) + outputVal;
return calcOutputGradients(targetVal);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuron::calcOutputGradients(float targetVal)
{
float delta = (targetVal > 1 ? 1 : targetVal < -1 ? -1 : targetVal) - outputVal;
gradient = (delta != 0 ? delta * activationFunctionDerivative(outputVal) : 0);
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuron::feedForward(CLayer *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID || prevLayer.Type() != defLayer)
return false;
//---
prevVal = outputVal;
float sum = 0.0;
int total = prevLayer.Total();
for(int n = 0; n < total && !IsStopped(); n++)
{
CNeuron *temp = prevLayer.At(n);
float val = temp.getOutputVal();
if(val != 0)
{
CConnection *con = temp.Connections.At(m_myIndex);
if(CheckPointer(con) == POINTER_INVALID)
continue;
sum += val * con.weight;
}
}
outputVal = activationFunction(MathMin(MathMax(sum, -18), 18));
//---
return true;
}
//+------------------------------------------------------------------+
///\class COpenCLMy
/// Class for working with OpenCL
//+------------------------------------------------------------------+
class COpenCLMy : public COpenCL
{
public:
/** Constructor */
COpenCLMy(void) {};
/** Destructor */~COpenCLMy(void) {};
template<typename T>
int AddBufferFromArray(T &data[], const uint data_array_offset, const uint data_array_count, const uint flags);
///< Method for creating OpenCL buffer from array.@param data[] Array of data.@param data_array_offset Offset of data in array.@param data_array_count Number of data items in array.@param flags Buffer's properties (CL_MEM_READ_WRITE, CL_MEM_WRITE_ONLY, CL_MEM_READ_ONLY, CL_MEM_ALLOC_HOST_PTR)
int AddBuffer(uint size_in_bytes, const uint flags);
/// @return Index of buffer.
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CLayer: public CArrayObj
{
private:
uint iOutputs; ///< Number of output connections from 1 neuron to neurons in next layer.
int iFileHandle; ///< File handle for download result of previous study.
COpenCLMy *OpenCL; ///< Class for working with OpenCL
public:
/** Constructor */
CLayer(uint outputs = 0, int handle = INVALID_HANDLE, COpenCLMy *OpenCL = NULL);
///< @param[in] outputs Number of output connections from 1 neuron to neurons in next layer @param[in] handle File handle for download result of previous study @param[in] OpenCL Pointer to class for working with OpenCL
/** Destructor */~CLayer(void) {};
//---
virtual bool CreateElement(int const index); ///< Method for creating new element in layer
virtual void IncreaseTotal() { m_data_total++; } ///< Method for increase number of items in layer
virtual int Type(void) const { return defLayer; } ///< Identificator of class.@return Type of class
virtual bool Load(const int file_handle); ///< Load method @param[in] file_handle handle of file @return logical result of operation
virtual uint Outputs(void) { return iOutputs; }
virtual void SetOpenCL(COpenCLMy *obj);
virtual bool WeightsUpdate(CLayer *source, float tau);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CLayer::CreateElement(int index)
{
if(index >= m_data_max)
return false;
//---
bool result = false;
CNeuronBase *temp = NULL;
CNeuronProof *temp_p = NULL;
CNeuronBaseOCL *temp_ocl = NULL;
CNeuronProofOCL *temp_proof_ocl = NULL;
CNeuronConvOCL *temp_con_ocl = NULL;
CNeuronAttentionOCL *temp_at_ocl = NULL;
CNeuronMH2AttentionOCL *temp_mh2at_ocl = NULL;
CNeuronMLMHAttentionOCL *temp_mlat_ocl = NULL;
CNeuronDropoutOCL *temp_drop_ocl = NULL;
CNeuronBatchNormOCL *temp_batch_ocl = NULL;
CVAE *vae = NULL;
CNeuronLSTMOCL *lstm = NULL;
CNeuronSoftMaxOCL *softmax = NULL;
CNeuronFQF *fqf = NULL;
CNeuronMultiModel *multi_model = NULL;
CNeuronConcatenate *concat = NULL;
CNeuronEmbeddingOCL *emb = NULL;
CNeuronPositionEncoder *pe = NULL;
CNeuronTransposeOCL *tr = NULL;
CNeuronCGConvOCL *cgc = NULL;
CNeuronDOTOCL *dot = NULL;
CNeuronFAQOCL *faq = NULL;
CNeuronCrossAttention *cross = NULL;
int windows[] = {1};
if(iFileHandle <= 0)
{
temp = new CNeuron();
if(CheckPointer(temp) == POINTER_INVALID || !temp.Init(iOutputs, index, SGD))
return false;
result = true;
}
else
{
int type = FileReadInteger(iFileHandle);
switch(type)
{
case defNeuron:
temp = new CNeuron();
if(CheckPointer(temp) == POINTER_INVALID)
result = false;
result = temp.Init(iOutputs, index, ADAM);
break;
case defNeuronProof:
temp_p = new CNeuronProof();
if(CheckPointer(temp_p) == POINTER_INVALID)
result = false;
if(temp_p.Init(iOutputs, index, 1, 1, 1, ADAM))
{
temp = temp_p;
result = true;
}
break;
case defNeuronConv:
temp_p = new CNeuronConv();
if(CheckPointer(temp_p) == POINTER_INVALID)
result = false;
if(temp_p.Init(iOutputs, index, 1, 1, 1, ADAM))
{
temp = temp_p;
result = true;
}
break;
case defNeuronLSTM:
temp_p = new CNeuronLSTM();
if(CheckPointer(temp_p) == POINTER_INVALID)
result = false;
if(temp_p.Init(iOutputs, index, 1, 1, 1, ADAM))
{
temp = temp_p;
result = true;
}
break;
case defNeuronBaseOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_ocl = new CNeuronBaseOCL();
if(CheckPointer(temp_ocl) == POINTER_INVALID)
result = false;
if(temp_ocl.Init(iOutputs, index, OpenCL, 1, ADAM, 1))
{
m_data[index] = temp_ocl;
return true;
}
break;
case defNeuronProofOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_proof_ocl = new CNeuronProofOCL();
if(CheckPointer(temp_proof_ocl) == POINTER_INVALID)
result = false;
if(temp_proof_ocl.Init(iOutputs, index, OpenCL, 1, 1, 1, ADAM, 1))
{
m_data[index] = temp_proof_ocl;
return true;
}
case defNeuronConvOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_con_ocl = new CNeuronConvOCL();
if(CheckPointer(temp_con_ocl) == POINTER_INVALID)
result = false;
if(temp_con_ocl.Init(iOutputs, index, OpenCL, 1, 1, 1, 1, ADAM, 1))
{
m_data[index] = temp_con_ocl;
return true;
}
break;
case defNeuronAttentionOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_at_ocl = new CNeuronAttentionOCL();
if(CheckPointer(temp_at_ocl) == POINTER_INVALID)
result = false;
if(temp_at_ocl.Init(iOutputs, index, OpenCL, 1, 1, ADAM, 1))
{
m_data[index] = temp_at_ocl;
return true;
}
break;
case defNeuronMHAttentionOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_at_ocl = new CNeuronMHAttentionOCL();
if(CheckPointer(temp_at_ocl) == POINTER_INVALID)
result = false;
if(temp_at_ocl.Init(iOutputs, index, OpenCL, 1, 1, ADAM, 1))
{
m_data[index] = temp_at_ocl;
return true;
}
break;
case defNeuronMLMHAttentionOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_mlat_ocl = new CNeuronMLMHAttentionOCL();
if(CheckPointer(temp_mlat_ocl) == POINTER_INVALID)
result = false;
if(temp_mlat_ocl.Init(iOutputs, index, OpenCL, 1, 1, 1, 1, 0, ADAM, 1))
{
m_data[index] = temp_mlat_ocl;
return true;
}
break;
case defNeuronMLMHSparseAttentionOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_mlat_ocl = new CNeuronMLMHSparseAttention();
if(CheckPointer(temp_mlat_ocl) == POINTER_INVALID)
result = false;
if(temp_mlat_ocl.Init(iOutputs, index, OpenCL, 1, 1, 1, 1, 0, ADAM, 1))
{
m_data[index] = temp_mlat_ocl;
return true;
}
break;
case defNeuronDropoutOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_drop_ocl = new CNeuronDropoutOCL();
if(CheckPointer(temp_drop_ocl) == POINTER_INVALID)
result = false;
if(temp_drop_ocl.Init(iOutputs, index, OpenCL, 1.0f, 0.1f, ADAM, 1))
{
m_data[index] = temp_drop_ocl;
return true;
}
break;
case defNeuronBatchNormOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_batch_ocl = new CNeuronBatchNormOCL();
if(CheckPointer(temp_batch_ocl) == POINTER_INVALID)
result = false;
if(temp_batch_ocl.Init(iOutputs, index, OpenCL, 1, 1, ADAM))
{
m_data[index] = temp_batch_ocl;
return true;
}
break;
case defNeuronVAEOCL:
if(!OpenCL)
return false;
vae = new CVAE();
if(!vae)
result = false;
if(vae.Init(iOutputs, index, OpenCL, 1, ADAM, 1))
{
m_data[index] = vae;
return true;
}
break;
case defNeuronLSTMOCL:
if(!OpenCL)
return false;
lstm = new CNeuronLSTMOCL();
if(!lstm)
result = false;
if(lstm.Init(iOutputs, index, OpenCL, 1, ADAM, 1))
{
m_data[index] = lstm;
return true;
}
break;
case defNeuronSoftMaxOCL:
if(!OpenCL)
return false;
softmax = new CNeuronSoftMaxOCL();
if(!softmax)
result = false;
if(softmax.Init(iOutputs, index, OpenCL, 1, ADAM, 1))
{
m_data[index] = softmax;
return true;
}
break;
case defNeuronFQF:
if(!OpenCL)
return false;
fqf = new CNeuronFQF();
if(!fqf)
result = false;
if(fqf.Init(iOutputs, index, OpenCL, 1, 32, 32, ADAM, 1))
{
m_data[index] = fqf.AsObject();
return true;
}
break;
case defNeuronMultiModels:
if(!OpenCL)
return false;
multi_model = new CNeuronMultiModel();
if(!multi_model)
result = false;
if(multi_model.Init(iOutputs, index, OpenCL, 1, ADAM, 1))
{
m_data[index] = multi_model;
return true;
}
break;
case defNeuronConcatenate:
if(!OpenCL)
return false;
concat = new CNeuronConcatenate();
if(!concat)
result = false;
if(concat.Init(iOutputs, index, OpenCL, 1, 1, 1, ADAM, 1))
{
m_data[index] = concat;
return true;
}
break;
case defNeuronSoftActorCritic:
if(!OpenCL)
return false;
fqf = new CNeuronSoftActorCritic();
if(!fqf)
return false;
if(fqf.Init(iOutputs, index, OpenCL, 1, 32, 32, ADAM, 1))
{
m_data[index] = fqf.AsObject();
return true;
}
break;
case defNeuronEmbeddingOCL:
if(!OpenCL)
return false;
emb = new CNeuronEmbeddingOCL();
if(!emb)
return false;
if(!emb.Init(iOutputs, index, OpenCL, 1, 1, windows))
{
delete emb;
return false;
}
m_data[index] = emb;
return true;
break;
case defNeuronPEOCL:
if(!OpenCL)
return false;
pe = new CNeuronPositionEncoder();
if(!pe)
return false;
if(!pe.Init(iOutputs, index, OpenCL, 1, 1, ADAM, 1))
{
delete pe;
return false;
}
m_data[index] = pe;
return true;
break;
case defNeuronTransposeOCL:
if(!OpenCL)
return false;
tr = new CNeuronTransposeOCL();
if(!tr)
return false;
if(!tr.Init(iOutputs, index, OpenCL, 1, 1, ADAM, 1))
{
delete tr;
return false;
}
m_data[index] = tr;
return true;
break;
case defNeuronMH2AttentionOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_mh2at_ocl = new CNeuronMH2AttentionOCL();
if(CheckPointer(temp_mh2at_ocl) == POINTER_INVALID)
result = false;
if(temp_mh2at_ocl.Init(iOutputs, index, OpenCL, 1, 1, 1, 1, ADAM, 1))
{
m_data[index] = temp_mh2at_ocl;
return true;
}
break;
case defNeuronCGConvOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
cgc = new CNeuronCGConvOCL();
if(CheckPointer(cgc) == POINTER_INVALID)
result = false;
if(cgc.Init(iOutputs, index, OpenCL, 1, 1, ADAM, 1))
{
m_data[index] = cgc;
return true;
}
break;
case defNeuronMFTOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_mlat_ocl = new CNeuronMFTOCL();
if(CheckPointer(temp_mlat_ocl) == POINTER_INVALID)
result = false;
if(temp_mlat_ocl.Init(iOutputs, index, OpenCL, 1, 1, 1, 1, 1, ADAM, 1))
{
m_data[index] = temp_mlat_ocl;
return true;
}
break;
case defNeuronXCiTOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
temp_mlat_ocl = new CNeuronXCiTOCL();
if(CheckPointer(temp_mlat_ocl) == POINTER_INVALID)
result = false;
if(temp_mlat_ocl.Init(iOutputs, index, OpenCL, 1, 1, 1, 1, 0, ADAM, 1))
{
m_data[index] = temp_mlat_ocl;
return true;
}
break;
case defNeuronDOTOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
dot = new CNeuronDOTOCL();
if(CheckPointer(dot) == POINTER_INVALID)
result = false;
if(dot.Init(iOutputs, index, OpenCL, 1, 1, 1, 1, 1, ADAM, 1))
{
m_data[index] = dot;
return true;
}
break;
case defNeuronFAQOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
faq = new CNeuronFAQOCL();
if(CheckPointer(faq) == POINTER_INVALID)
result = false;
if(faq.Init(iOutputs, index, OpenCL, 1, 1, 1, 1, 1, ADAM, 1))
{
m_data[index] = faq;
return true;
}
break;
case defNeuronCrossAttenOCL:
if(CheckPointer(OpenCL) == POINTER_INVALID)
return false;
cross = new CNeuronCrossAttention();
if(CheckPointer(cross) == POINTER_INVALID)
result = false;
if(cross.Init(iOutputs, index, OpenCL, 1, 1, 1, 1, 1, 1, ADAM, 1))
{
m_data[index] = cross;
return true;
}
break;
default:
result = false;
break;
}
}
if(result)
m_data[index] = temp;
//---
return (result);
}
//+------------------------------------------------------------------+
///\class CArrayLayer
/// Class of layers collection in Neural Net.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/7447#para53">the link.</A>
//+------------------------------------------------------------------+
class CArrayLayer : public CArrayObj
{
public:
/** Constructor */
CArrayLayer(void) {};
/** Destructor */~CArrayLayer(void) {};
//---
virtual bool CreateElement(uint neurons, uint outputs); ///< Method for creating new element
virtual int Type(void) const { return defArrayLayer; } ///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CArrayLayer::CreateElement(uint neurons, uint outputs)
{
if(neurons <= 0)
return false;
//---
CLayer *layer = new CLayer(outputs);
if(!CheckPointer(layer) != POINTER_INVALID)
return false;
//---
if(!layer.Reserve(neurons + 1))
return false;
for(uint i = 0; i <= neurons; i++)
{
if(!layer.CreateElement(i))
return false;
layer.IncreaseTotal();
}
//---
return (Add(layer));
}
//+------------------------------------------------------------------+
///\class CNeuronProof
/// Class of pooling layer
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8234#para42">the link.</A>
//+------------------------------------------------------------------+
class CNeuronProof : public CNeuronBase
{
protected:
CLayer *OutputLayer; ///< Layer of output data. Used for connection with next layer.
int iWindow; ///< Input window size
int iStep; ///< Size of step
virtual bool feedForward(CLayer *prevLayer); ///< Feed Forward method.@param prevLayer Pointer to previos layer.
virtual bool calcHiddenGradients(CLayer *&nextLayer); ///< Method to transfer gradient to previous layer. @param nextLayer Pointer to next layer.
public:
/** Constructor */
CNeuronProof(void) {};
/** Destructor */~CNeuronProof(void);
virtual bool Init(uint numOutputs, uint myIndex, int window, int step, int units_count, ENUM_OPTIMIZATION optimization_type);
///< Method of initialization class.@param numOutputs Number of connections to next layer.@param myIndex Index of neuron in layer.@param window Size of input window @param step Step size.@param units_countNumber of neurons.@param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
//---
virtual CLayer *getOutputLayer(void) { return OutputLayer; } ///< Method for getting a pointer to the resulting neural layer. Not used in fully connected neural networks.@return Pointer to layer.
virtual bool calcInputGradients(CLayer *prevLayer); ///< Method to transfer gradients to previous layer @param[in] prevLayer Pointer to previous layer.
virtual bool calcInputGradients(CNeuronBase *prevNeuron, uint index); ///< Method to transfer gradients to neuron in previous layer @param[in] prevNeuron Pointer to neuron.@param[in] index Index of neuron in previous layer
//--- methods for working with files
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
virtual int Type(void) const { return defNeuronProof; }///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
///\class CNeuronConv
/// Class of convolution layer
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8234#para43">the link.</A>
//+------------------------------------------------------------------+
class CNeuronConv : public CNeuronProof
{
protected:
float param; //PReLU param
virtual bool feedForward(CLayer *prevLayer); ///< Feed Forward method.@param prevLayer Pointer to previos layer.
virtual bool calcHiddenGradients(CLayer *&nextLayer); ///< Method to transfer gradient to previous layer. @param nextLayer Pointer to next layer.
virtual float activationFunction(float x); ///< Method to calculate activation function.@param x Input data. @return Result of activation function.
virtual bool updateInputWeights(CLayer *&prevLayer); ///< Method for updating weights.@param prevLayer Pointer to previos layer.
public:
/** Constructor */
CNeuronConv() : param((float)0.01) { };
/** Destructor */~CNeuronConv(void) { };
//---
virtual bool calcInputGradients(CLayer *prevLayer); ///< Method to transfer gradients to previous layer @param[in] prevLayer Pointer to previous layer.
virtual bool calcInputGradients(CNeuronBase *prevNeuron, uint index);///< Method to transfer gradients to neuron in previous layer @param[in] prevNeuron Pointer to neuron.@param[in] index Index of neuron in previous layer
virtual float activationFunctionDerivative(float x); ///< Calculate derivative of activation function.@param[in] x Input data@return Derivative
virtual int Type(void) const { return defNeuronConv; }///< Identificator of class.@return Type of class
//--- methods for working with files
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBase::feedForward(CObject *&SourceObject)
{
bool result = false;
//---
if(CheckPointer(SourceObject) == POINTER_INVALID)
return result;
//---
CLayer *temp_l;
CNeuronProof *temp_n;
switch(SourceObject.Type())
{
case defLayer:
temp_l = SourceObject;
result = feedForward(temp_l);
break;
case defNeuronConv:
case defNeuronProof:
case defNeuronLSTM:
temp_n = SourceObject;
result = feedForward(temp_n.getOutputLayer());
break;
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBase::updateInputWeights(CObject *&SourceObject)
{
bool result = false;
//---
if(CheckPointer(SourceObject) == POINTER_INVALID)
return result;
//---
CLayer *temp_l;
CNeuronProof *temp_n;
switch(SourceObject.Type())
{
case defLayer:
temp_l = SourceObject;
result = updateInputWeights(temp_l);
break;
case defNeuronConv:
case defNeuronProof:
case defNeuronLSTM:
temp_n = SourceObject;
temp_l = temp_n.getOutputLayer();
result = updateInputWeights(temp_l);
break;
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConv::feedForward(CLayer *prevLayer)
{
bool result = false;
//---
if(CheckPointer(prevLayer) == POINTER_INVALID)
return result;
//---
int total = prevLayer.Total() - iWindow + 1;
CNeuron *temp;
CConnection *con;
result = true;
for(int i = 0; (i < total && result); i += iStep)
{
float sum = 0;
for(int j = 0; (j < iWindow && result); j++)
{
temp = prevLayer.At(i + j);
con = Connections.At(j);
if(CheckPointer(temp) == POINTER_INVALID || CheckPointer(con) == POINTER_INVALID)
return false;
float val = temp.getOutputVal();
sum += val * con.weight;
}
temp = OutputLayer.At(i / iStep);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
temp.setOutputVal(activationFunction(sum));
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
float CNeuronConv::activationFunction(float x)
{
if(x >= 0)
return x;
return param * x;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBase::calcHiddenGradients(CObject *&TargetObject)
{
bool result = false;
//---
if(CheckPointer(TargetObject) == POINTER_INVALID)
return result;
//---
CLayer *temp_l;
CNeuronProof *temp_n;
switch(TargetObject.Type())
{
case defLayer:
temp_l = TargetObject;
result = calcHiddenGradients(temp_l);
break;
case defNeuronConv:
case defNeuronProof:
case defNeuronLSTM:
switch(Type())
{
case defNeuron:
temp_n = TargetObject;
result = temp_n.calcInputGradients(GetPointer(this), m_myIndex);
break;
case defNeuronLSTM:
temp_n = TargetObject;
temp_l = getOutputLayer();
if(!temp_n.calcInputGradients(temp_l))
{
result = false;
break;
}
result = calcHiddenGradients(temp_l);
break;
default:
//temp_n=GetPointer(this);
temp_l =/*temp_n*/getOutputLayer();
temp_n = TargetObject;
result = temp_n.calcInputGradients(temp_l);
break;
}
break;
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConv::calcHiddenGradients(CLayer *&nextLayer)
{
if(CheckPointer(nextLayer) == POINTER_INVALID || CheckPointer(OutputLayer) == POINTER_INVALID || OutputLayer.Total() <= 0)
return false;
//---
gradient = 0;
int total = OutputLayer.Total();
CNeuron *temp;
for(int i = 0; i < total; i++)
{
temp = OutputLayer.At(i);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
temp.setGradient(temp.sumDOW(nextLayer)*activationFunctionDerivative(temp.getOutputVal()));
}
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
float CNeuronConv::activationFunctionDerivative(float x)
{
if(x >= 0)
return 1;
return param;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConv::updateInputWeights(CLayer *&prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID || CheckPointer(OutputLayer) == POINTER_INVALID)
return false;
//---
CConnection *con;
float lt = (float)(lr * sqrt(1 - pow(b2, t)) / (1 - pow(b1, t)));
for(int n = 0; n < iWindow && !IsStopped(); n++)
{
con = Connections.At(n);
if(CheckPointer(con) == POINTER_INVALID)
continue;
float delta = 0;
int total_i = OutputLayer.Total();
CNeuron *prev, *out;
for(int i = 0; i < total_i; i++)
{
prev = prevLayer.At(n * iStep + i);
out = OutputLayer.At(total_i - i - 1);
if(CheckPointer(prev) == POINTER_INVALID || CheckPointer(out) == POINTER_INVALID)
continue;
delta += prev.getOutputVal() * out.getGradient();
}
if(optimization == SGD)
con.weight += con.deltaWeight = (delta != 0 ? lr*delta : 0) + (con.deltaWeight != 0 ? alpha*con.deltaWeight : 0);
else
{
con.mt = b1 * con.mt + (1 - b1) * delta;
con.vt = (float)(b2 * con.vt + (1 - b2) * pow(delta, 2) + 0.00000001);
con.weight += con.deltaWeight = (float)(lt * con.mt / sqrt(con.vt));
t++;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProof::Init(uint numOutputs, uint myIndex, int window, int step, int units_count, ENUM_OPTIMIZATION optimization_type)
{
iWindow = window;
iStep = step;
if(!CNeuronBase::Init(window, myIndex, optimization_type))
return false;
OutputLayer = new CLayer(numOutputs);
if(CheckPointer(OutputLayer) == POINTER_INVALID)
return false;
if(OutputLayer.Reserve(units_count))
for(int i = 0; i < units_count; i++)
{
if(!OutputLayer.CreateElement(i))
return false;
OutputLayer.IncreaseTotal();
}
//---
if(Type() == defNeuronProof)
{
if(CheckPointer(Connections) != POINTER_INVALID)
Connections.Clear();
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronProof::~CNeuronProof(void)
{
if(CheckPointer(OutputLayer) != POINTER_INVALID)
delete OutputLayer;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProof::feedForward(CLayer *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
int total = prevLayer.Total() - iWindow + 1;
CNeuron *temp;
for(int i = 0; i <= total; i += iStep)
{
float sum = 0;
for(int j = 0; j < iWindow; j++)
{
temp = prevLayer.At(i + j);
if(CheckPointer(temp) == POINTER_INVALID)
continue;
sum += temp.getOutputVal();
}
temp = OutputLayer.At(i / iStep);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
temp.setOutputVal(sum / iWindow);
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProof::calcHiddenGradients(CLayer *&nextLayer)
{
if(CheckPointer(nextLayer) == POINTER_INVALID || CheckPointer(OutputLayer) == POINTER_INVALID || OutputLayer.Total() <= 0)
return false;
//---
gradient = 0;
int total = OutputLayer.Total();
CNeuron *temp;
for(int i = 0; i < total; i++)
{
temp = OutputLayer.At(i);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
temp.setGradient(temp.sumDOW(nextLayer));
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProof::calcInputGradients(CLayer *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID || CheckPointer(OutputLayer) == POINTER_INVALID || CheckPointer(prevLayer.At(0)) == POINTER_INVALID)
return false;
//---
if(prevLayer.At(0).Type() != defNeuron)
{
CNeuronProof *temp = prevLayer.At(m_myIndex);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
prevLayer = temp.getOutputLayer();
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
}
//---
CNeuronBase *prevNeuron, *outputNeuron;
int total = prevLayer.Total();
for(int i = 0; i < total; i++)
{
prevNeuron = prevLayer.At(i);
if(CheckPointer(prevNeuron) == POINTER_INVALID)
continue;
float prev_gradient = 0;
int start = i - iWindow + iStep;
start = (start - start % iStep) / iStep;
float stop = (float)((i - i % iStep) / iStep + 1);
for(int out = (int)fmax(0, start); out < (int)fmin(OutputLayer.Total(), stop); out++)
{
outputNeuron = OutputLayer.At(out);
if(CheckPointer(outputNeuron) == POINTER_INVALID)
continue;
prev_gradient += outputNeuron.getGradient() / iWindow;
}
prevNeuron.setGradient(prev_gradient);
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProof::calcInputGradients(CNeuronBase *prevNeuron, uint index)
{
if(CheckPointer(prevNeuron) == POINTER_INVALID || CheckPointer(OutputLayer) == POINTER_INVALID)
return false;
//---
if(prevNeuron.Type() != defNeuron)
{
CNeuronProof *temp = prevNeuron;
return calcInputGradients(temp.getOutputLayer());
}
//---
CNeuronBase *outputNeuron;
float prev_gradient = 0;
int start = (int)index - iWindow + iStep;
start = (start - start % iStep) / iStep;
float stop = (float)((index - index % iStep) / iStep + 1);
for(int out = (int)fmax(0, start); out < (int)fmin(OutputLayer.Total(), stop); out++)
{
outputNeuron = OutputLayer.At(out);
if(CheckPointer(outputNeuron) == POINTER_INVALID)
continue;
prev_gradient += outputNeuron.getGradient() / iWindow;
}
prevNeuron.setGradient(prev_gradient);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConv::calcInputGradients(CLayer *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID || CheckPointer(OutputLayer) == POINTER_INVALID)
return false;
//---
if(prevLayer.At(0).Type() != defNeuron)
{
CNeuronProof *temp = prevLayer.At(m_myIndex);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
prevLayer = temp.getOutputLayer();
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
}
//---
CNeuronBase *prevNeuron, *outputNeuron;
CConnection *con;
int total = prevLayer.Total();
for(int i = 0; i < total; i++)
{
prevNeuron = prevLayer.At(i);
if(CheckPointer(prevNeuron) == POINTER_INVALID)
continue;
float prev_gradient = 0;
int start = i - iWindow + iStep;
start = (start - start % iStep) / iStep;
float stop = (float)((i - i % iStep) / iStep + 1);
for(int out = (int)fmax(0, start); out < (int)fmin(OutputLayer.Total(), stop); out++)
{
outputNeuron = OutputLayer.At(out);
int c = ((int)fmin(OutputLayer.Total(), stop) - out - 1) * iStep + i % iStep;
con = Connections.At(c);
if(CheckPointer(outputNeuron) == POINTER_INVALID || CheckPointer(con) == POINTER_INVALID)
continue;
prev_gradient += outputNeuron.getGradient() * prevNeuron.activationFunctionDerivative(prevNeuron.getOutputVal()) * con.weight;
}
prevNeuron.setGradient(prev_gradient);
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConv::calcInputGradients(CNeuronBase *prevNeuron, uint index)
{
if(CheckPointer(prevNeuron) == POINTER_INVALID || CheckPointer(OutputLayer) == POINTER_INVALID)
return false;
//---
if(prevNeuron.Type() != defNeuron)
{
CNeuronProof *temp = prevNeuron;
return calcInputGradients(temp.getOutputLayer());
}
//---
CNeuronBase *outputNeuron;
CConnection *con;
float prev_gradient = 0;
int start = (int)index - iWindow + iStep;
start = (start - start % iStep) / iStep;
float stop = (float)((index - index % iStep) / iStep + 1);
for(int out = (int)fmax(0, start); out < (int)fmin(OutputLayer.Total(), stop); out++)
{
outputNeuron = OutputLayer.At(out);
int c = (int)(((int)fmin(OutputLayer.Total(), stop) - out - 1) * iStep + index % iStep);
con = Connections.At(c);
if(CheckPointer(outputNeuron) == POINTER_INVALID || CheckPointer(con) == POINTER_INVALID)
continue;
prev_gradient += outputNeuron.getGradient() * activationFunctionDerivative(outputNeuron.getOutputVal()) * con.weight;
}
prevNeuron.setGradient(prev_gradient);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBase::Save(int file_handle)
{
if(file_handle == INVALID_HANDLE)
return false;
if(FileWriteInteger(file_handle, Type()) < INT_VALUE)
return false;
//---
if(FileWriteInteger(file_handle, (int)activation, INT_VALUE) < INT_VALUE)
return false;
//---
if(FileWriteInteger(file_handle, (int)optimization, INT_VALUE) < INT_VALUE)
return false;
//---
if(FileWriteInteger(file_handle, t, INT_VALUE) < INT_VALUE)
return false;
//---
return Connections.Save(file_handle);
}
//+------------------------------------------------------------------+
///\class CLayerDescription
/// Class of layer decription. Used to describe the structure of a neural network from the main program.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8234#para44">the link.</A>
//+------------------------------------------------------------------+
class CLayerDescription : public CObject
{
public:
/** Constructor */
CLayerDescription(void);
/** Destructor */~CLayerDescription(void) {};
//---
int type; ///< Type of neurons in layer (\ref ObjectTypes)
int count; ///< Number of neurons
int window; ///< Size of input window
int window_out; ///< Size of output window
int step; ///< Step size
int layers; ///< Layers count
int batch; ///< Batch Size
ENUM_ACTIVATION activation; ///< Type of activation function (#ENUM_ACTIVATION)
ENUM_OPTIMIZATION optimization; ///< Type of optimization method (#ENUM_OPTIMIZATION)
float probability; ///< Probability of neurons shutdown, only Dropout used
int windows[];
int units[];
//---
virtual bool Copy(CLayerDescription *source);
//---
virtual bool operator= (CLayerDescription *source) { return Copy(source); }
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription::CLayerDescription(void) : type(defNeuron),
count(0),
window(1),
step(1),
layers(1),
activation(TANH),
optimization(ADAM),
probability((float)0.1),
batch(100)
{}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CLayerDescription::Copy(CLayerDescription *source)
{
if(!source)
return false;
//---
type = source.type;
count = source.count;
window = source.window;
window_out = source.window_out;
step = source.step;
layers = source.layers;
batch = source.batch;
activation = source.activation;
optimization = source.optimization;
probability = source.probability;
ArrayCopy(windows, source.windows);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CBufferFloat;
//+------------------------------------------------------------------+
///\class CNet
/// The main class of the neural network. Contains basic methods for the functioning of a neural network.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/7447#para53">the link.</A>
//+------------------------------------------------------------------+
class CNet : public CObject
{
protected:
bool backPropOCL(CBufferFloat *targetVals, CBufferFloat *SecondInput = NULL, CBufferFloat *SecondGradient = NULL, bool layer_by_layer = false, ENUM_ACTIVATION SecondActivation = None); ///< Back propagation method for GPU calculation. @param[in] targetVals Target values
int backPropCount;
float recentAverageError; ///< Average error
CArrayLayer *layers; ///< Array of layers
COpenCLMy *opencl; ///< Class for working with OpenCL
public:
/** Constructor */
CNet(void) { Create(NULL); }
CNet(CArrayObj *Description) { Create(Description); }
bool Create(CArrayObj *Description);
/** Destructor */ ~CNet(void);
bool feedForward(CArrayFloat *inputVals, int window = 1, bool tem = true, CBufferFloat *SecondInput = NULL); ///< Feed Forward method.@param[in] prevLayer Pointer to previos layer. @param[in] window Window of input data. @param[in] tem Use Time Embedding.
bool feedForward(CNet *inputNet, int inputLayer = -1, CBufferFloat *SecondInput = NULL);
bool feedForward(CNet *inputNet, int inputLayer = -1, CNet *secondNet = NULL, int secondLayer = -1);
bool feedForward(CArrayFloat *inputVals, int window = 1, bool tem = true, CNet *secondNet = NULL, int secondLayer = -1);
bool backProp(CArrayFloat *targetVals, CBufferFloat *SecondInput = NULL, CBufferFloat *SecondGradient = NULL); ///< Back propagation method. @param[in] targetVals Target values
bool backProp(CArrayFloat *targetVals, CNet *secondNet = NULL, int secondLayer = -1); ///< Back propagation method. @param[in] targetVals Target values
bool backPropGradient(CBufferFloat *SecondInput = NULL, CBufferFloat *SecondGradient = NULL, int LastLayer = -1, bool load_weights = true); ///< Back propagation method for GPU calculation. @param[in] targetVals Target values
bool backPropGradient(CNet *secondNet, int secondLayer = -1, int LastLayer = -1, bool load_weights = true);
void getResults(CBufferFloat *&resultVals); ///< Method to get results of feed forward process.@param[out] resultVals Array of result values
void getResults(vector<float> &resultVals); ///< Method to get results of feed forward process.@param[out] resultVals Array of result values
void getResults(float &resultVals[]); ///< Method to get results of feed forward process.@param[out] resultVals Array of result values
float getRecentAverageError() { return recentAverageError; } ///< Method to check quality of study. @return Average error
bool Save(string file_name, float error, float undefine, float forecast, datetime time, bool common = true);
///< Save method. @param[in] file_name File name to save @param[in] error Average error @param[in] undefine Undefined percent @param[in] Foecast percent @param[in] time Last study time @param[in] common Common flag
virtual bool Save(const int file_handle);
bool Load(string file_name, float &error, float &undefine, float &forecast, datetime &time, bool common = true);
///< Load method. @param[in] file_name File name to save @param[out] error Average error @param[out] undefine Undefined percent @param[out] Foecast percent @param[out] time Last study time @param[in] common Common flag
virtual bool Load(const int file_handle);
//---
static float recentAverageSmoothingFactor; ///< Smoothing factor of average error
virtual int Type(void) const { return defNet; }///< Identificator of class.@return Type of class
virtual bool TrainMode(bool flag); ///< Set Training Mode Flag
virtual bool GetLayerOutput(uint layer, CBufferFloat *&result); ///< Retutn Output data of layer. @param[in] layer Number of layer @param[out] return Buffer with data
virtual bool GetLayerOutput(uint layer, vector<float> &result); ///< Retutn Output data of layer. @param[in] layer Number of layer @param[out] return Buffer with data
//---
virtual void SetOpenCL(COpenCLMy *obj);
virtual COpenCLMy* GetOpenCL(void) { return opencl; }
//---
virtual bool WeightsUpdate(CNet *net, float tau);
//--- Soft Actor-Critic
virtual bool GetLogProbs(vector<float> &log_probs);
virtual bool AlphasGradient(CNet *PolicyNet);
virtual bool CalcLogProbs(CBufferFloat *buffer);
virtual bool SetResult(float &result[]);
virtual bool Clear(void);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
float CNet::recentAverageSmoothingFactor = 10000.0; // Number of training samples to average over
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::Create(CArrayObj *Description)
{
recentAverageError = 0;
backPropCount = 0;
if(!Description)
return false;
//---
int total = Description.Total();
if(total <= 0)
return false;
//---
if(!layers)
layers = new CArrayLayer();
if(!layers)
return false;
layers.FreeMode(true);
layers.Clear();
//---
CLayer *temp;
CLayerDescription *desc = NULL, *next = NULL, *prev = NULL;
CNeuronBase *neuron = NULL;
CNeuronProof *neuron_p = NULL;
int output_count = 0;
int temp_count = 0;
//---
next = Description.At(1);
if(next.type == defNeuron || next.type >= defNeuronBaseOCL)
{
opencl = new COpenCLMy();
if(!!opencl && !opencl.Initialize(cl_program, true))
delete opencl;
}
else
{
if(!!opencl)
delete opencl;
}
//---
for(int i = 0; i < total; i++)
{
prev = desc;
desc = Description.At(i);
if((i + 1) < total)
{
next = Description.At(i + 1);
if(!next)
return false;
}
else
next = NULL;
int outputs = (next == NULL || (next.type != defNeuron && next.type != defNeuronBaseOCL) ? 0 : next.count);
if(!!next && (next.type == defNeuronFQF || next.type == defNeuronSoftActorCritic))
outputs = next.count * next.window_out;
temp = new CLayer(outputs);
int neurons = (desc.count + (desc.type == defNeuron || desc.type == defNeuronBaseOCL ? 1 : 0));
if(!!opencl)
{
CNeuronBaseOCL *neuron_ocl = NULL;
CNeuronConvOCL *neuron_conv_ocl = NULL;
CNeuronProofOCL *neuron_proof_ocl = NULL;
CNeuronAttentionOCL *neuron_attention_ocl = NULL;
CNeuronMLMHAttentionOCL *neuron_mlattention_ocl = NULL;
CNeuronMLMHSparseAttention *neuron_sparseattention = NULL;
CNeuronMH2AttentionOCL *neuron_mh2attention_ocl = NULL;
CNeuronDropoutOCL *dropout = NULL;
CNeuronBatchNormOCL *batch = NULL;
CVAE *vae = NULL;
CNeuronLSTMOCL *lstm = NULL;
CNeuronSoftMaxOCL *softmax = NULL;
CNeuronFQF *fqf = NULL;
CNeuronMultiModel *multi_model = NULL;
CNeuronConcatenate *concat = NULL;
CNeuronEmbeddingOCL *emb = NULL;
CNeuronPositionEncoder *pe = NULL;
CNeuronTransposeOCL *tr = NULL;
CNeuronCGConvOCL *cgc = NULL;
CNeuronXCiTOCL *xcit = NULL;
CNeuronDOTOCL *dot = NULL;
CNeuronFAQOCL *faq = NULL;
CNeuronCrossAttention *cross = NULL;
switch(desc.type)
{
case defNeuron:
case defNeuronBase:
case defNeuronBaseOCL:
neuron_ocl = new CNeuronBaseOCL();
if(CheckPointer(neuron_ocl) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!neuron_ocl.Init(outputs, 0, opencl, desc.count, desc.optimization, desc.batch))
{
delete neuron_ocl;
delete temp;
return false;
}
neuron_ocl.SetActivationFunction(desc.activation);
if(!temp.Add(neuron_ocl))
{
delete neuron_ocl;
delete temp;
return false;
}
neuron_ocl = NULL;
break;
//---
case defNeuronConvOCL:
neuron_conv_ocl = new CNeuronConvOCL();
if(CheckPointer(neuron_conv_ocl) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!neuron_conv_ocl.Init(outputs, 0, opencl, desc.window, desc.step, desc.window_out, desc.count, desc.optimization, desc.batch))
{
delete neuron_conv_ocl;
delete temp;
return false;
}
neuron_conv_ocl.SetActivationFunction(desc.activation);
if(!temp.Add(neuron_conv_ocl))
{
delete neuron_conv_ocl;
delete temp;
return false;
}
neuron_conv_ocl = NULL;
break;
//---
case defNeuronProofOCL:
neuron_proof_ocl = new CNeuronProofOCL();
if(!neuron_proof_ocl)
{
delete temp;
return false;
}
if(!neuron_proof_ocl.Init(outputs, 0, opencl, desc.window, desc.step, desc.count, desc.optimization, desc.batch))
{
delete neuron_proof_ocl;
delete temp;
return false;
}
neuron_proof_ocl.SetActivationFunction(desc.activation);
if(!temp.Add(neuron_proof_ocl))
{
delete neuron_proof_ocl;
delete temp;
return false;
}
neuron_proof_ocl = NULL;
break;
//---
case defNeuronAttentionOCL:
neuron_attention_ocl = new CNeuronAttentionOCL();
if(CheckPointer(neuron_attention_ocl) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!neuron_attention_ocl.Init(outputs, 0, opencl, desc.window, desc.count, desc.optimization, desc.batch))
{
delete neuron_attention_ocl;
delete temp;
return false;
}
neuron_attention_ocl.SetActivationFunction(desc.activation);
if(!temp.Add(neuron_attention_ocl))
{
delete neuron_attention_ocl;
delete temp;
return false;
}
neuron_attention_ocl = NULL;
break;
//---
case defNeuronMHAttentionOCL:
neuron_attention_ocl = new CNeuronMHAttentionOCL();
if(CheckPointer(neuron_attention_ocl) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!neuron_attention_ocl.Init(outputs, 0, opencl, desc.window, desc.count, desc.optimization, desc.batch))
{
delete neuron_attention_ocl;
delete temp;
return false;
}
neuron_attention_ocl.SetActivationFunction(desc.activation);
if(!temp.Add(neuron_attention_ocl))
{
delete neuron_attention_ocl;
delete temp;
return false;
}
neuron_attention_ocl = NULL;
break;
//---
case defNeuronMLMHAttentionOCL:
neuron_mlattention_ocl = new CNeuronMLMHAttentionOCL();
if(CheckPointer(neuron_mlattention_ocl) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!neuron_mlattention_ocl.Init(outputs, 0, opencl, desc.window, desc.window_out, desc.step, desc.count, desc.layers, desc.optimization, desc.batch))
{
delete neuron_mlattention_ocl;
delete temp;
return false;
}
neuron_mlattention_ocl.SetActivationFunction(desc.activation);
if(!temp.Add(neuron_mlattention_ocl))
{
delete neuron_mlattention_ocl;
delete temp;
return false;
}
neuron_mlattention_ocl = NULL;
break;
//---
case defNeuronMLMHSparseAttentionOCL:
neuron_sparseattention = new CNeuronMLMHSparseAttention();
if(CheckPointer(neuron_sparseattention) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!neuron_sparseattention.Init(outputs, 0, opencl, desc.window, desc.window_out, desc.step, desc.count, desc.layers, desc.optimization, desc.batch))
{
delete neuron_sparseattention;
delete temp;
return false;
}
neuron_sparseattention.SetActivationFunction(desc.activation);
neuron_sparseattention.Sparse(desc.probability);
if(!temp.Add(neuron_sparseattention))
{
delete neuron_mlattention_ocl;
delete temp;
return false;
}
neuron_sparseattention = NULL;
break;
//---
case defNeuronMFTOCL:
neuron_mlattention_ocl = new CNeuronMFTOCL();
if(CheckPointer(neuron_mlattention_ocl) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!neuron_mlattention_ocl.Init(outputs, 0, opencl, desc.window, desc.window_out, desc.step, desc.count, desc.layers, desc.optimization, desc.batch))
{
delete neuron_mlattention_ocl;
delete temp;
return false;
}
neuron_mlattention_ocl.SetActivationFunction(desc.activation);
if(!temp.Add(neuron_mlattention_ocl))
{
delete neuron_mlattention_ocl;
delete temp;
return false;
}
neuron_mlattention_ocl = NULL;
break;
case defNeuronMH2AttentionOCL:
neuron_mh2attention_ocl = new CNeuronMH2AttentionOCL();
if(CheckPointer(neuron_mh2attention_ocl) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!neuron_mh2attention_ocl.Init(outputs, 0, opencl, desc.window, desc.window_out, desc.step, desc.count, desc.optimization, desc.batch))
{
delete neuron_mh2attention_ocl;
delete temp;
return false;
}
neuron_mh2attention_ocl.SetActivationFunction(None);
if(!temp.Add(neuron_mh2attention_ocl))
{
delete neuron_mh2attention_ocl;
delete temp;
return false;
}
neuron_mh2attention_ocl = NULL;
break;
//---
case defNeuronXCiTOCL:
xcit = new CNeuronXCiTOCL();
if(CheckPointer(xcit) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!xcit.Init(outputs, 0, opencl, desc.window, desc.window_out, desc.step, desc.count, desc.layers, desc.optimization, desc.batch))
{
delete xcit;
delete temp;
return false;
}
if(!temp.Add(xcit))
{
delete xcit;
delete temp;
return false;
}
xcit = NULL;
break;
//---
case defNeuronDropoutOCL:
dropout = new CNeuronDropoutOCL();
if(CheckPointer(dropout) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!dropout.Init(outputs, 0, opencl, desc.count, desc.probability, desc.optimization, desc.batch))
{
delete dropout;
delete temp;
return false;
}
if(!temp.Add(dropout))
{
delete dropout;
delete temp;
return false;
}
dropout = NULL;
break;
//---
case defNeuronBatchNormOCL:
batch = new CNeuronBatchNormOCL();
if(CheckPointer(batch) == POINTER_INVALID)
{
delete temp;
return false;
}
if(!batch.Init(outputs, 0, opencl, desc.count, desc.batch, desc.optimization))
{
delete batch;
delete temp;
return false;
}
batch.SetActivationFunction(desc.activation);
if(!temp.Add(batch))
{
delete batch;
delete temp;
return false;
}
batch = NULL;
break;
//---
case defNeuronVAEOCL:
vae = new CVAE();
if(!vae)
{
delete temp;
return false;
}
if(!vae.Init(outputs, 0, opencl, desc.count, desc.optimization, desc.batch))
{
delete vae;
delete temp;
return false;
}
if(!temp.Add(vae))
{
delete vae;
delete temp;
return false;
}
vae = NULL;
break;
case defNeuronLSTMOCL:
lstm = new CNeuronLSTMOCL();
if(!lstm)
{
delete temp;
return false;
}
if(!lstm.Init(outputs, 0, opencl, desc.count, desc.optimization, desc.batch))
{
delete lstm;
delete temp;
return false;
}
if(!!prev)
if(!lstm.SetInputs(prev.count))
{
delete lstm;
delete temp;
return false;
}
if(!temp.Add(lstm))
{
delete lstm;
delete temp;
return false;
}
lstm = NULL;
break;
//---
case defNeuronSoftMaxOCL:
softmax = new CNeuronSoftMaxOCL();
if(!softmax)
{
delete temp;
return false;
}
if(!softmax.Init(outputs, 0, opencl, desc.count * desc.step, desc.optimization, desc.batch))
{
delete softmax;
delete temp;
return false;
}
softmax.SetHeads(desc.step);
if(!temp.Add(softmax))
{
delete softmax;
delete temp;
return false;
}
softmax = NULL;
break;
//---
case defNeuronFQF:
fqf = new CNeuronFQF();
if(!fqf)
{
delete temp;
return false;
}
if(!fqf.Init(outputs, 0, opencl, desc.count, desc.window_out, prev.count * (prev.type == defNeuronConv ? prev.window_out : 1), desc.optimization, desc.batch))
{
delete fqf;
delete temp;
return false;
}
if(!temp.Add(fqf.AsObject()))
{
delete fqf;
delete temp;
return false;
}
fqf = NULL;
break;
case defNeuronMultiModels:
multi_model = new CNeuronMultiModel();
if(!multi_model)
{
delete temp;
return false;
}
if(!multi_model.Init(desc.window, 0, opencl, desc.count, ADAM, desc.step))
{
delete multi_model;
delete temp;
return false;
}
multi_model.SetActivationFunction(desc.activation);
if(!temp.Add(multi_model))
{
delete multi_model;
delete temp;
return false;
}
multi_model = NULL;
break;
case defNeuronConcatenate:
concat = new CNeuronConcatenate();
if(!concat)
{
delete temp;
return false;
}
if(!concat.Init(outputs, 0, opencl, desc.count, desc.window, desc.step, ADAM, desc.batch))
{
delete concat;
delete temp;
return false;
}
concat.SetActivationFunction(desc.activation);
if(!temp.Add(concat))
{
delete concat;
delete temp;
return false;
}
concat = NULL;
break;
//---
case defNeuronSoftActorCritic:
fqf = new CNeuronSoftActorCritic();
if(!fqf)
{
delete temp;
return false;
}
if(!fqf.Init(outputs, 0, opencl, desc.count, desc.window_out, prev.count * (prev.type == defNeuronConv ? prev.window_out : 1), desc.optimization, desc.batch))
{
delete fqf;
delete temp;
return false;
}
fqf.SetActivationFunction(desc.activation);
if(!temp.Add(fqf.AsObject()))
{
delete fqf;
delete temp;
return false;
}
fqf = NULL;
break;
//---
case defNeuronEmbeddingOCL:
emb = new CNeuronEmbeddingOCL();
if(!emb)
{
delete temp;
return false;
}
if(!emb.Init(outputs, 0, opencl, desc.count, desc.window_out, desc.windows))
{
delete temp;
delete emb;
return false;
}
if(!temp.Add(emb))
{
delete temp;
delete emb;
return false;
}
break;
//---
case defNeuronPEOCL:
pe = new CNeuronPositionEncoder();
if(!pe)
{
delete temp;
return false;
}
if(!pe.Init(outputs, 0, opencl, desc.count, desc.window, desc.optimization, desc.batch))
{
delete temp;
delete pe;
return false;
}
if(!temp.Add(pe))
{
delete temp;
delete pe;
return false;
}
break;
//---
case defNeuronTransposeOCL:
tr = new CNeuronTransposeOCL();
if(!tr)
{
delete temp;
return false;
}
if(!tr.Init(outputs, 0, opencl, desc.count, desc.window, desc.optimization, desc.batch))
{
delete temp;
delete tr;
return false;
}
if(!temp.Add(tr))
{
delete temp;
delete tr;
return false;
}
break;
case defNeuronCGConvOCL:
cgc = new CNeuronCGConvOCL();
if(!cgc)
{
delete temp;
return false;
}
if(!cgc.Init(outputs, 0, opencl, desc.window, desc.count, desc.optimization, desc.batch))
{
delete temp;
delete cgc;
return false;
}
if(!temp.Add(cgc))
{
delete temp;
delete cgc;
return false;
}
break;
//---
case defNeuronDOTOCL:
dot = new CNeuronDOTOCL();
if(!dot)
{
delete temp;
return false;
}
neurons = prev.count * MathMax((prev.type == defNeuronConv ? prev.window_out : prev.window), 1) / desc.count;
if(!dot.Init(outputs, 0, opencl, desc.window, desc.window_out, desc.step, desc.count, neurons, desc.optimization, desc.batch))
{
delete temp;
delete dot;
return false;
}
if(!temp.Add(dot))
{
delete temp;
delete dot;
return false;
}
break;
//---
case defNeuronFAQOCL:
faq = new CNeuronFAQOCL();
if(!faq)
{
delete temp;
return false;
}
if(!faq.Init(outputs, 0, opencl, desc.window, desc.window_out, desc.step, desc.units[0], desc.units[1], desc.optimization, desc.batch))
{
delete temp;
delete faq;
return false;
}
if(!temp.Add(faq))
{
delete temp;
delete faq;
return false;
}
break;
//---
case defNeuronCrossAttenOCL:
cross = new CNeuronCrossAttention();
if(!cross)
{
delete temp;
return false;
}
if(!cross.Init(outputs, 0, opencl, desc.windows[0], desc.window_out, desc.step, desc.units[0], desc.windows[1], desc.units[1], desc.optimization, desc.batch))
{
delete temp;
delete cross;
return false;
}
if(!temp.Add(cross))
{
delete temp;
delete cross;
return false;
}
break;
//---
default:
return false;
break;
}
}
else
for(int n = 0; n < neurons; n++)
{
switch(desc.type)
{
case defNeuron:
neuron = new CNeuron();
if(CheckPointer(neuron) == POINTER_INVALID)
{
delete temp;
delete layers;
return false;
}
neuron.Init(outputs, n, desc.optimization);
neuron.SetActivationFunction(desc.activation);
break;
case defNeuronConv:
neuron_p = new CNeuronConv();
if(CheckPointer(neuron_p) == POINTER_INVALID)
{
delete temp;
delete layers;
return false;
}
if(CheckPointer(prev) != POINTER_INVALID)
{
if(prev.type == defNeuron)
{
temp_count = (int)((prev.count - desc.window) % desc.step);
output_count = (int)((prev.count - desc.window - temp_count) / desc.step + (temp_count == 0 ? 1 : 2));
}
else
if(n == 0)
{
temp_count = (int)((output_count - desc.window) % desc.step);
output_count = (int)((output_count - desc.window - temp_count) / desc.step + (temp_count == 0 ? 1 : 2));
}
}
if(neuron_p.Init(outputs, n, desc.window, desc.step, output_count, desc.optimization))
neuron = neuron_p;
break;
case defNeuronProof:
neuron_p = new CNeuronProof();
if(CheckPointer(neuron_p) == POINTER_INVALID)
{
delete temp;
delete layers;
return false;
}
if(CheckPointer(prev) != POINTER_INVALID)
{
if(prev.type == defNeuron)
{
temp_count = (int)((prev.count - desc.window) % desc.step);
output_count = (int)((prev.count - desc.window - temp_count) / desc.step + (temp_count == 0 ? 1 : 2));
}
else
if(n == 0)
{
temp_count = (int)((output_count - desc.window) % desc.step);
output_count = (int)((output_count - desc.window - temp_count) / desc.step + (temp_count == 0 ? 1 : 2));
}
}
if(neuron_p.Init(outputs, n, desc.window, desc.step, output_count, desc.optimization))
neuron = neuron_p;
break;
case defNeuronLSTM:
neuron_p = new CNeuronLSTM();
if(CheckPointer(neuron_p) == POINTER_INVALID)
{
delete temp;
delete layers;
return false;
}
output_count = (next != NULL ? next.window : desc.step);
if(neuron_p.Init(outputs, n, desc.window, 1, output_count, desc.optimization))
neuron = neuron_p;
break;
}
if(!temp.Add(neuron))
{
delete temp;
delete layers;
return false;
}
neuron = NULL;
}
if(!layers.Add(temp))
{
delete temp;
delete layers;
return false;
}
}
//---
if(CheckPointer(opencl) == POINTER_INVALID)
return false;
//--- create kernels
opencl.SetKernelsCount(71);
if(!opencl.KernelCreate(def_k_FeedForward, "FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcOutputGradient, "CalcOutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcHiddenGradient, "CalcHiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsMomentum, "UpdateWeightsMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsAdam, "UpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsLS, "UpdateWeightsLS"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_AttentionGradients, "AttentionInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_AttentionOut, "AttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_AttentionScore, "AttentionScore"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcHiddenGradientConv, "CalcHiddenGradientConv"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcInputGradientProof, "CalcInputGradientProof"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FeedForwardConv, "FeedForwardConv"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FeedForwardProof, "FeedForwardProof"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MatrixSum, "SumMatrix"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Matrix5Sum, "Sum5Matrix"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsConvAdam, "UpdateWeightsConvAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsConvLS, "UpdateWeightsConvLS"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsConvMomentum, "UpdateWeightsConvMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Normilize, "Normalize"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_NormilizeWeights, "NormalizeWeights"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatenateMatrix, "ConcatenateBuffers"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_DeconcatenateMatrix, "DeconcatenateBuffers"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHAttentionGradients, "MHAttentionInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHAttentionScore, "MHAttentionScore"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHAttentionOut, "MHAttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_BatchFeedForward, "BatchFeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcHiddenGradientBatch, "CalcHiddenGradientBatch"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateBatchOptionsMomentum, "UpdateBatchOptionsMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateBatchOptionsAdam, "UpdateBatchOptionsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_VAEFeedForward, "VAE_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_VAECalcHiddenGradient, "VAE_CalcHiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_UpdateWeightsAdam, "LSTM_UpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_HiddenGradient, "LSTM_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_FeedForward, "LSTM_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_ConcatenatedGradient, "LSTM_ConcatenatedGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftMax_FeedForward, "SoftMax_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftMax_HiddenGradient, "SoftMax_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftMax_OutputGradient, "SoftMax_OutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Dropout, "Dropout"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_Cosine, "FQF_Cosine"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_Output, "FQF_Output"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_OutputGradient, "FQF_OutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_QuantileGradient, "FQF_QuantileGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_CosineGradient, "FQF_CosineGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHSparseAttentionScore, "MHSparseAttentionScore"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHSparseAttentionOut, "MHSparseAttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FFMultiModels, "FeedForwardMultiModels"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_HGMultiModels, "CalcHiddenGradientMultiModels"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UWMultiModels, "UpdateWeightsAdamMultiModels"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatFeedForward, "Concat_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatCalcHiddenGradient, "Concat_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatUpdWeightsMomentum, "Concat_UpdateWeightsMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatUpdWeightsAdam, "Concat_UpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftUpdate, "SoftUpdate"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftUpdateAdam, "SoftUpdateAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_AlphaLogProbs, "SAC_AlphaLogProbs"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_AlphaGradients, "SAC_AlphaGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_OutputGradient, "SAC_OutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_CalcLogProbs, "SAC_CalcLogProbs"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Embedding, "Embedding"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_EmbeddingHiddenGradient, "EmbeddingHiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_EmbeddingUpdateWeightsAdam, "EmbeddingUpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Transpose, "Transpose"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MH2AttentionOut, "MH2AttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MH2AttentionInsideGradients, "MH2AttentionInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CGConv_HiddenGradient, "CGConv_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_XCiTFeedForward, "XCiTFeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_XCiTInsideGradients, "XCiTInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_DOTFeedForward, "DOTFeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_DOTInsideGradients, "DOTInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_RPBUpdateAdam, "RPBUpdateAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::feedForward(CArrayFloat *inputVals, int window = 1, bool tem = true, CBufferFloat *SecondInput = NULL)
{
if(CheckPointer(layers) == POINTER_INVALID || CheckPointer(inputVals) == POINTER_INVALID || layers.Total() <= 1)
return false;
//---
CLayer *previous = NULL;
CLayer *current = layers.At(0);
int total = MathMin(current.Total(), inputVals.Total());
CNeuronBase *neuron = NULL;
if(CheckPointer(opencl) == POINTER_INVALID)
{
for(int i = 0; i < total; i++)
{
neuron = current.At(i);
if(CheckPointer(neuron) == POINTER_INVALID)
return false;
int pos = i;
int d = 0;
if(window > 1)
{
d = i % window;
pos = (i - d) / window;
}
neuron.setOutputVal(inputVals.At(i) + (float)(tem ? (d % 2 == 0 ? sin(pos / pow(10000, (2 * d + 1) / (window + 1))) : cos(pos / pow(10000, (2 * d + 1) / (window + 1)))) : 0));
if(tem)
inputVals.Update(i, neuron.getOutputVal());
}
}
else
{
CNeuronBaseOCL *neuron_ocl = current.At(0);
CBufferFloat *inputs = neuron_ocl.getOutput();
if(tem)
{
int total_data = inputVals.Total();
for(int d = 0; d < total_data; d++)
{
int pos = d;
int dim = 0;
if(window > 1)
{
dim = d % window;
pos = (d - dim) / window;
}
float value = pos / pow(10000, (2 * dim + 1) / (float)(window + 1));
value = (float)(inputVals.At(d) + (dim % 2 == 0 ? sin(value) : cos(value)));
if(!inputVals.Update(d, value))
return false;
}
}
if(!inputs.AssignArray(inputVals) || !inputs.BufferWrite())
return false;
}
//---
CObject *temp = NULL;
//vector<float> res;
for(int l = 1; l < layers.Total(); l++)
{
previous = current;
current = layers.At(l);
if(CheckPointer(current) == POINTER_INVALID)
return false;
//---
if(CheckPointer(opencl) != POINTER_INVALID)
{
CNeuronBaseOCL *current_ocl = current.At(0);
if(!current_ocl.FeedForward(previous.At(0), SecondInput))
return false;
//current_ocl.getOutputVal(res);
continue;
}
//---
total = current.Total();
if(current.At(0).Type() == defNeuron)
total--;
//---
for(int n = 0; n < total; n++)
{
neuron = current.At(n);
if(CheckPointer(neuron) == POINTER_INVALID)
return false;
if(previous.At(0).Type() == defNeuron)
{
temp = previous;
if(!neuron.feedForward(temp))
return false;
continue;
}
if(neuron.Type() == defNeuron)
{
if(n == 0)
{
CLayer *temp_l = new CLayer(total);
if(CheckPointer(temp_l) == POINTER_INVALID)
return false;
CNeuronProof *proof = NULL;
for(int p = 0; p < previous.Total(); p++)
{
proof = previous.At(p);
if(CheckPointer(proof) == POINTER_INVALID)
return false;
temp_l.AddArray(proof.getOutputLayer());
}
temp = temp_l;
}
if(!neuron.feedForward(temp))
return false;
if(n == total - 1)
{
CLayer *temp_l = temp;
temp_l.FreeMode(false);
temp_l.Shutdown();
delete temp_l;
}
continue;
}
temp = previous.At(n);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!neuron.feedForward(temp))
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::backProp(CArrayFloat *targetVals, CBufferFloat *SecondInput = NULL, CBufferFloat *SecondGradient = NULL)
{
if(CheckPointer(targetVals) == POINTER_INVALID || CheckPointer(layers) == POINTER_INVALID)
return false;
if(CheckPointer(opencl) != POINTER_INVALID)
{
if(!backPropOCL(targetVals, SecondInput, SecondGradient, false))
return false;
return true;
}
//---
CLayer *outputLayer = layers.At(layers.Total() - 1);
if(CheckPointer(outputLayer) == POINTER_INVALID)
return false;
//---
float error = 0.0;
int total = outputLayer.Total() - 1;
for(int n = 0; n < total && !IsStopped(); n++)
{
CNeuron *neuron = outputLayer.At(n);
float target = targetVals.At(n);
float delta = (target > 1 ? 1 : target < -1 ? -1 : target) - neuron.getOutputVal();
error += delta * delta;
neuron.calcOutputGradients(targetVals.At(n));
}
error /= (float)total;
error = (float)sqrt(error);
backPropCount++;
recentAverageError += (error - recentAverageError) / fmin(recentAverageSmoothingFactor, backPropCount);
//---
CNeuronBase *neuron = NULL;
CObject *temp = NULL;
for(int layerNum = layers.Total() - 2; layerNum > 0; layerNum--)
{
CLayer *hiddenLayer = layers.At(layerNum);
CLayer *nextLayer = layers.At(layerNum + 1);
total = hiddenLayer.Total();
for(int n = 0; n < total && !IsStopped(); ++n)
{
neuron = hiddenLayer.At(n);
if(nextLayer.At(0).Type() == defNeuron)
{
temp = nextLayer;
neuron.calcHiddenGradients(temp);
continue;
}
if(neuron.Type() == defNeuron)
{
float g = 0;
for(int i = 0; i < nextLayer.Total(); i++)
{
temp = nextLayer.At(i);
neuron.calcHiddenGradients(temp);
g += neuron.getGradient();
}
neuron.setGradient(g);
continue;
}
temp = nextLayer.At(n);
neuron.calcHiddenGradients(temp);
}
}
//---
for(int layerNum = layers.Total() - 1; layerNum > 0; layerNum--)
{
CLayer *layer = layers.At(layerNum);
CLayer *prevLayer = layers.At(layerNum - 1);
total = layer.Total() - (layer.At(0).Type() == defNeuron ? 1 : 0);
int n_conv = 0;
for(int n = 0; n < total && !IsStopped(); n++)
{
neuron = layer.At(n);
if(CheckPointer(neuron) == POINTER_INVALID)
return false;
if(neuron.Type() == defNeuronProof)
continue;
switch(prevLayer.At(0).Type())
{
case defNeuron:
temp = prevLayer;
neuron.updateInputWeights(temp);
break;
case defNeuronConv:
case defNeuronProof:
case defNeuronLSTM:
if(neuron.Type() == defNeuron)
{
for(n_conv = 0; n_conv < prevLayer.Total(); n_conv++)
{
temp = prevLayer.At(n_conv);
neuron.updateInputWeights(temp);
}
}
else
{
temp = prevLayer.At(n);
neuron.updateInputWeights(temp);
}
break;
default:
temp = NULL;
break;
}
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::backPropOCL(CBufferFloat *targetVals, CBufferFloat *SecondInput = NULL, CBufferFloat *SecondGradient = NULL, bool layer_by_layer = false, ENUM_ACTIVATION SecondActivation = None)
{
if(CheckPointer(targetVals) == POINTER_INVALID || CheckPointer(layers) == POINTER_INVALID || CheckPointer(opencl) == POINTER_INVALID)
return false;
CLayer *currentLayer = layers.At(layers.Total() - 1);
if(CheckPointer(currentLayer) == POINTER_INVALID)
return false;
//---
float error = 0.0;
int total = targetVals.Total();
CNeuronBaseOCL *neuron = currentLayer.At(0);
{
vector<float> target, output;
if(neuron.getOutputVal(output) < total)
return false;
targetVals.GetData(target);
error = output.Loss(target, LOSS_MSE);
}
//---
if(!neuron.calcOutputGradients(targetVals, error))
return false;
//---
if(neuron.TrainMode())
{
if(!MathIsValidNumber(error))
error = getRecentAverageError();
backPropCount++;
recentAverageError += (error - recentAverageError) / fmin(recentAverageSmoothingFactor, (float)backPropCount);
}
//---
if(layer_by_layer)
{
total = layers.Total();
for(int layer_update = 1; layer_update < total; layer_update++)
{
for(int layerNum = total - 2; layerNum > layer_update - 1; layerNum--)
{
CLayer *nextLayer = currentLayer;
currentLayer = layers.At(layerNum);
neuron = currentLayer.At(0);
if(!neuron.calcHiddenGradients(nextLayer.At(0), SecondInput, SecondGradient, SecondActivation))
return false;
}
//---
CLayer *prevLayer = layers.At(layer_update - 1);
currentLayer = layers.At(layer_update);
neuron = currentLayer.At(0);
if(!neuron.UpdateInputWeights(prevLayer.At(0), SecondInput))
return false;
//---
for(int layerNum = layer_update; layerNum < total; layerNum++)
{
currentLayer = layers.At(layerNum);
if(CheckPointer(currentLayer) == POINTER_INVALID)
return false;
//---
CNeuronBaseOCL *current_ocl = currentLayer.At(0);
if(!current_ocl.FeedForward(prevLayer.At(0), SecondInput))
return false;
prevLayer = currentLayer;
}
}
return true;
}
//--- Calc Hidden Gradients
//CObject *temp=NULL;
total = layers.Total();
for(int layerNum = total - 2; layerNum >= 0; layerNum--)
{
CLayer *nextLayer = currentLayer;
currentLayer = layers.At(layerNum);
neuron = currentLayer.At(0);
if(!neuron.calcHiddenGradients(nextLayer.At(0), SecondInput, SecondGradient, SecondActivation))
return false;
}
//---
CLayer *prevLayer = layers.At(total - 1);
for(int layerNum = total - 1; layerNum > 0; layerNum--)
{
currentLayer = prevLayer;
prevLayer = layers.At(layerNum - 1);
neuron = currentLayer.At(0);
if(!neuron.UpdateInputWeights(prevLayer.At(0), SecondInput))
return false;
}
//---
bool result = false;
for(int layerNum = 0; (layerNum < layers.Total() && !result); layerNum++)
{
currentLayer = layers.At(layerNum);
CNeuronBaseOCL *temp = currentLayer.At(0);
CNeuronConvOCL *conv = NULL;
CNeuronBatchNormOCL *batch = NULL;
CNeuronLSTMOCL *lstm = NULL;
if(!temp)
continue;
if(!temp.TrainMode())
{
if(layerNum == layers.Total() - 1)
result = true;
continue;
}
switch(temp.Type())
{
case defNeuronConvOCL:
conv = temp;
if(!!conv.GetWeightsConv() && conv.GetWeightsConv().BufferRead())
result = true;
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
case defNeuronBatchNormOCL:
batch = temp;
if(!!batch.getBatchOptions() && batch.getBatchOptions().BufferRead())
result = true;
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
case defNeuronLSTMOCL:
lstm = temp;
if(!!lstm.getLSTMWeights() && lstm.getLSTMWeights().BufferRead())
result = true;
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
default:
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
}
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNet::getResults(CBufferFloat *&resultVals)
{
if(CheckPointer(resultVals) == POINTER_INVALID)
{
resultVals = new CBufferFloat();
if(CheckPointer(resultVals) == POINTER_INVALID)
return;
}
//---
resultVals.Clear();
if(CheckPointer(layers) == POINTER_INVALID || layers.Total() <= 0)
return;
//---
CLayer *output = layers.At(layers.Total() - 1);
if(CheckPointer(output) == POINTER_INVALID)
return;
//---
if(CheckPointer(opencl) != POINTER_INVALID && output.At(0).Type() >= defNeuronBaseOCL)
{
CNeuronBaseOCL *temp = output.At(0);
temp.getOutputVal(resultVals);
return;
}
CNeuronBase *neuron = NULL;
CLayer *temp = NULL;
int total = output.Total();
if(output.At(0).Type() == defNeuron)
total--;
//---
for(int i = 0; i < total; i++)
{
neuron = output.At(i);
if(CheckPointer(neuron) == POINTER_INVALID)
continue;
if(neuron.Type() == defNeuron)
{
resultVals.Add(neuron.getOutputVal());
continue;
}
CNeuronProof *n = neuron;
temp = n.getOutputLayer();
for(int ii = 0; ii < temp.Total(); ii++)
{
neuron = temp.At(ii);
if(CheckPointer(neuron) == POINTER_INVALID)
continue;
resultVals.Add(neuron.getOutputVal());
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::Save(string file_name, float error, float undefine, float forecast, datetime time, bool common = true)
{
//if(MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_FORWARD) || MQLInfoInteger(MQL_OPTIMIZATION))
// return true;
if(file_name == NULL || !layers)
return false;
//---
int handle = FileOpen(file_name, (common ? FILE_COMMON : 0) | FILE_BIN | FILE_WRITE);
if(handle == INVALID_HANDLE)
return false;
//---
if(FileWriteDouble(handle, error) <= 0 || FileWriteDouble(handle, undefine) <= 0 || FileWriteDouble(handle, forecast) <= 0 || FileWriteLong(handle, (long)time) <= 0)
{
FileClose(handle);
return false;
}
bool result = layers.Save(handle);
FileFlush(handle);
FileClose(handle);
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::Save(const int file_handle)
{
if(file_handle == INVALID_HANDLE || !layers)
return false;
//---
if(FileWriteDouble(file_handle, (double)recentAverageError) <= 0 || FileWriteDouble(file_handle, 0) <= 0 || FileWriteDouble(file_handle, 0) <= 0 || FileWriteLong(file_handle, (long)0) <= 0)
return false;
//---
return layers.Save(file_handle);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::Load(string file_name, float &error, float &undefine, float &forecast, datetime &time, bool common = true)
{
//if(MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_FORWARD) || MQLInfoInteger(MQL_OPTIMIZATION))
// return false;
//---
if(file_name == NULL)
return false;
//---
Print(file_name);
int handle = FileOpen(file_name, (common ? FILE_COMMON : 0) | FILE_BIN | FILE_READ | FILE_SHARE_READ);
if(handle == INVALID_HANDLE)
return false;
//---
error = (float)FileReadDouble(handle);
undefine = (float)FileReadDouble(handle);
forecast = (float)FileReadDouble(handle);
time = (datetime)FileReadLong(handle);
recentAverageError = fmax(error, 0);
//---
if(CheckPointer(layers) != POINTER_INVALID)
layers.Clear();
else
layers = new CArrayLayer();
int i = 0, num;
//---
if(CheckPointer(opencl) == POINTER_INVALID)
{
opencl = new COpenCLMy();
if(CheckPointer(opencl) != POINTER_INVALID && !opencl.Initialize(cl_program, true))
delete opencl;
else
{
//--- create kernels
opencl.SetKernelsCount(71);
if(!opencl.KernelCreate(def_k_FeedForward, "FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcOutputGradient, "CalcOutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcHiddenGradient, "CalcHiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsMomentum, "UpdateWeightsMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsAdam, "UpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsLS, "UpdateWeightsLS"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_AttentionGradients, "AttentionInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_AttentionOut, "AttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_AttentionScore, "AttentionScore"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcHiddenGradientConv, "CalcHiddenGradientConv"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcInputGradientProof, "CalcInputGradientProof"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FeedForwardConv, "FeedForwardConv"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FeedForwardProof, "FeedForwardProof"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MatrixSum, "SumMatrix"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Matrix5Sum, "Sum5Matrix"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsConvAdam, "UpdateWeightsConvAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsConvMomentum, "UpdateWeightsConvMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsConvLS, "UpdateWeightsConvLS"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Normilize, "Normalize"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_NormilizeWeights, "NormalizeWeights"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatenateMatrix, "ConcatenateBuffers"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_DeconcatenateMatrix, "DeconcatenateBuffers"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHAttentionGradients, "MHAttentionInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHAttentionScore, "MHAttentionScore"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHAttentionOut, "MHAttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Dropout, "Dropout"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_BatchFeedForward, "BatchFeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcHiddenGradientBatch, "CalcHiddenGradientBatch"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateBatchOptionsMomentum, "UpdateBatchOptionsMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateBatchOptionsAdam, "UpdateBatchOptionsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_VAEFeedForward, "VAE_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_VAECalcHiddenGradient, "VAE_CalcHiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_ConcatenatedGradient, "LSTM_ConcatenatedGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_HiddenGradient, "LSTM_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_FeedForward, "LSTM_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_UpdateWeightsAdam, "LSTM_UpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftMax_FeedForward, "SoftMax_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftMax_HiddenGradient, "SoftMax_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftMax_OutputGradient, "SoftMax_OutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_Cosine, "FQF_Cosine"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_Output, "FQF_Output"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_OutputGradient, "FQF_OutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_QuantileGradient, "FQF_QuantileGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_CosineGradient, "FQF_CosineGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHSparseAttentionScore, "MHSparseAttentionScore"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHSparseAttentionOut, "MHSparseAttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FFMultiModels, "FeedForwardMultiModels"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_HGMultiModels, "CalcHiddenGradientMultiModels"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UWMultiModels, "UpdateWeightsAdamMultiModels"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatFeedForward, "Concat_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatCalcHiddenGradient, "Concat_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatUpdWeightsMomentum, "Concat_UpdateWeightsMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatUpdWeightsAdam, "Concat_UpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftUpdate, "SoftUpdate"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftUpdateAdam, "SoftUpdateAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_AlphaLogProbs, "SAC_AlphaLogProbs"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_AlphaGradients, "SAC_AlphaGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_OutputGradient, "SAC_OutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_CalcLogProbs, "SAC_CalcLogProbs"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Embedding, "Embedding"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_EmbeddingHiddenGradient, "EmbeddingHiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_EmbeddingUpdateWeightsAdam, "EmbeddingUpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Transpose, "Transpose"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MH2AttentionOut, "MH2AttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MH2AttentionInsideGradients, "MH2AttentionInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CGConv_HiddenGradient, "CGConv_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_XCiTFeedForward, "XCiTFeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_XCiTInsideGradients, "XCiTInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_DOTFeedForward, "DOTFeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_DOTInsideGradients, "DOTInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_RPBUpdateAdam, "RPBUpdateAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
}
}
//--- check
//--- read and check start marker - 0xFFFFFFFFFFFFFFFF
long temp = FileReadLong(handle);
if(temp == -1)
{
//--- read and check array type
if(FileReadInteger(handle, INT_VALUE) != layers.Type())
{
FileClose(handle);
return(false);
}
}
else
{
FileClose(handle);
return(false);
}
//--- read array length
num = FileReadInteger(handle, INT_VALUE);
//--- read array
if(num != 0)
{
for(i = 0; i < num; i++)
{
//--- create new element
CLayer *Layer = new CLayer(0, handle, opencl);
if(!Layer.Load(handle))
break;
if(!layers.Add(Layer))
break;
}
}
FileClose(handle);
//--- result
return (layers.Total() == num);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::Load(const int file_handle)
{
if(file_handle == INVALID_HANDLE || FileIsEnding(file_handle))
return false;
//---
{
recentAverageError = (float)FileReadDouble(file_handle);
float temp = (float)fmax(FileReadDouble(file_handle), 0);
temp = (float)FileReadDouble(file_handle);
temp = (float)FileReadLong(file_handle);
}
//---
if(CheckPointer(layers) != POINTER_INVALID)
layers.Clear();
else
layers = new CArrayLayer();
int i = 0, num;
//---
if(CheckPointer(opencl) == POINTER_INVALID)
{
opencl = new COpenCLMy();
if(CheckPointer(opencl) != POINTER_INVALID && !opencl.Initialize(cl_program, true))
delete opencl;
else
{
//--- create kernels
opencl.SetKernelsCount(71);
if(!opencl.KernelCreate(def_k_FeedForward, "FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcOutputGradient, "CalcOutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcHiddenGradient, "CalcHiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsMomentum, "UpdateWeightsMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsAdam, "UpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsLS, "UpdateWeightsLS"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_AttentionGradients, "AttentionInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_AttentionOut, "AttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_AttentionScore, "AttentionScore"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcHiddenGradientConv, "CalcHiddenGradientConv"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcInputGradientProof, "CalcInputGradientProof"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FeedForwardConv, "FeedForwardConv"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FeedForwardProof, "FeedForwardProof"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MatrixSum, "SumMatrix"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Matrix5Sum, "Sum5Matrix"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsConvAdam, "UpdateWeightsConvAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsConvMomentum, "UpdateWeightsConvMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateWeightsConvLS, "UpdateWeightsConvLS"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Normilize, "Normalize"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_NormilizeWeights, "NormalizeWeights"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatenateMatrix, "ConcatenateBuffers"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_DeconcatenateMatrix, "DeconcatenateBuffers"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHAttentionGradients, "MHAttentionInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHAttentionScore, "MHAttentionScore"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHAttentionOut, "MHAttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Dropout, "Dropout"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_BatchFeedForward, "BatchFeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CalcHiddenGradientBatch, "CalcHiddenGradientBatch"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateBatchOptionsMomentum, "UpdateBatchOptionsMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UpdateBatchOptionsAdam, "UpdateBatchOptionsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_VAEFeedForward, "VAE_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_VAECalcHiddenGradient, "VAE_CalcHiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_ConcatenatedGradient, "LSTM_ConcatenatedGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_HiddenGradient, "LSTM_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_FeedForward, "LSTM_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_LSTM_UpdateWeightsAdam, "LSTM_UpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftMax_FeedForward, "SoftMax_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftMax_HiddenGradient, "SoftMax_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftMax_OutputGradient, "SoftMax_OutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_Cosine, "FQF_Cosine"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_Output, "FQF_Output"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_OutputGradient, "FQF_OutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_QuantileGradient, "FQF_QuantileGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FQF_CosineGradient, "FQF_CosineGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHSparseAttentionScore, "MHSparseAttentionScore"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MHSparseAttentionOut, "MHSparseAttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_FFMultiModels, "FeedForwardMultiModels"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_HGMultiModels, "CalcHiddenGradientMultiModels"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_UWMultiModels, "UpdateWeightsAdamMultiModels"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatFeedForward, "Concat_FeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatCalcHiddenGradient, "Concat_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatUpdWeightsMomentum, "Concat_UpdateWeightsMomentum"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_ConcatUpdWeightsAdam, "Concat_UpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftUpdate, "SoftUpdate"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SoftUpdateAdam, "SoftUpdateAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_AlphaLogProbs, "SAC_AlphaLogProbs"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_AlphaGradients, "SAC_AlphaGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_OutputGradient, "SAC_OutputGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_SAC_CalcLogProbs, "SAC_CalcLogProbs"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Embedding, "Embedding"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_EmbeddingHiddenGradient, "EmbeddingHiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_EmbeddingUpdateWeightsAdam, "EmbeddingUpdateWeightsAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_Transpose, "Transpose"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MH2AttentionOut, "MH2AttentionOut"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_MH2AttentionInsideGradients, "MH2AttentionInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_CGConv_HiddenGradient, "CGConv_HiddenGradient"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_XCiTFeedForward, "XCiTFeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_XCiTInsideGradients, "XCiTInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_DOTFeedForward, "DOTFeedForward"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_DOTInsideGradients, "DOTInsideGradients"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
if(!opencl.KernelCreate(def_k_RPBUpdateAdam, "RPBUpdateAdam"))
{
PrintFormat("Error of create kernell: %d line %d", GetLastError(), __LINE__);
return false;
}
}
}
//--- check
//--- read and check start marker - 0xFFFFFFFFFFFFFFFF
long temp = FileReadLong(file_handle);
if(temp == -1)
{
//--- read and check array type
if(FileReadInteger(file_handle, INT_VALUE) != layers.Type())
return(false);
}
else
{
while((temp = FileReadLong(file_handle)) != -1 && !FileIsEnding(file_handle))
{
Sleep(0);
}
if(temp != -1)
return(false);
}
//--- read array length
num = FileReadInteger(file_handle, INT_VALUE);
//--- read array
if(num != 0)
{
for(i = 0; i < num; i++)
{
//--- create new element
CLayer *Layer = new CLayer(0, file_handle, opencl);
if(!Layer.Load(file_handle))
break;
if(!layers.Add(Layer))
break;
}
}
FileClose(file_handle);
//--- result
return (layers.Total() == num);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::TrainMode(bool flag)
{
if(CheckPointer(layers) == POINTER_INVALID || layers.Total() <= 1)
return false;
//---
CLayer *current = NULL;
//---
CObject *temp = NULL;
for(int l = 0; l < layers.Total(); l++)
{
current = layers.At(l);
if(CheckPointer(current) == POINTER_INVALID || CheckPointer(current.At(0)) == POINTER_INVALID)
return false;
//---
if(CheckPointer(opencl) != POINTER_INVALID)
{
CNeuronBaseOCL *current_ocl = current.At(0);
current_ocl.TrainMode(flag);
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProof::Save(const int file_handle)
{
if(!CNeuronBase::Save(file_handle) || !OutputLayer.Save(file_handle))
return false;
if(FileWriteInteger(file_handle, iWindow, INT_VALUE) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, iStep, INT_VALUE) < INT_VALUE)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProof::Load(const int file_handle)
{
if(!CNeuronBase::Load(file_handle) || !OutputLayer.Load(file_handle))
return false;
iWindow = FileReadInteger(file_handle, INT_VALUE);
iStep = FileReadInteger(file_handle, INT_VALUE);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConv::Save(const int file_handle)
{
if(!CNeuronProof::Save(file_handle))
return false;
if(FileWriteDouble(file_handle, param) < 8)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConv::Load(const int file_handle)
{
if(!CNeuronProof::Load(file_handle))
return false;
param = (float)FileReadDouble(file_handle);
//---
return true;
}
//+------------------------------------------------------------------+
///\class CNeuronLSTM
/// Class of recurrent LSTM unit
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8385#para5">the link.</A>
//+------------------------------------------------------------------+
class CNeuronLSTM : public CNeuronProof
{
protected:
CLayer *ForgetGate; ///< Object of forget gate
CLayer *InputGate; ///< Object of input gate
CLayer *OutputGate; ///< Object of output gate
CLayer *NewContent; ///< Object of new content
CArrayFloat *Memory; ///< Memory array
CArrayFloat *PrevMemory; ///< Ravious iteration memory array
CArrayFloat *Input; ///< Input data
CArrayFloat *InputGradient; ///< Gradient on previous layer
//---
virtual bool feedForward(CLayer *prevLayer); ///< Feed Forward method. Detailed description on <A HREF="https://www.mql5.com/en/articles/8385#para52">the link.</A>@param prevLayer Pointer to previos layer.
virtual bool calcHiddenGradients(CLayer *&nextLayer); ///< Method to transfer gradient to previous layer. @param nextLayer Pointer to next layer.
virtual bool updateInputWeights(CLayer *&prevLayer); ///< Method for updating weights.@param prevLayer Pointer to previos layer.
virtual bool updateInputWeights(CLayer *gate, CArrayFloat *input_data); ///< Method for updating gates' weights.@param gate Pointer to gate. @param input_data Pointer to tensor with input data.
virtual bool InitLayer(CLayer *layer, int numUnits, int numOutputs, ENUM_OPTIMIZATION optimization_type);
///< Method of gate initialization @param[in] layer Pointer to gate @param[in] numUnits Number of units in gate @param[in] numOutputs Number of outputs @param[in] optimization_type Type of optimization (#ENUM_OPTIMIZATION)
virtual CArrayFloat *CalculateGate(CLayer *gate, CArrayFloat *sequence); ///< Method of calculation gate iteration @param[in] gate Pointer to gate @param[in] sequence Input data @return Array of output data
public:
/** Constructor */
CNeuronLSTM(void);
/** Destructor */~CNeuronLSTM(void);
virtual bool Init(uint numOutputs, uint myIndex, int window, int step, int units_count, ENUM_OPTIMIZATION optimization_type);
///< Unit initialization method. Detailed description on <A HREF="https://www.mql5.com/en/articles/8385#para51">the link.</A>
//---
virtual CLayer *getOutputLayer(void) { return OutputLayer; } ///< Method for getting a pointer to the resulting neural layer. Not used in fully connected neural networks.@return Pointer to layer.
virtual bool calcInputGradients(CLayer *prevLayer) ;
virtual bool calcInputGradients(CNeuronBase *prevNeuron, uint index) ;
//--- methods for working with files
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
virtual int Type(void) const { return defNeuronLSTM; }///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronLSTM::CNeuronLSTM(void)
{
ForgetGate = new CLayer();
InputGate = new CLayer();
OutputGate = new CLayer();
NewContent = new CLayer();
Memory = new CArrayFloat();
PrevMemory = new CArrayFloat();
Input = new CArrayFloat();
InputGradient = new CArrayFloat();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronLSTM::~CNeuronLSTM(void)
{
if(CheckPointer(ForgetGate) != POINTER_INVALID)
delete ForgetGate;
if(CheckPointer(InputGate) != POINTER_INVALID)
delete InputGate;
if(CheckPointer(OutputGate) != POINTER_INVALID)
delete OutputGate;
if(CheckPointer(NewContent) != POINTER_INVALID)
delete NewContent;
if(CheckPointer(Memory) != POINTER_INVALID)
delete Memory;
if(CheckPointer(PrevMemory) != POINTER_INVALID)
delete PrevMemory;
if(CheckPointer(Input) != POINTER_INVALID)
delete Input;
if(CheckPointer(InputGradient) != POINTER_INVALID)
delete InputGradient;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::Init(uint numOutputs, uint myIndex, int window, int step, int units_count, ENUM_OPTIMIZATION optimization_type)
{
if(units_count <= 0)
return false;
//--- Init Layers
if(!CNeuronProof::Init(numOutputs, myIndex, window, step, units_count, optimization_type))
return false;
if(!InitLayer(ForgetGate, units_count, window + units_count, optimization_type))
return false;
if(!InitLayer(InputGate, units_count, window + units_count, optimization_type))
return false;
if(!InitLayer(OutputGate, units_count, window + units_count, optimization_type))
return false;
if(!InitLayer(NewContent, units_count, window + units_count, optimization_type))
return false;
if(!Memory.Reserve(units_count))
return false;
if(!PrevMemory.Reserve(units_count))
return false;
CNeuron *temp;
for(int i = 0; i < units_count; i++)
{
if(!Memory.Add(0))
return false;
if(!PrevMemory.Add(0))
return false;
temp = OutputLayer.At(i);
temp.setOutputVal(0);
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::InitLayer(CLayer *layer, int numUnits, int numOutputs, ENUM_OPTIMIZATION optimization_type)
{
if(CheckPointer(layer) == POINTER_INVALID)
{
layer = new CLayer(numOutputs);
if(CheckPointer(layer) == POINTER_INVALID)
return false;
}
else
layer.Clear();
if(!layer.Reserve(numUnits))
return false;
//---
CNeuron *temp;
for(int i = 0; i < numUnits; i++)
{
temp = new CNeuron();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Init(numOutputs + 1, i, optimization_type))
return false;
if(!layer.Add(temp))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::feedForward(CLayer *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID || prevLayer.Total() <= 0)
return false;
CNeuronBase *temp;
CConnection *temp_con;
if(CheckPointer(Input) == POINTER_INVALID)
{
Input = new CArrayFloat();
if(CheckPointer(Input) == POINTER_INVALID)
return false;
}
else
Input.Clear();
//--- Concatenate input sequence
int total = prevLayer.Total();
if(!Input.Reserve(total + OutputLayer.Total()))
return false;
for(int i = 0; i < total; i++)
{
temp = prevLayer.At(i);
if(CheckPointer(temp) == POINTER_INVALID || !Input.Add(temp.getOutputVal()))
return false;
}
total = OutputLayer.Total();
for(int i = 0; i < total; i++)
{
temp = OutputLayer.At(i);
if(CheckPointer(temp) == POINTER_INVALID || !Input.Add(temp.getOutputVal()))
return false;
}
int total_data = Input.Total();
//--- Calculated forget gate
CArrayFloat *forget_gate = CalculateGate(ForgetGate, Input);
if(CheckPointer(forget_gate) == POINTER_INVALID)
return false;
//--- Calculated input gate
CArrayFloat *input_gate = CalculateGate(InputGate, Input);
if(CheckPointer(input_gate) == POINTER_INVALID)
return false;
//--- Calculated output gate
CArrayFloat *output_gate = CalculateGate(OutputGate, Input);
if(CheckPointer(output_gate) == POINTER_INVALID)
return false;
//--- Calculated new content
CArrayFloat *new_content = new CArrayFloat();
if(CheckPointer(new_content) == POINTER_INVALID)
return false;
total = NewContent.Total();
for(int i = 0; i < total; i++)
{
temp = NewContent.At(i);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
float val = 0;
for(int c = 0; c < total_data; c++)
{
temp_con = temp.Connections.At(c);
if(CheckPointer(temp_con) == POINTER_INVALID)
return false;
val += temp_con.weight * Input.At(c);
}
val = TanhFunction(val);
temp.setOutputVal(val);
if(!new_content.Add(val))
return false;
}
//--- Calculated output sequences
for(int i = 0; i < total; i++)
{
if(PrevMemory.Total() <= i)
PrevMemory.Add(Memory.At(i));
else
PrevMemory.Update(i, Memory.At(i));
float value = Memory.At(i) * forget_gate.At(i) + new_content.At(i) * input_gate.At(i);
if(!Memory.Update(i, value))
return false;
temp = OutputLayer.At(i);
value = TanhFunction(value) * output_gate.At(i);
temp.setOutputVal(value);
}
//---
delete forget_gate;
delete input_gate;
delete new_content;
delete output_gate;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CArrayFloat *CNeuronLSTM::CalculateGate(CLayer *gate, CArrayFloat *sequence)
{
CNeuronBase *temp;
CConnection *temp_con;
CArrayFloat *result = new CArrayFloat();
if(CheckPointer(gate) == POINTER_INVALID)
return NULL;
int total = gate.Total();
int total_data = sequence.Total();
for(int i = 0; i < total; i++)
{
temp = gate.At(i);
if(CheckPointer(temp) == POINTER_INVALID)
{
delete result;
return NULL;
}
float val = 0;
for(int c = 0; c < total_data; c++)
{
temp_con = temp.Connections.At(c);
if(CheckPointer(temp_con) == POINTER_INVALID)
{
delete result;
return NULL;
}
val += temp_con.weight * (sequence.At(c) == DBL_MAX ? 1 : sequence.At(c));
}
val = SigmoidFunction(val);
temp.setOutputVal(val);
if(!result.Add(val))
{
delete result;
return NULL;
}
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::calcHiddenGradients(CLayer *&nextLayer)
{
if(CheckPointer(InputGradient) == POINTER_INVALID)
{
InputGradient = new CArrayFloat();
if(CheckPointer(InputGradient) == POINTER_INVALID)
return false;
}
else
InputGradient.Clear();
//---
int total = OutputLayer.Total();
CNeuron *temp;
CArrayFloat *MemoryGradient = new CArrayFloat();
CNeuron *gate;
CConnection *con;
//---
if(nextLayer != OutputLayer)
for(int i = 0; i < total; i++)
{
temp = OutputLayer.At(i);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
temp.setGradient(temp.sumDOW(nextLayer));
}
//--- Calculated memory and output gate gradients
if(CheckPointer(MemoryGradient) == POINTER_INVALID)
return false;
if(!MemoryGradient.Reserve(total))
return false;
for(int i = 0; i < total; i++)
{
temp = OutputLayer.At(i);
gate = OutputGate.At(i);
if(CheckPointer(gate) == POINTER_INVALID)
return false;
float value = temp.getGradient() * gate.getOutputVal();
value = TanhFunctionDerivative(Memory.At(i)) * value;
if(i >= MemoryGradient.Total())
{
if(!MemoryGradient.Add(value))
return false;
}
else
{
value = MemoryGradient.At(i) + value;
if(!MemoryGradient.Update(i, value))
return false;
}
gate.setGradient(gate.getOutputVal() != 0 && temp.getGradient() != 0 ? temp.getGradient()*temp.getOutputVal()*SigmoidFunctionDerivative(gate.getOutputVal()) / gate.getOutputVal() : 0);
//--- Calcculated gates and new content gradients
gate = ForgetGate.At(i);
if(CheckPointer(gate) == POINTER_INVALID)
return false;
gate.setGradient(gate.getOutputVal() != 0 && value != 0 ? value * SigmoidFunctionDerivative(gate.getOutputVal()) : 0);
gate = InputGate.At(i);
temp = NewContent.At(i);
if(CheckPointer(gate) == POINTER_INVALID)
return false;
gate.setGradient(gate.getOutputVal() != 0 && value != 0 ? value * temp.getOutputVal()*SigmoidFunctionDerivative(gate.getOutputVal()) : 0);
temp.setGradient(temp.getOutputVal() != 0 && value != 0 ? value * gate.getOutputVal()*TanhFunctionDerivative(temp.getOutputVal()) : 0);
}
//--- Calculated input gradients
int total_inp = temp.getConnections().Total();
for(int n = 0; n < total_inp; n++)
{
float value = 0;
for(int i = 0; i < total; i++)
{
temp = ForgetGate.At(i);
con = temp.getConnections().At(n);
value += temp.getGradient() * con.weight;
//---
temp = InputGate.At(i);
con = temp.getConnections().At(n);
value += temp.getGradient() * con.weight;
//---
temp = OutputGate.At(i);
con = temp.getConnections().At(n);
value += temp.getGradient() * con.weight;
//---
temp = NewContent.At(i);
con = temp.getConnections().At(n);
value += temp.getGradient() * con.weight;
}
if(InputGradient.Total() >= n)
{
if(!InputGradient.Add(value))
return false;
}
else
if(!InputGradient.Update(n, value))
return false;
}
//--- Calculated gradients for prev. state
int shift = total_inp - total;
for(int i = 0; i < total; i++)
{
temp = OutputLayer.At(i);
if(CheckPointer(temp) == POINTER_INVALID)
return false;
temp.setGradient(InputGradient.At(shift + i));
}
//--- Calculated memory and output gate gradients
for(int i = 0; i < total; i++)
{
temp = OutputLayer.At(i);
gate = OutputGate.At(i);
if(CheckPointer(gate) == POINTER_INVALID)
return false;
float value = temp.getGradient() * gate.getPrevVal();
value = MemoryGradient.At(i) + TanhFunctionDerivative(PrevMemory.At(i)) * value;
if(!MemoryGradient.Update(i, value))
return false;
gate.setGradient(gate.getGradient() + (gate.getPrevVal() != 0 && temp.getGradient() != 0 ? temp.getGradient()*temp.getPrevVal()*SigmoidFunctionDerivative(gate.getPrevVal()) / gate.getPrevVal() : 0));
//--- Calcculated gates and new content gradients
gate = ForgetGate.At(i);
if(CheckPointer(gate) == POINTER_INVALID)
return false;
gate.setGradient(gate.getGradient() + (gate.getPrevVal() != 0 && value != 0 ? value * SigmoidFunctionDerivative(gate.getPrevVal()) : 0));
gate = InputGate.At(i);
temp = NewContent.At(i);
if(CheckPointer(gate) == POINTER_INVALID)
return false;
gate.setGradient(gate.getGradient() + (gate.getPrevVal() != 0 && value != 0 ? value * temp.getPrevVal()*SigmoidFunctionDerivative(gate.getPrevVal()) : 0));
temp.setGradient(temp.getGradient() + (temp.getPrevVal() != 0 && value != 0 ? value * gate.getPrevVal()*TanhFunctionDerivative(temp.getPrevVal()) : 0));
}
//---
delete MemoryGradient;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::updateInputWeights(CLayer *&prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID || CheckPointer(Input) == POINTER_INVALID)
return false;
//---
if(!updateInputWeights(ForgetGate, Input) || !updateInputWeights(InputGate, Input) || !updateInputWeights(OutputGate, Input)
|| !updateInputWeights(NewContent, Input))
{
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::updateInputWeights(CLayer *gate, CArrayFloat *input_data)
{
if(CheckPointer(gate) == POINTER_INVALID || CheckPointer(input_data) == POINTER_INVALID)
return false;
CNeuronBase *neuron;
CConnection *con;
int total_n = gate.Total();
int total_data = input_data.Total();
float lt = (float)(lr * sqrt(1 - pow(b2, t)) / (1 - pow(b1, t)));
for(int n = 0; n < total_n; n++)
{
neuron = gate.At(n);
if(CheckPointer(neuron) == POINTER_INVALID)
return false;
for(int i = 0; i < total_data; i++)
{
con = neuron.getConnections().At(i);
if(CheckPointer(con) == POINTER_INVALID)
return false;
float data = input_data.At(i);
float g = neuron.getGradient();
if(optimization == SGD)
con.weight += con.deltaWeight = (g != 0 && data != 0 ? lr * g * (data != DBL_MAX ? data : 1) : 0) + alpha * con.deltaWeight;
else
{
con.mt = b1 * con.mt + (1 - b1) * g;
con.vt = (float)(b2 * con.vt + (1 - b2) * pow(g, 2) + 0.00000001);
con.weight += con.deltaWeight = (float)(lt * con.mt / sqrt(con.vt));
t++;
}
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::calcInputGradients(CNeuronBase *prevNeuron, uint index)
{
if(CheckPointer(prevNeuron) == POINTER_INVALID || CheckPointer(InputGradient) == POINTER_INVALID || InputGradient.Total() <= (int)index)
return false;
//---
prevNeuron.setGradient(InputGradient.At(index));
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::calcInputGradients(CLayer *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
int total = prevLayer.Total();
if(total <= 0)
return false;
CNeuronBase *neuron;
bool result = true;
for(int i = 0; (i < total && result); i++)
{
neuron = prevLayer.At(i);
if(CheckPointer(neuron) == POINTER_INVALID)
{
result = false;
break;
}
result = calcInputGradients(neuron, i);
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::Save(const int file_handle)
{
if(!CNeuronProof::Save(file_handle))
return false;
if(!ForgetGate.Save(file_handle))
return false;
if(!InputGate.Save(file_handle))
return false;
if(!OutputGate.Save(file_handle))
return false;
if(!NewContent.Save(file_handle))
return false;
if(!Memory.Save(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTM::Load(const int file_handle)
{
if(!CNeuronProof::Load(file_handle))
return false;
if(!ForgetGate.Load(file_handle))
return false;
if(!InputGate.Load(file_handle))
return false;
if(!OutputGate.Load(file_handle))
return false;
if(!NewContent.Load(file_handle))
return false;
if(!Memory.Load(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
float CNeuronBase::activationFunction(float x)
{
switch(activation)
{
case TANH:
return TanhFunction(x);
break;
case SIGMOID:
return SigmoidFunction(x);
break;
}
//---
return x;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
float CNeuronBase::activationFunctionDerivative(float x)
{
switch(activation)
{
case TANH:
return TanhFunctionDerivative(x);
break;
case SIGMOID:
return SigmoidFunctionDerivative(x);
break;
}
//---
return 1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template<typename T>
int COpenCLMy::AddBufferFromArray(T &data[], const uint data_array_offset, const uint data_array_count, const uint flags)
{
int result = -1;
for(int i = 0; i < m_buffers_total; i++)
{
if(m_buffers[i] != INVALID_HANDLE)
continue;
result = i;
break;
}
//---
if(result < 0)
{
if(ArrayResize(m_buffers, m_buffers_total + 1) > 0)
{
m_buffers_total = ArraySize(m_buffers);
result = m_buffers_total - 1;
m_buffers[result] = INVALID_HANDLE;
}
else
return result;
}
//---
if(!BufferFromArray(result, data, data_array_offset, data_array_count, flags))
return -1;
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int COpenCLMy::AddBuffer(uint size_in_bytes, const uint flags)
{
int result = -1;
for(int i = 0; i < m_buffers_total; i++)
{
if(m_buffers[i] != INVALID_HANDLE)
continue;
result = i;
break;
}
//---
if(result < 0)
{
if(ArrayResize(m_buffers, m_buffers_total + 1) > 0)
{
m_buffers_total = ArraySize(m_buffers);
result = m_buffers_total - 1;
m_buffers[result] = INVALID_HANDLE;
}
else
return result;
}
//---
if(!BufferCreate(result, size_in_bytes, flags))
return -1;
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayer::CLayer(uint outputs = 0, int handle = -1, COpenCLMy *opencl = NULL)
{
iOutputs = outputs;
iFileHandle = handle;
OpenCL = opencl;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CLayer::Load(const int file_handle)
{
iFileHandle = file_handle;
if(!CArrayObj::Load(file_handle))
return false;
if(CheckPointer(m_data[0]) == POINTER_INVALID)
return false;
//---
CNeuronBaseOCL *ocl = NULL;
CNeuronBase *cpu = NULL;
switch(m_data[0].Type())
{
case defNeuronBaseOCL:
case defNeuronProofOCL:
case defNeuronConvOCL:
case defNeuronAttentionOCL:
case defNeuronMHAttentionOCL:
case defNeuronMH2AttentionOCL:
case defNeuronMLMHAttentionOCL:
case defNeuronMLMHSparseAttentionOCL:
case defNeuronDropoutOCL:
case defNeuronBatchNormOCL:
case defNeuronVAEOCL:
case defNeuronLSTMOCL:
case defNeuronSoftMaxOCL:
case defNeuronFQF:
case defNeuronMultiModels:
case defNeuronConcatenate:
case defNeuronSoftActorCritic:
case defNeuronEmbeddingOCL:
case defNeuronPEOCL:
case defNeuronTransposeOCL:
case defNeuronCGConvOCL:
case defNeuronMFTOCL:
case defNeuronXCiTOCL:
case defNeuronDOTOCL:
case defNeuronFAQOCL:
case defNeuronCrossAttenOCL:
ocl = m_data[0];
iOutputs = ocl.getConnections();
break;
default:
cpu = m_data[0];
iOutputs = cpu.getConnections().Total();
break;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CLayer::SetOpenCL(COpenCLMy *obj)
{
if(!!OpenCL)
delete OpenCL;
if(!obj || Total() <= 0)
return;
//---
for(int i = 0; i < Total(); i++)
{
CNeuronBaseOCL *neuron = m_data[i];
if(!neuron)
continue;
neuron.SetOpenCL(obj);
}
OpenCL = obj;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNet::~CNet(void)
{
if(CheckPointer(layers) != POINTER_INVALID)
delete layers;
if(CheckPointer(opencl) != POINTER_INVALID)
{
opencl.Shutdown();
delete opencl;
}
}
//+------------------------------------------------------------------+
///\class CBufferFloat
/// Class of OpenCL buffer data. Used for transfer data from CPU to GPU and back.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8435#para44">the link.</A>
//+------------------------------------------------------------------+
class CBufferFloat : public CArrayFloat
{
protected:
COpenCLMy *OpenCL; ///< Object for working with OpenCL
int m_myIndex; ///< Index of buffer
public:
/** Constructor */
CBufferFloat(void);
/** Destructor */~CBufferFloat(void);
//---
virtual bool BufferInit(uint count, float value); ///< Method for buffer initialization @param[in] count Number of items @param[in] value Initialization value
virtual bool BufferCreate(COpenCLMy *opencl); ///< Method for creating new buffer @param[in] opencl Pointer to #COpenCLMy object
virtual bool BufferFree(void); ///< Method for deleting buffer from GPU
virtual bool BufferRead(void); ///< Method for reading buffer data from GPU
virtual bool BufferWrite(void); ///< Method for writing buffer data to GPU
virtual bool BufferSet(int index) { if(!OpenCL.BufferFree(m_myIndex)) return false; m_myIndex = index; return true; } ///< Change buffer index number @param index New index
virtual int GetData(vectorf &values); ///< Read data from buffer to vector @param[out] values Vector to read data
virtual int GetData(float &values[]); ///< Read data from buffer to array @param[out] values Array to read data
virtual int GetData(CArrayFloat *values); ///< Read data from buffer to array @param[out] values Array to read data
virtual int GetIndex(void) { return m_myIndex; } ///< Get buffer index @return Index
virtual float Maximum(void) { return m_data[ArrayMaximum(m_data, 0, m_data_total)];}
int Maximum(const int start, const int count) const { return(CArray::Maximum(m_data, start, count)); }
virtual int Argmax(void) { return ArrayMaximum(m_data, 0, m_data_total);}
//---
virtual bool AssignArray(const float &src[]);
virtual bool AssignArray(const double &src[]);
virtual bool AssignArray(const matrix<float> &src);
virtual bool AssignArray(const vector<float> &src);
virtual bool AssignArray(const CArrayFloat *obj) { return CArrayFloat::AssignArray(obj); }
virtual bool AssignArray(const CBufferFloat *obj) { return CArrayFloat::AssignArray(obj); }
virtual bool AddArray(const vector<float> &src);
virtual bool AddArray(const float &src[]);
//---
virtual int Type(void) const { return defBufferDouble; }///< Identificator of class.@return Type of class
virtual void BufferToCSV(const string file_name); ///< Save buffer data to CSV file @param[in] file_name File name to write data
//--- methods for working with files
virtual bool Save(const int file_handle);
virtual bool Load(const int file_handle);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CBufferFloat::CBufferFloat(void) : m_myIndex(-1)
{
OpenCL = NULL;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CBufferFloat::~CBufferFloat(void)
{
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
{
if(OpenCL.BufferFree(m_myIndex))
{
m_myIndex = -1;
OpenCL = NULL;
}
}
Shutdown();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CBufferFloat::BufferCreate(COpenCLMy *opencl)
{
if(CheckPointer(opencl) == POINTER_INVALID)
return false;
//---
if(opencl == OpenCL && m_myIndex >= 0)
if(BufferWrite())
return true;
//---
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
{
if(OpenCL.BufferFree(m_myIndex))
{
m_myIndex = -1;
OpenCL = NULL;
}
else
return false;
}
//---
if((m_myIndex = opencl.AddBufferFromArray(m_data, 0, m_data_total, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR)) < 0)
return false;
OpenCL = opencl;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CBufferFloat::BufferFree(void)
{
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
if(OpenCL.BufferFree(m_myIndex))
{
m_myIndex = -1;
OpenCL = NULL;
return true;
}
//---
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CBufferFloat::BufferRead(void)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || m_myIndex < 0)
return false;
//---
if(!OpenCL.BufferRead(m_myIndex, m_data, 0, 0, m_data_total))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CBufferFloat::BufferWrite(void)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || m_myIndex < 0)
return false;
//---
return OpenCL.BufferWrite(m_myIndex, m_data, 0, 0, m_data_total);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CBufferFloat::BufferInit(uint count, float value)
{
if(m_data_max < (int)count && !Reserve((int)count - m_data_total))
return false;
m_data_total = (int)fmin(ArrayInitialize(m_data, value), count);
//---
return m_data_total == count;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CBufferFloat::GetData(float &values[])
{
if(!!OpenCL && !BufferRead())
return false;
return ArrayCopy(values, m_data, 0, 0, m_data_total);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CBufferFloat::GetData(vector<float> &values)
{
if(!!OpenCL && !BufferRead())
return false;
values.Assign(m_data);
if(!values.Resize(m_data_total))
return false;
return (int)values.Size();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CBufferFloat::GetData(CArrayFloat *values)
{
if(!BufferRead())
return -1;
if(!values.AssignArray(GetPointer(this)))
return -1;
return m_data_total;
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CBufferFloat::AssignArray(const double &src[])
{
int num = ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max < num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i = 0; i < num; i++)
{
m_data[i] = (float)src[i];
m_data_total++;
}
m_sort_mode = -1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CBufferFloat::AssignArray(const float &src[])
{
int num = ArraySize(src);
//--- check/reserve elements of array
Clear();
if(m_data_max < num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i = 0; i < num; i++)
{
m_data[i] = (float)src[i];
m_data_total++;
}
m_sort_mode = -1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CBufferFloat::AssignArray(const matrix<float> &src)
{
int num = (int)(src.Rows() * src.Cols());
//--- check/reserve elements of array
Clear();
if(m_data_max < num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i = 0; i < num; i++)
{
m_data[i] = src.Flat(i);
m_data_total++;
}
m_sort_mode = -1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Assignment (copying) of another array |
//+------------------------------------------------------------------+
bool CBufferFloat::AssignArray(const vector<float> &src)
{
int num = (int)(src.Size());
//--- check/reserve elements of array
Clear();
if(m_data_max < num)
{
if(!Reserve(num))
return(false);
}
else
Resize(num);
//--- copy array
for(int i = 0; i < num; i++)
{
m_data[i] = src[i];
m_data_total++;
}
m_sort_mode = -1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding (copying) of another array |
//+------------------------------------------------------------------+
bool CBufferFloat::AddArray(const vector<float> &src)
{
int num = (int)(src.Size());
//--- check/reserve elements of array
if(m_data_max < num + m_data_total)
{
if(!Reserve(num + m_data_total))
return(false);
}
else
Resize(num + m_data_total);
//--- copy array
for(int i = 0; i < num; i++)
m_data[m_data_total + i] = src[i];
m_data_total += num;
m_sort_mode = -1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| Adding (copying) of another array |
//+------------------------------------------------------------------+
bool CBufferFloat::AddArray(const float &src[])
{
int num = ArraySize(src);
//--- check/reserve elements of array
if(m_data_max < num + m_data_total)
{
if(!Reserve(num + m_data_total))
return(false);
}
else
Resize(num + m_data_total);
//--- copy array
for(int i = 0; i < num; i++)
m_data[m_data_total + i] = src[i];
m_data_total += num;
m_sort_mode = -1;
//--- successful
return(true);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CBufferFloat::Save(const int file_handle)
{
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
if(!BufferRead())
return false;
//---
return CArrayFloat::Save(file_handle);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CBufferFloat::Load(const int file_handle)
{
if(!CArrayFloat::Load(file_handle))
return false;
if(m_data_total == 0 || !OpenCL)
return true;
//---
COpenCLMy *temp = OpenCL;
if(!BufferFree())
return false;
return BufferCreate(temp);
}
//+------------------------------------------------------------------+
///\ingroup neuron_base
///\class CNeuronBaseOCL
///\brief The base class of neuron for GPU calculation.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8435#para45">the link.</A>
//+------------------------------------------------------------------+
class CNeuronBaseOCL : public CObject
{
protected:
bool bTrain; ///< Training Mode Flag
COpenCLMy *OpenCL; ///< Object for working with OpenCL
CBufferFloat *Output; ///< Buffer of Output tensor
CBufferFloat *PrevOutput; ///< Buffer of previous iteration Output tensor
CBufferFloat *Weights; ///< Buffer of weights matrix
CBufferFloat *DeltaWeights; ///< Buffer of last delta weights matrix (#SGD)
CBufferFloat *Gradient; ///< Buffer of gradient tensor
CBufferFloat *FirstMomentum; ///< Buffer of first momentum matrix (#ADAM)
CBufferFloat *SecondMomentum; ///< Buffer of second momentum matrix (#ADAM)
vector<float> prev_output;
//---
//const float lr;
const float alpha; ///< Multiplier to momentum in #SGD optimization
uint iBatch; ///< Batch size used in LS optimization
uint t; ///< Count of iterations
//---
int m_myIndex; ///< Index of neuron in layer
ENUM_ACTIVATION activation; ///< Activation type (#ENUM_ACTIVATION)
ENUM_OPTIMIZATION optimization; ///< Optimization method (#ENUM_OPTIMIZATION)
//---
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput) { return feedForward(NeuronOCL); } ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL); ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
virtual float GenerateWeight(void);
virtual bool WeightsUpdateAdam(CNeuronBaseOCL *source, float tau);
virtual bool SumAndNormilize(CBufferFloat *tensor1, CBufferFloat *tensor2, CBufferFloat *out, int dimension, bool normilize = true, int shift_in1 = 0, int shift_in2 = 0, int shift_out = 0);
///< \brief Method sum and normilize 2 tensors by calling 2 kernels ::SumMatrix() and ::Normalize().
virtual bool LoadInsideLayer(int file_handle, CNeuronBaseOCL *neuron);
public:
/** Constructor */
CNeuronBaseOCL(void);
/** Destructor */~CNeuronBaseOCL(void);
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, ENUM_OPTIMIZATION optimization_type, uint batch);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object. #param[in] numNeurons Number of neurons in layer @param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
virtual void SetActivationFunction(ENUM_ACTIVATION value) { activation = value; } ///< Set the type of activation function (#ENUM_ACTIVATION)
//---
virtual int getOutputIndex(void) { return Output.GetIndex(); } ///< Get index of output buffer @return Index
virtual int getPrevOutIndex(void) { return PrevOutput.GetIndex(); } ///< Get index of previous iteration output buffer @return Index
virtual int getGradientIndex(void) { return Gradient.GetIndex(); } ///< Get index of gradient buffer @return Index
virtual bool SetGradientIndex(int index) { return Gradient.BufferSet(index); } ///< Method for change index of gradient buffer.@param[in] New index of buffer
virtual int getWeightsIndex(void) { return Weights.GetIndex(); } ///< Get index of weights matrix buffer @return Index
virtual int getDeltaWeightsIndex(void) { return DeltaWeights.GetIndex(); } ///< Get index of delta weights matrix buffer (SGD)@return Index
virtual int getFirstMomentumIndex(void) { return FirstMomentum.GetIndex(); } ///< Get index of first momentum matrix buffer (Adam)@return Index
virtual int getSecondMomentumIndex(void) { return SecondMomentum.GetIndex();} ///< Get index of Second momentum matrix buffer (Adam)@return Index
//---
virtual int getOutputVal(float &values[]) { return Output.GetData(values); } ///< Get values of output buffer @param[out] values Array of data @return number of items
virtual int getOutputVal(CArrayFloat *values) { return Output.GetData(values); } ///< Get values of output buffer @param[out] values Array of data @return number of items
virtual int getOutputVal(vector<float> &values) { return Output.GetData(values); } ///< Get values of output buffer @param[out] values Array of data @return number of items
virtual int getPrevVal(float &values[]) { return PrevOutput.GetData(values); } ///< Get values of previous iteration output buffer @param[out] values Array of data @return number of items
virtual int getGradient(float &values[]) { return Gradient.GetData(values); } ///< Get values of gradient buffer @param[out] values Array of data @return number of items
virtual bool calcAlphaGradients(CNeuronBaseOCL *NeuronOCL) { return true; }
virtual bool GetAlphaLogProbs(vector<float> &log_probs) { return false; }
virtual bool ReCalcLogProbs(void) { return false; }
virtual CBufferFloat *getOutput(void) { return Output; } ///< Get pointer of output buffer @return Pointer to object
virtual CBufferFloat *getGradient(void) { return Gradient; } ///< Get pointer of gradient buffer @return Pointer to object
virtual int getWeights(float &values[]) { return Weights.GetData(values); } ///< Get values of weights matrix buffer @param[out] values Array of data @return number of items
virtual CBufferFloat *getWeights(void) { return Weights; } ///< Get pointer of gradient buffer @return Pointer to object
virtual int Neurons(void) { return Output.Total(); } ///< Get number of neurons in layer @return Number of neurons
virtual int Activation(void) { return (int)activation; } ///< Get type of activation function @return Type (#ENUM_ACTIVATION)
virtual int getConnections(void) { return (CheckPointer(Weights) != POINTER_INVALID ? Weights.Total() / (Gradient.Total()) : 0); } ///< Get number of connections 1 neuron to next layer @return Number of connections
virtual ENUM_OPTIMIZATION Optimization(void) { return optimization; }
//---
virtual bool FeedForward(CObject *SourceObject, CBufferFloat *SecondInput = NULL); ///< Dispatch method for defining the subroutine for feed forward process. @param SourceObject Pointer to the previous layer.
virtual bool calcHiddenGradients(CObject *TargetObject, CBufferFloat *SecondInput, CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = None); ///< Dispatch method for defining the subroutine for transferring the gradient to the previous layer. @param TargetObject Pointer to the next layer.
virtual bool UpdateInputWeights(CObject *SourceObject, CBufferFloat *SecondInput = NULL); ///< Dispatch method for defining the subroutine for updating weights.@param SourceObject Pointer to previos layer.
///\ingroup neuron_base_gr
///@{
virtual bool calcHiddenGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
virtual bool calcOutputGradients(CArrayFloat *Target, float &error); ///< Method of output gradients calculation by calling kernel ::CalcOutputGradient().@param Target Traget value
///@}
//---
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) const { return defNeuronBaseOCL; }///< Identificator of class.@return Type of class
virtual void TrainMode(bool flag) { bTrain = flag; } ///< Set Training Mode Flag
virtual bool TrainMode(void) { return bTrain; }///< Get Training Mode Flag
virtual CLayerDescription* GetLayerInfo(void);
virtual bool numOutputs(const uint outputs, ENUM_OPTIMIZATION optimization_type);
virtual void SetOpenCL(COpenCLMy *obj);
virtual CObject* AsObject(void) { return GetPointer(this); }
//---
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
//---
virtual bool Clear(void) {return true;}
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronBaseOCL::CNeuronBaseOCL(void) : alpha(momentum),
activation(TANH),
optimization(SGD),
t(1),
bTrain(true)
{
OpenCL = NULL;
Output = new CBufferFloat();
PrevOutput = new CBufferFloat();
Weights = new CBufferFloat();
DeltaWeights = new CBufferFloat();
Gradient = new CBufferFloat();
FirstMomentum = new CBufferFloat();
SecondMomentum = new CBufferFloat();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronBaseOCL::~CNeuronBaseOCL(void)
{
if(CheckPointer(Output) != POINTER_INVALID)
delete Output;
if(CheckPointer(PrevOutput) != POINTER_INVALID)
delete PrevOutput;
if(CheckPointer(Weights) != POINTER_INVALID)
delete Weights;
if(CheckPointer(DeltaWeights) != POINTER_INVALID)
delete DeltaWeights;
if(CheckPointer(Gradient) != POINTER_INVALID)
delete Gradient;
if(CheckPointer(FirstMomentum) != POINTER_INVALID)
delete FirstMomentum;
if(CheckPointer(SecondMomentum) != POINTER_INVALID)
delete SecondMomentum;
OpenCL = NULL;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(CheckPointer(open_cl) == POINTER_INVALID || numNeurons <= 0)
return false;
OpenCL = open_cl;
optimization = optimization_type;
iBatch = batch;
//---
if(CheckPointer(Output) == POINTER_INVALID)
{
Output = new CBufferFloat();
if(CheckPointer(Output) == POINTER_INVALID)
return false;
}
if(!Output.BufferInit(numNeurons, 1.0))
return false;
if(!Output.BufferCreate(OpenCL))
return false;
prev_output.Init(numNeurons);
//---
if(CheckPointer(PrevOutput) == POINTER_INVALID)
{
PrevOutput = new CBufferFloat();
if(CheckPointer(PrevOutput) == POINTER_INVALID)
return false;
}
if(!PrevOutput.BufferInit(numNeurons, 1.0))
return false;
if(!PrevOutput.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(Gradient) == POINTER_INVALID)
{
Gradient = new CBufferFloat();
if(CheckPointer(Gradient) == POINTER_INVALID)
return false;
}
if(!Gradient.BufferInit(numNeurons, 0.0))
return false;
if(!Gradient.BufferCreate(OpenCL))
return false;
//---
if(numOutputs > 0)
{
if(CheckPointer(Weights) == POINTER_INVALID)
{
Weights = new CBufferFloat();
if(CheckPointer(Weights) == POINTER_INVALID)
return false;
}
int count = (int)((numNeurons + 1) * numOutputs);
if(!Weights.Reserve(count))
return false;
float k = (float)(1 / sqrt(numNeurons + 1));
for(int i = 0; i < count; i++)
{
if(!Weights.Add((2 * GenerateWeight()*k - k)*WeightsMultiplier))
return false;
}
if(!Weights.BufferCreate(OpenCL))
return false;
//---
if(optimization == SGD)
{
if(CheckPointer(DeltaWeights) == POINTER_INVALID)
{
DeltaWeights = new CBufferFloat();
if(CheckPointer(DeltaWeights) == POINTER_INVALID)
return false;
}
if(!DeltaWeights.BufferInit(count, 0))
return false;
if(!DeltaWeights.BufferCreate(OpenCL))
return false;
if(CheckPointer(FirstMomentum) != POINTER_INVALID)
delete FirstMomentum;
if(CheckPointer(SecondMomentum) != POINTER_INVALID)
delete SecondMomentum;
}
else
{
if(CheckPointer(DeltaWeights) != POINTER_INVALID)
delete DeltaWeights;
//---
if(CheckPointer(FirstMomentum) == POINTER_INVALID)
{
FirstMomentum = new CBufferFloat();
if(CheckPointer(FirstMomentum) == POINTER_INVALID)
return false;
}
if(!FirstMomentum.BufferInit(count, 0))
return false;
if(!FirstMomentum.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(SecondMomentum) == POINTER_INVALID)
{
SecondMomentum = new CBufferFloat();
if(CheckPointer(SecondMomentum) == POINTER_INVALID)
return false;
}
if(!SecondMomentum.BufferInit(count, 0))
return false;
if(!SecondMomentum.BufferCreate(OpenCL))
return false;
}
}
else
{
if(CheckPointer(Weights) != POINTER_INVALID)
delete Weights;
if(CheckPointer(DeltaWeights) != POINTER_INVALID)
delete DeltaWeights;
if(CheckPointer(FirstMomentum) != POINTER_INVALID)
delete FirstMomentum;
if(CheckPointer(SecondMomentum) != POINTER_INVALID)
delete SecondMomentum;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::FeedForward(CObject *SourceObject, CBufferFloat *SecondInput = NULL)
{
if(CheckPointer(SourceObject) == POINTER_INVALID)
return false;
//---
CNeuronBaseOCL *temp = NULL;
if(Type() == defNeuronConcatenate)
{
temp = SourceObject;
return feedForward(temp, SecondInput);
}
if(Type() == defNeuronCrossAttenOCL)
{
temp = SourceObject;
return feedForward(temp, SecondInput);
}
switch(SourceObject.Type())
{
case defNeuronBaseOCL:
case defNeuronProofOCL:
case defNeuronConvOCL:
case defNeuronAttentionOCL:
case defNeuronMHAttentionOCL:
case defNeuronMH2AttentionOCL:
case defNeuronMLMHAttentionOCL:
case defNeuronMLMHSparseAttentionOCL:
case defNeuronDropoutOCL:
case defNeuronBatchNormOCL:
case defNeuronVAEOCL:
case defNeuronLSTMOCL:
case defNeuronSoftMaxOCL:
case defNeuronMultiModels:
case defNeuronFQF:
case defNeuronConcatenate:
case defNeuronSoftActorCritic:
case defNeuronEmbeddingOCL:
case defNeuronPEOCL:
case defNeuronTransposeOCL:
case defNeuronCGConvOCL:
case defNeuronMFTOCL:
case defNeuronXCiTOCL:
case defNeuronDOTOCL:
case defNeuronFAQOCL:
temp = SourceObject;
return feedForward(temp);
break;
}
//---
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Output.Total();
if(!OpenCL.SetArgumentBuffer(def_k_FeedForward, def_k_ff_matrix_w, NeuronOCL.getWeightsIndex()))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FeedForward, def_k_ff_matrix_i, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FeedForward, def_k_ff_matrix_o, Output.GetIndex()))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_FeedForward, def_k_ff_inputs, NeuronOCL.Neurons()))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_FeedForward, def_k_ff_activation, (int)activation))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_FeedForward, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel FeedForward: %d", GetLastError());
return false;
}
//---
//vector<float> temp;
//Output.GetData(temp);
//float delta = MathAbs(temp - prev_output).Sum();
//prev_output = temp;
//string error;
//CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::calcHiddenGradients(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Neurons();
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradient, def_k_chg_matrix_w, getWeightsIndex());
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradient, def_k_chg_matrix_g, NeuronOCL.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradient, def_k_chg_matrix_o, getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradient, def_k_chg_matrix_ig, getGradientIndex());
OpenCL.SetArgument(def_k_CalcHiddenGradient, def_k_chg_outputs, NeuronOCL.Neurons());
OpenCL.SetArgument(def_k_CalcHiddenGradient, def_k_chg_activation, Activation());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_CalcHiddenGradient, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel CalcHiddenGradient: %d", GetLastError());
return false;
}
//if(!Gradient.BufferRead())
// return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::calcOutputGradients(CArrayFloat *target, float &error)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(target) == POINTER_INVALID)
return false;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = target.Total();
for(uint i = 0; i < global_work_size[0]; i++)
if(!Gradient.Update(i, target.At(i)))
return false;
Gradient.BufferWrite();
OpenCL.SetArgumentBuffer(def_k_CalcOutputGradient, def_k_cog_matrix_t, getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_CalcOutputGradient, def_k_cog_matrix_o, getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_CalcOutputGradient, def_k_cog_matrix_ig, getGradientIndex());
OpenCL.SetArgument(def_k_CalcOutputGradient, def_k_cog_activation, (int)activation);
OpenCL.SetArgument(def_k_CalcOutputGradient, def_k_cog_error, error);
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_CalcOutputGradient, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel CalcOutputGradient: %d", GetLastError());
return false;
}
//Gradient.BufferRead();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = Neurons();
global_work_size[1] = NeuronOCL.Neurons() + 1;
uint rest = 0;
float lt = lr;
switch(NeuronOCL.Optimization())
{
case SGD:
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsMomentum, def_k_uwm_matrix_w, NeuronOCL.getWeightsIndex());
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsMomentum, def_k_uwm_matrix_g, getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsMomentum, def_k_uwm_matrix_i, NeuronOCL.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsMomentum, def_k_uwm_matrix_dw, NeuronOCL.getDeltaWeightsIndex());
OpenCL.SetArgument(def_k_UpdateWeightsMomentum, def_k_uwm_inputs, NeuronOCL.Neurons());
OpenCL.SetArgument(def_k_UpdateWeightsMomentum, def_k_uwm_learning_rates, lr);
OpenCL.SetArgument(def_k_UpdateWeightsMomentum, def_k_uwm_momentum, alpha);
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_UpdateWeightsMomentum, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateWeightsMomentum: %d", GetLastError());
return false;
}
break;
case ADAM:
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsAdam, def_k_uwa_matrix_w, NeuronOCL.getWeightsIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsAdam, def_k_uwa_matrix_g, getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsAdam, def_k_uwa_matrix_i, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsAdam, def_k_uwa_matrix_m, NeuronOCL.getFirstMomentumIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsAdam, def_k_uwa_matrix_v, NeuronOCL.getSecondMomentumIndex()))
return false;
lt = (float)(lr * sqrt(1 - pow(b2, (float)t)) / (1 - pow(b1, (float)t)));
if(!OpenCL.SetArgument(def_k_UpdateWeightsAdam, def_k_uwa_inputs, NeuronOCL.Neurons()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsAdam, def_k_uwa_l, lt))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsAdam, def_k_uwa_b1, b1))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsAdam, def_k_uwa_b2, b2))
return false;
global_work_size[1] = (global_work_size[1] + 3) / 4;
////Comment(com+"\n UpdateWeightsAdam");
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_UpdateWeightsAdam, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateWeightsAdam: %d", GetLastError());
return false;
}
t++;
break;
case LS:
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsLS, def_k_uwls_matrix_w, NeuronOCL.getWeightsIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsLS, def_k_uwls_matrix_g, getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsLS, def_k_uwls_matrix_i, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsLS, def_k_uwls_matrix_xg, NeuronOCL.getFirstMomentumIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsLS, def_k_uwls_matrix_xx, NeuronOCL.getSecondMomentumIndex()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsLS, def_k_uwls_inputs, NeuronOCL.Neurons()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsLS, def_k_uwls_l, lr))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsLS, def_k_uwls_update, (int)(t >= iBatch)))
return false;
rest = global_work_size[1] % 4;
global_work_size[1] = (global_work_size[1] - rest) / 4 + (rest > 0 ? 1 : 0);
////Comment(com+"\n UpdateWeightsAdam");
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_UpdateWeightsLS, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateWeightsLS: %d", GetLastError());
return false;
}
if(t >= iBatch)
t = 0;
else
t++;
break;
default:
return false;
break;
}
//---
return true;//NeuronOCL.Weights.BufferRead();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::calcHiddenGradients(CObject *TargetObject, CBufferFloat *SecondInput, CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = None)
{
//---
if(CheckPointer(TargetObject) == POINTER_INVALID)
return false;
//---
CNeuronBaseOCL *temp = NULL;
CNeuronAttentionOCL *at = NULL;
CNeuronMH2AttentionOCL *mh2at = NULL;
CNeuronMLMHAttentionOCL *mlat = NULL;
CNeuronProofOCL *conv = NULL;
CNeuronDropoutOCL *dropout = NULL;
CNeuronBatchNormOCL *batch = NULL;
CVAE *vae = NULL;
CNeuronLSTMOCL *lstm = NULL;
CNeuronSoftMaxOCL* softmax = NULL;
CNeuronFQF* fqf = NULL;
CNeuronMultiModel *multi_model = NULL;
CNeuronConcatenate *concat = NULL;
CNeuronEmbeddingOCL *embed = NULL;
CNeuronPositionEncoder *pe = NULL;
CNeuronTransposeOCL *tr = NULL;
CNeuronCGConvOCL *cgc = NULL;
CNeuronDOTOCL *dot = NULL;
CNeuronFAQOCL *faq = NULL;
CNeuronCrossAttention *cross = NULL;
switch(TargetObject.Type())
{
case defNeuronBaseOCL:
temp = TargetObject;
return calcHiddenGradients(temp);
case defNeuronConvOCL:
case defNeuronProofOCL:
conv = TargetObject;
temp = GetPointer(this);
return conv.calcInputGradients(temp);
case defNeuronAttentionOCL:
case defNeuronMHAttentionOCL:
at = TargetObject;
temp = GetPointer(this);
return at.calcInputGradients(temp);
case defNeuronMH2AttentionOCL:
mh2at = TargetObject;
temp = GetPointer(this);
return mh2at.calcInputGradients(temp);
case defNeuronMLMHAttentionOCL:
case defNeuronMLMHSparseAttentionOCL:
case defNeuronMFTOCL:
case defNeuronXCiTOCL:
mlat = TargetObject;
temp = GetPointer(this);
return mlat.calcInputGradients(temp);
case defNeuronDropoutOCL:
dropout = TargetObject;
temp = GetPointer(this);
return dropout.calcInputGradients(temp);
case defNeuronBatchNormOCL:
batch = TargetObject;
temp = GetPointer(this);
return batch.calcInputGradients(temp);
case defNeuronVAEOCL:
vae = TargetObject;
temp = GetPointer(this);
return vae.calcInputGradients(temp);
case defNeuronLSTMOCL:
lstm = TargetObject;
temp = GetPointer(this);
return lstm.calcInputGradients(temp);
case defNeuronSoftMaxOCL:
softmax = TargetObject;
temp = GetPointer(this);
return softmax.calcInputGradients(temp);
case defNeuronFQF:
case defNeuronSoftActorCritic:
fqf = TargetObject;
temp = GetPointer(this);
return fqf.calcInputGradients(temp);
case defNeuronMultiModels:
multi_model = TargetObject;
return multi_model.calcHiddenGradients(GetPointer(this));
case defNeuronConcatenate:
concat = TargetObject;
temp = GetPointer(this);
return concat.calcHiddenGradients(temp, SecondInput, SecondGradient, SecondActivation);
case defNeuronEmbeddingOCL:
embed = TargetObject;
temp = GetPointer(this);
return embed.calcInputGradients(temp);
case defNeuronPEOCL:
pe = TargetObject;
temp = GetPointer(this);
return pe.calcInputGradients(temp);
case defNeuronTransposeOCL:
tr = TargetObject;
temp = GetPointer(this);
return tr.calcInputGradients(temp);
case defNeuronCGConvOCL:
cgc = TargetObject;
temp = GetPointer(this);
return cgc.calcInputGradients(temp);
case defNeuronDOTOCL:
dot = TargetObject;
temp = GetPointer(this);
return dot.calcInputGradients(temp);
case defNeuronFAQOCL:
faq = TargetObject;
temp = GetPointer(this);
return faq.calcInputGradients(temp);
case defNeuronCrossAttenOCL:
cross = TargetObject;
temp = GetPointer(this);
return cross.calcInputGradients(temp, SecondInput, SecondGradient, SecondActivation);
}
//---
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::UpdateInputWeights(CObject *SourceObject, CBufferFloat *SecondInput = NULL)
{
//---
if(CheckPointer(SourceObject) == POINTER_INVALID)
return false;
//---
CNeuronBaseOCL *temp = SourceObject;
if(!bTrain && !temp.TrainMode())
return true;
if(Type() == defNeuronConcatenate)
{
CNeuronConcatenate *concat = GetPointer(this);
return concat.updateInputWeights(temp, SecondInput);
}
if(Type() == defNeuronCrossAttenOCL)
{
CNeuronCrossAttention *cross = GetPointer(this);
return cross.updateInputWeights(temp, SecondInput);
}
switch(SourceObject.Type())
{
case defNeuronBaseOCL:
case defNeuronConvOCL:
case defNeuronProofOCL:
case defNeuronAttentionOCL:
case defNeuronMHAttentionOCL:
case defNeuronMH2AttentionOCL:
case defNeuronMLMHAttentionOCL:
case defNeuronMLMHSparseAttentionOCL:
case defNeuronDropoutOCL:
case defNeuronBatchNormOCL:
case defNeuronVAEOCL:
case defNeuronLSTMOCL:
case defNeuronFQF:
case defNeuronMultiModels:
case defNeuronConcatenate:
case defNeuronSoftActorCritic:
case defNeuronEmbeddingOCL:
case defNeuronPEOCL:
case defNeuronTransposeOCL:
case defNeuronCGConvOCL:
case defNeuronMFTOCL:
case defNeuronXCiTOCL:
case defNeuronDOTOCL:
case defNeuronFAQOCL:
return updateInputWeights(temp);
case defNeuronSoftMaxOCL:
return true;
}
//---
return false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::Save(const int file_handle)
{
if(file_handle == INVALID_HANDLE)
return false;
if(FileWriteInteger(file_handle, Type()) < INT_VALUE)
return false;
//---
if(FileWriteInteger(file_handle, (int)activation, INT_VALUE) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)optimization, INT_VALUE) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iBatch, INT_VALUE) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)t, INT_VALUE) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)bTrain, INT_VALUE) < INT_VALUE)
return false;
//---
if(CheckPointer(Output) == POINTER_INVALID || !Output.Save(file_handle))
return false;
if(CheckPointer(PrevOutput) == POINTER_INVALID || !PrevOutput.Save(file_handle))
return false;
if(CheckPointer(Gradient) == POINTER_INVALID || !Gradient.Save(file_handle))
return false;
//---
if(CheckPointer(Weights) == POINTER_INVALID)
{
FileWriteInteger(file_handle, 0);
return true;
}
else
FileWriteInteger(file_handle, 1);
//---
if(CheckPointer(Weights) == POINTER_INVALID || !Weights.Save(file_handle))
return false;
if(optimization == SGD)
{
if(CheckPointer(DeltaWeights) == POINTER_INVALID || !DeltaWeights.Save(file_handle))
return false;
}
else
{
if(CheckPointer(FirstMomentum) == POINTER_INVALID || !FirstMomentum.Save(file_handle))
return false;
if(CheckPointer(SecondMomentum) == POINTER_INVALID || !SecondMomentum.Save(file_handle))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::Load(const int file_handle)
{
if(file_handle == INVALID_HANDLE)
return false;
//---
activation = (ENUM_ACTIVATION)FileReadInteger(file_handle, INT_VALUE);
optimization = (ENUM_OPTIMIZATION)FileReadInteger(file_handle, INT_VALUE);
iBatch = (uint)FileReadInteger(file_handle, INT_VALUE);
t = (uint)FileReadInteger(file_handle, INT_VALUE);
bTrain = (bool)FileReadInteger(file_handle, INT_VALUE);
if(CheckPointer(Output) == POINTER_INVALID)
{
Output = new CBufferFloat();
if(CheckPointer(Output) == POINTER_INVALID)
return false;
}
if(Output.GetIndex() >= 0)
Output.BufferFree();
if(!Output.Load(file_handle))
return false;
if(Output.Total() > 0 && !Output.BufferCreate(OpenCL))
return false;
prev_output.Init(Output.Total());
//---
if(CheckPointer(PrevOutput) == POINTER_INVALID)
{
PrevOutput = new CBufferFloat();
if(CheckPointer(PrevOutput) == POINTER_INVALID)
return false;
}
if(PrevOutput.GetIndex() >= 0)
PrevOutput.BufferFree();
if(!PrevOutput.Load(file_handle))
return false;
if(PrevOutput.Total() > 0 && !PrevOutput.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(Gradient) == POINTER_INVALID)
{
Gradient = new CBufferFloat();
if(CheckPointer(Gradient) == POINTER_INVALID)
return false;
}
if(Gradient.GetIndex() >= 0)
Gradient.BufferFree();
if(!Gradient.Load(file_handle))
return false;
if(Gradient.Total() > 0 && !Gradient.BufferCreate(OpenCL))
return false;
//---
if(FileReadInteger(file_handle) == 0)
return true;
//---
if(CheckPointer(Weights) == POINTER_INVALID)
{
Weights = new CBufferFloat();
if(CheckPointer(Weights) == POINTER_INVALID)
return false;
}
if(Weights.GetIndex() >= 0)
Weights.BufferFree();
if(!Weights.Load(file_handle))
return false;
if(Weights.Total() > 0 && !Weights.BufferCreate(OpenCL))
return false;
//---
if(optimization == SGD)
{
if(CheckPointer(DeltaWeights) == POINTER_INVALID)
{
DeltaWeights = new CBufferFloat();
if(CheckPointer(DeltaWeights) == POINTER_INVALID)
return false;
}
if(DeltaWeights.GetIndex() >= 0)
DeltaWeights.BufferFree();
if(!DeltaWeights.Load(file_handle))
return false;
if(DeltaWeights.Total() > 0 && !DeltaWeights.BufferCreate(OpenCL))
return false;
}
else
{
if(CheckPointer(FirstMomentum) == POINTER_INVALID)
{
FirstMomentum = new CBufferFloat();
if(CheckPointer(FirstMomentum) == POINTER_INVALID)
return false;
}
if(FirstMomentum.GetIndex() >= 0)
FirstMomentum.BufferFree();
if(!FirstMomentum.Load(file_handle))
return false;
if(FirstMomentum.Total() > 0 && !FirstMomentum.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(SecondMomentum) == POINTER_INVALID)
{
SecondMomentum = new CBufferFloat();
if(CheckPointer(SecondMomentum) == POINTER_INVALID)
return false;
}
if(SecondMomentum.GetIndex() >= 0)
SecondMomentum.BufferFree();
if(!SecondMomentum.Load(file_handle))
return false;
if(SecondMomentum.Total() > 0 && !SecondMomentum.BufferCreate(OpenCL))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronBaseOCL::GetLayerInfo(void)
{
CLayerDescription* result = new CLayerDescription();
if(!result)
return result;
//---
result.type = Type();
result.count = Output.Total();
result.optimization = optimization;
result.activation = activation;
result.batch = (int)(optimization == LS ? iBatch : 1);
result.layers = 1;
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::numOutputs(const uint outputs, ENUM_OPTIMIZATION optimization_type)
{
if(outputs > 0)
{
if(CheckPointer(Weights) == POINTER_INVALID)
{
Weights = new CBufferFloat();
if(CheckPointer(Weights) == POINTER_INVALID)
return false;
}
Weights.BufferFree();
Weights.Clear();
int count = (int)((Output.Total() + 1) * outputs);
if(!Weights.Reserve(count))
return false;
float k = (float)(1 / sqrt(Output.Total() + 1));
for(int i = 0; i < count; i++)
{
if(!Weights.Add((2 * GenerateWeight()*k - k)*WeightsMultiplier))
return false;
}
if(!Weights.BufferCreate(OpenCL))
return false;
//---
if(optimization_type == SGD)
{
if(CheckPointer(DeltaWeights) == POINTER_INVALID)
{
DeltaWeights = new CBufferFloat();
if(CheckPointer(DeltaWeights) == POINTER_INVALID)
return false;
}
DeltaWeights.BufferFree();
if(!DeltaWeights.BufferInit(count, 0))
return false;
if(!DeltaWeights.BufferCreate(OpenCL))
return false;
if(CheckPointer(FirstMomentum) != POINTER_INVALID)
{
FirstMomentum.BufferFree();
delete FirstMomentum;
}
if(CheckPointer(SecondMomentum) != POINTER_INVALID)
{
SecondMomentum.BufferFree();
delete SecondMomentum;
}
}
else
{
if(CheckPointer(DeltaWeights) != POINTER_INVALID)
{
DeltaWeights.BufferFree();
delete DeltaWeights;
}
//---
if(CheckPointer(FirstMomentum) == POINTER_INVALID)
{
FirstMomentum = new CBufferFloat();
if(CheckPointer(FirstMomentum) == POINTER_INVALID)
return false;
}
FirstMomentum.BufferFree();
if(!FirstMomentum.BufferInit(count, 0))
return false;
if(!FirstMomentum.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(SecondMomentum) == POINTER_INVALID)
{
SecondMomentum = new CBufferFloat();
if(CheckPointer(SecondMomentum) == POINTER_INVALID)
return false;
}
SecondMomentum.BufferFree();
if(!SecondMomentum.BufferInit(count, 0))
return false;
if(!SecondMomentum.BufferCreate(OpenCL))
return false;
}
}
else
{
if(CheckPointer(Weights) != POINTER_INVALID)
{
Weights.BufferFree();
delete Weights;
}
if(CheckPointer(DeltaWeights) != POINTER_INVALID)
{
DeltaWeights.BufferFree();
delete DeltaWeights;
}
if(CheckPointer(FirstMomentum) != POINTER_INVALID)
{
FirstMomentum.BufferFree();
delete FirstMomentum;
}
if(CheckPointer(SecondMomentum) != POINTER_INVALID)
{
SecondMomentum.BufferFree();
delete SecondMomentum;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronBaseOCL::SetOpenCL(COpenCLMy *obj)
{
if(OpenCL == obj)
return;
if(!!OpenCL)
delete OpenCL;
if(!obj)
return;
OpenCL = obj;
if(!!Output)
Output.BufferCreate(OpenCL); ///< Buffer of Output tensor
if(!!PrevOutput)
PrevOutput.BufferCreate(OpenCL); ///< Buffer of previous iteration Output tensor
if(!!Weights)
Weights.BufferCreate(OpenCL); ///< Buffer of weights matrix
if(!!DeltaWeights)
DeltaWeights.BufferCreate(OpenCL); ///< Buffer of last delta weights matrix (#SGD)
if(!!Gradient)
Gradient.BufferCreate(OpenCL); ///< Buffer of gradient tensor
if(!!FirstMomentum)
FirstMomentum.BufferCreate(OpenCL); ///< Buffer of first momentum matrix (#ADAM)
if(!!SecondMomentum)
SecondMomentum.BufferCreate(OpenCL); ///< Buffer of second momentum matrix (#ADAM)
}
//+------------------------------------------------------------------+
///\class CNeuronProofOCL
/// Class of pooling layer GPU calculation
//+------------------------------------------------------------------+
class CNeuronProofOCL : public CNeuronBaseOCL
{
protected:
uint iWindow; ///< Input window size
uint iStep; ///< Size of step
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< Feed Forward method.@param NeuronOCL Pointer to previos layer.
public:
/** Constructor */
CNeuronProofOCL(void) : iWindow(2), iStep(1) {};
/** Destructor */~CNeuronProofOCL(void);
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, int window, int step, int units_count, ENUM_OPTIMIZATION optimization_type, uint batch);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object.@param[in] window Size of input window @param[in] step Step size.@param[in] units_countNumber of neurons.@param[in] optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
//---
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradients to previous layer @param[in] NeuronOCL Pointer to previous layer.
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) { return true;}; ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
//--- methods for working with files
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
virtual int Type(void) const { return defNeuronProofOCL; }///< Identificator of class.@return Type of class
virtual CLayerDescription* GetLayerInfo(void);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProofOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, int window, int step, int units_count, ENUM_OPTIMIZATION optimization_type, uint batch)
{
iWindow = window;
iStep = step;
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, units_count, optimization_type, batch))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronProofOCL::~CNeuronProofOCL(void)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProofOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Output.Total();
OpenCL.SetArgumentBuffer(def_k_FeedForwardProof, def_k_ffp_matrix_i, NeuronOCL.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FeedForwardProof, def_k_ffp_matrix_o, Output.GetIndex());
OpenCL.SetArgument(def_k_FeedForwardProof, def_k_ffp_inputs, NeuronOCL.Neurons());
OpenCL.SetArgument(def_k_FeedForwardProof, def_k_ffp_window, (int)iWindow);
OpenCL.SetArgument(def_k_FeedForwardProof, def_k_ffp_step, (int)iStep);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_FeedForwardProof, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel FeedForwardProof: %d", GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProofOCL::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = NeuronOCL.Neurons();
OpenCL.SetArgumentBuffer(def_k_CalcInputGradientProof, def_k_cigp_matrix_i, NeuronOCL.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_CalcInputGradientProof, def_k_cigp_matrix_o, Output.GetIndex());
OpenCL.SetArgumentBuffer(def_k_CalcInputGradientProof, def_k_cigp_matrix_g, Gradient.GetIndex());
OpenCL.SetArgumentBuffer(def_k_CalcInputGradientProof, def_k_cigp_matrix_ig, NeuronOCL.getGradientIndex());
OpenCL.SetArgument(def_k_CalcInputGradientProof, def_k_cigp_outputs, Output.Total());
OpenCL.SetArgument(def_k_CalcInputGradientProof, def_k_cigp_window, (int)iWindow);
OpenCL.SetArgument(def_k_CalcInputGradientProof, def_k_cigp_step, (int)iStep);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_CalcInputGradientProof, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel CalcInputGradientProof: %d", GetLastError());
return false;
}
//NeuronOCL.getGradient().BufferRead();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronProofOCL::GetLayerInfo(void)
{
CLayerDescription *result = CNeuronBaseOCL::GetLayerInfo();
if(!result)
return result;
result.window = (int)iWindow;
result.step = (int)iStep;
//---
return result;
}
//+------------------------------------------------------------------+
///\class CNeuronConvOCL
/// Class of convolution layer GPU calculation
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8765#para41">the link.</A>
//+------------------------------------------------------------------+
class CNeuronConvOCL : public CNeuronProofOCL
{
protected:
uint iWindowOut; ///< Size of out window
//---
CBufferFloat *WeightsConv; ///< Matrix of weights to previous layer
CBufferFloat *DeltaWeightsConv; ///< Matrix of delta weights to previous layer (#SGD)
CBufferFloat *FirstMomentumConv; ///< Matrix of first momentum to previous layer (#ADAM)
CBufferFloat *SecondMomentumConv; ///< Matrix of second momentum to previous layer (#ADAM)
//---
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< Feed Forward method.@param NeuronOCL Pointer to previos layer.
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL); ///< Method for updating weights.@param NeuronOCL Pointer to previos layer.
public:
/** Constructor */
CNeuronConvOCL(void) : iWindowOut(1) { activation = LReLU; }
/** Destructor */~CNeuronConvOCL(void);
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint step, uint window_out, uint units_count, ENUM_OPTIMIZATION optimization_type, uint batch);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object.@param[in] window Size of input window @param[in] step Step size.@param[in] window_out Size of output window @param[in] units_countNumber of neurons.@param[in] optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
//---
virtual CBufferFloat* GetWeightsConv(void) { return WeightsConv; }
//---
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradients to previous layer @param[in] NeuronOCL Pointer to previous layer.
virtual int Type(void) const { return defNeuronConvOCL; }///< Identificator of class.@return Type of class
//--- methods for working with files
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual CLayerDescription* GetLayerInfo(void);
virtual void SetOpenCL(COpenCLMy *obj);
//---
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronConvOCL::~CNeuronConvOCL(void)
{
if(CheckPointer(WeightsConv) != POINTER_INVALID)
delete WeightsConv;
if(CheckPointer(DeltaWeightsConv) != POINTER_INVALID)
delete DeltaWeightsConv;
if(CheckPointer(FirstMomentumConv) != POINTER_INVALID)
delete FirstMomentumConv;
if(CheckPointer(SecondMomentumConv) != POINTER_INVALID)
delete SecondMomentumConv;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConvOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window_in, uint step, uint window_out, uint units_count, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(window_out <= 0 || (optimization == LS && batch <= 0))
return false;
if(!CNeuronProofOCL::Init(numOutputs, myIndex, open_cl, window_in, step, units_count * window_out, optimization_type, batch))
return false;
//---
iWindowOut = fmax(window_out, 1);
//---
if(CheckPointer(WeightsConv) == POINTER_INVALID)
{
WeightsConv = new CBufferFloat();
if(CheckPointer(WeightsConv) == POINTER_INVALID)
return false;
}
int count = (int)((iWindow + 1) * iWindowOut);
if(!WeightsConv.Reserve(count))
return false;
float k = (float)(1 / sqrt(iWindow + 1));
for(int i = 0; i < count; i++)
{
if(!WeightsConv.Add((GenerateWeight() * 2 * k - k)*WeightsMultiplier))
return false;
}
if(!WeightsConv.BufferCreate(OpenCL))
return false;
//---
if(optimization == SGD)
{
if(CheckPointer(DeltaWeightsConv) == POINTER_INVALID)
{
DeltaWeightsConv = new CBufferFloat();
if(CheckPointer(DeltaWeightsConv) == POINTER_INVALID)
return false;
}
if(!DeltaWeightsConv.BufferInit(count, 0.0))
return false;
if(!DeltaWeightsConv.BufferCreate(OpenCL))
return false;
}
else
{
if(CheckPointer(FirstMomentumConv) == POINTER_INVALID)
{
FirstMomentumConv = new CBufferFloat();
if(CheckPointer(FirstMomentumConv) == POINTER_INVALID)
return false;
}
if(!FirstMomentumConv.BufferInit(count, 0.0))
return false;
if(!FirstMomentumConv.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(SecondMomentumConv) == POINTER_INVALID)
{
SecondMomentumConv = new CBufferFloat();
if(CheckPointer(SecondMomentumConv) == POINTER_INVALID)
return false;
}
if(!SecondMomentumConv.BufferInit(count, 0.0))
return false;
if(!SecondMomentumConv.BufferCreate(OpenCL))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConvOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Output.Total() / iWindowOut;
OpenCL.SetArgumentBuffer(def_k_FeedForwardConv, def_k_ffc_matrix_w, WeightsConv.GetIndex());
OpenCL.SetArgumentBuffer(def_k_FeedForwardConv, def_k_ffc_matrix_i, NeuronOCL.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FeedForwardConv, def_k_ffc_matrix_o, Output.GetIndex());
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffc_inputs, NeuronOCL.Neurons());
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffc_step, (int)iStep);
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffc_window_in, (int)iWindow);
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffс_window_out, (int)iWindowOut);
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffc_activation, (int)activation);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_FeedForwardConv, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel FeedForwardConv: %d", GetLastError());
return false;
}
//vector<float> temp;
//Output.GetData(temp);
//float delta = MathAbs((temp - prev_output)).Sum();
//prev_output = temp;
//string error;
//CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConvOCL::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = NeuronOCL.Neurons();
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientConv, def_k_chgc_matrix_w, WeightsConv.GetIndex());
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientConv, def_k_chgc_matrix_g, Gradient.GetIndex());
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientConv, def_k_chgc_matrix_o, NeuronOCL.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientConv, def_k_chgc_matrix_ig, NeuronOCL.getGradientIndex());
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_outputs, Neurons());
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_step, (int)iStep);
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_window_in, (int)iWindow);
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_window_out, (int)iWindowOut);
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_activation, (int)NeuronOCL.Activation());
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_shift_out, (int)0);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_CalcHiddenGradientConv, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel CalcHiddenGradientConv: %d", GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConvOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = WeightsConv.Total();
float lt = 0;
switch(optimization)
{
case SGD:
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvMomentum, def_k_uwcm_matrix_w, WeightsConv.GetIndex());
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvMomentum, def_k_uwcm_matrix_g, getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvMomentum, def_k_uwcm_matrix_i, NeuronOCL.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvMomentum, def_k_uwcm_matrix_dw, DeltaWeightsConv.GetIndex());
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_inputs, NeuronOCL.Neurons());
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_learning_rates, lr);
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_momentum, alpha);
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_window_in, (int)iWindow);
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_window_out, (int)iWindowOut);
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_step, (int)iStep);
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_UpdateWeightsConvMomentum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateWeightsConvMomentum: %d", GetLastError());
return false;
}
break;
case ADAM:
global_work_size[0] = iWindow + 1;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_w, WeightsConv.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_g, getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_i, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_m, FirstMomentumConv.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_v, SecondMomentumConv.GetIndex()))
return false;
lt = (float)(lr * sqrt(1 - pow(b2, t)) / (1 - pow(b1, t)));
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwa_inputs, NeuronOCL.Neurons()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_l, lt))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_b1, b1))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_b2, b2))
return false;
OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_window_in, (int)iWindow);
OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_window_out, (int)iWindowOut);
OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_step, (int)iStep);
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_UpdateWeightsConvAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateWeightsConvAdam: %d", GetLastError());
return false;
}
t++;
break;
case LS:
global_work_size[0] = iWindow + 1;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvLS, def_k_uwcls_matrix_w, WeightsConv.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvLS, def_k_uwcls_matrix_g, getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvLS, def_k_uwcls_matrix_i, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvLS, def_k_uwcls_matrix_xg, FirstMomentumConv.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvLS, def_k_uwcls_matrix_xx, SecondMomentumConv.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvLS, def_k_uwls_inputs, NeuronOCL.Neurons()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvLS, def_k_uwcls_l, lr))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvLS, def_k_uwcls_update, (int)(t >= iBatch)))
return false;
OpenCL.SetArgument(def_k_UpdateWeightsConvLS, def_k_uwcls_window_in, (int)iWindow);
OpenCL.SetArgument(def_k_UpdateWeightsConvLS, def_k_uwcls_window_out, (int)iWindowOut);
OpenCL.SetArgument(def_k_UpdateWeightsConvLS, def_k_uwcls_step, (int)iStep);
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_UpdateWeightsConvLS, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateWeightsConvLS: %d", GetLastError());
return false;
}
if(t >= iBatch)
t = 0;
else
t++;
break;
default:
return false;
break;
}
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronConvOCL::GetLayerInfo(void)
{
CLayerDescription *result = CNeuronProofOCL::GetLayerInfo();
if(!result)
return result;
result.window_out = (int)iWindowOut;
result.count /= (int)iWindowOut;
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronConvOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
if(!!WeightsConv)
WeightsConv.BufferCreate(obj); ///< Matrix of weights to previous layer
if(!!DeltaWeightsConv)
DeltaWeightsConv.BufferCreate(obj); ///< Matrix of delta weights to previous layer (#SGD)
if(!!FirstMomentumConv)
FirstMomentumConv.BufferCreate(obj); ///< Matrix of first momentum to previous layer (#ADAM)
if(!!SecondMomentumConv)
SecondMomentumConv.BufferCreate(obj); ///< Matrix of second momentum to previous layer (#ADAM)
}
//+------------------------------------------------------------------+
///\class CNeuronAttentionOCL
/// Class of Self-Attention layer GPU calculation
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8765#para42">the link.</A>
//+------------------------------------------------------------------+
class CNeuronAttentionOCL : public CNeuronBaseOCL
{
protected:
CNeuronConvOCL *Querys; ///< Convolution layer for Querys
CNeuronConvOCL *Keys; ///< Convolution layer for Keys
CNeuronConvOCL *Values; ///< Convolution layer for Values
CBufferFloat *Scores; ///< Buffer for Scores matrix
CNeuronBaseOCL *AttentionOut; ///< Layer of Self-Attention Out
CNeuronConvOCL *FF1; ///< Convolution layer for first layer of Feed Forward block
CNeuronConvOCL *FF2; ///< Convolution layer for second layer of Feed Forward block
//---
uint iWindow; ///< Window size
uint iUnits; ///< Number of units
//---
virtual bool feedForward(CNeuronBaseOCL *prevLayer); ///< Feed Forward method.@param prevLayer Pointer to previos layer.
virtual bool updateInputWeights(CNeuronBaseOCL *prevLayer); ///< Method for updating weights.@param prevLayer Pointer to previos layer.
public:
/** Constructor */
CNeuronAttentionOCL(void) : iWindow(1), iUnits(0) {};
/** Destructor */~CNeuronAttentionOCL(void);
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint units_count, ENUM_OPTIMIZATION optimization_type, uint batch);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object.@param[in] window Size of in/out window and step.@param[in] units_countNumber of neurons.@param[in] optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer); ///< Method to transfer gradients to previous layer @param[in] prevLayer Pointer to previous layer.
//---
virtual int Type(void) const { return defNeuronAttentionOCL; }///< Identificator of class.@return Type of class
//--- methods for working with files
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
virtual CLayerDescription* GetLayerInfo(void);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronAttentionOCL::~CNeuronAttentionOCL(void)
{
if(CheckPointer(Querys) != POINTER_INVALID)
delete Querys;
if(CheckPointer(Keys) != POINTER_INVALID)
delete Keys;
if(CheckPointer(Values) != POINTER_INVALID)
delete Values;
if(CheckPointer(Scores) != POINTER_INVALID)
delete Scores;
if(CheckPointer(AttentionOut) != POINTER_INVALID)
delete AttentionOut;
if(CheckPointer(FF1) != POINTER_INVALID)
delete FF1;
if(CheckPointer(FF2) != POINTER_INVALID)
delete FF2;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronAttentionOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint units_count, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, units_count * window, optimization_type, batch))
return false;
//---
if(CheckPointer(Querys) == POINTER_INVALID)
{
Querys = new CNeuronConvOCL();
if(CheckPointer(Querys) == POINTER_INVALID)
return false;
if(!Querys.Init(0, 0, open_cl, window, window, window, units_count, optimization_type, batch))
return false;
Querys.SetActivationFunction(None);
}
//---
//if(CheckPointer(Keys)==POINTER_INVALID)
// {
// Keys=new CNeuronConvOCL();
// if(CheckPointer(Keys)==POINTER_INVALID)
// return false;
// if(!Keys.Init(0,1,open_cl,window,window,window,units_count,optimization_type))
// return false;
// Keys.SetActivationFunction(None);
// }
//---
if(CheckPointer(Values) == POINTER_INVALID)
{
Values = new CNeuronConvOCL();
if(CheckPointer(Values) == POINTER_INVALID)
return false;
if(!Values.Init(0, 2, open_cl, window, window, window, units_count, optimization_type, batch))
return false;
Values.SetActivationFunction(None);
}
//---
if(CheckPointer(Scores) == POINTER_INVALID)
{
Scores = new CBufferFloat();
if(CheckPointer(Scores) == POINTER_INVALID)
return false;
}
if(!Scores.BufferInit(units_count * units_count, 0.0))
return false;
if(!Scores.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(AttentionOut) == POINTER_INVALID)
{
AttentionOut = new CNeuronBaseOCL();
if(CheckPointer(AttentionOut) == POINTER_INVALID)
return false;
if(!AttentionOut.Init(0, 3, open_cl, window * units_count, optimization_type, batch))
return false;
AttentionOut.SetActivationFunction(None);
}
//---
if(CheckPointer(FF1) == POINTER_INVALID)
{
FF1 = new CNeuronConvOCL();
if(CheckPointer(FF1) == POINTER_INVALID)
return false;
if(!FF1.Init(0, 4, open_cl, window, window, window * 4, units_count, optimization_type, batch))
return false;
FF1.SetActivationFunction(LReLU);
}
//---
if(CheckPointer(FF2) == POINTER_INVALID)
{
FF2 = new CNeuronConvOCL();
if(CheckPointer(FF2) == POINTER_INVALID)
return false;
if(!FF2.Init(0, 5, open_cl, window * 4, window * 4, window, units_count, optimization_type, batch))
return false;
FF2.SetActivationFunction(None);
FF2.SetGradientIndex(Gradient.GetIndex());
}
//---
iWindow = window;
iUnits = units_count;
activation = (ENUM_ACTIVATION)FF2.Activation();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronAttentionOCL::feedForward(CNeuronBaseOCL *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = 1;
OpenCL.SetArgumentBuffer(def_k_Normilize, def_k_norm_buffer, prevLayer.getOutputIndex());
OpenCL.SetArgument(def_k_Normilize, def_k_norm_dimension, prevLayer.Neurons());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_Normilize, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Normalize: %d", GetLastError());
return false;
}
//if(!prevLayer.Output.BufferRead())
// return false;
}
//---
if(CheckPointer(Querys) == POINTER_INVALID || !Querys.FeedForward(prevLayer))
return false;
//if(CheckPointer(Keys)==POINTER_INVALID || !Keys.FeedForward(prevLayer))
// return false;
if(CheckPointer(Values) == POINTER_INVALID || !Values.FeedForward(prevLayer))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_querys, Querys.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_keys, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_score, Scores.GetIndex());
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_mask, 0);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionScore, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel AttentionScore: %d", GetLastError());
return false;
}
//if(!Scores.BufferRead())
// return false;
}
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iWindow;
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_scores, Scores.GetIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_inputs, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_values, Values.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_out, AttentionOut.getOutputIndex());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionOut, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel Attention Out: %d", GetLastError());
return false;
}
//float temp[];
//if(!AttentionOut.getOutputVal(temp))
// return false;
}
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = 1;
OpenCL.SetArgumentBuffer(def_k_Normilize, def_k_norm_buffer, AttentionOut.getOutputIndex());
OpenCL.SetArgument(def_k_Normilize, def_k_norm_dimension, AttentionOut.Neurons());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_Normilize, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Normalize: %d", GetLastError());
return false;
}
//float temp[];
//if(!AttentionOut.getOutputVal(temp))
// return false;
}
//---
if(!FF1.FeedForward(AttentionOut))
return false;
if(!FF2.FeedForward(FF1))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, AttentionOut.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, FF2.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, Output.GetIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 0.5f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
//if(!Output.BufferRead())
// return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronAttentionOCL::calcInputGradients(CNeuronBaseOCL *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
if(!FF2.calcInputGradients(FF1))
return false;
if(!FF1.calcInputGradients(AttentionOut))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, AttentionOut.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, Gradient.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, AttentionOut.getGradientIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 0.5f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
float temp[];
if(AttentionOut.getGradient(temp) <= 0)
return false;
}
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iWindow;
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_gradient, AttentionOut.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_keys, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_keys_g, prevLayer.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_querys, Querys.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_querys_g, Querys.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_values, Values.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_values_g, Values.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_scores, Scores.GetIndex());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionGradients, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel AttentionGradients: %d", GetLastError());
return false;
}
float temp[];
if(Querys.getGradient(temp) <= 0)
return false;
}
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, AttentionOut.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, prevLayer.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, AttentionOut.getGradientIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 1.0f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
float temp[];
if(AttentionOut.getGradient(temp) <= 0)
return false;
}
//---
if(!Querys.calcInputGradients(prevLayer))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, AttentionOut.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, prevLayer.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, AttentionOut.getGradientIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 1.0f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
float temp[];
if(AttentionOut.getGradient(temp) <= 0)
return false;
}
//---
if(!Values.calcInputGradients(prevLayer))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, AttentionOut.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, prevLayer.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, prevLayer.getGradientIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)(iWindow + 1));
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 0.1f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
float temp[];
if(prevLayer.getGradient(temp) <= 0)
return false;
}
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = 1;
OpenCL.SetArgumentBuffer(def_k_Normilize, def_k_norm_buffer, prevLayer.getGradientIndex());
OpenCL.SetArgument(def_k_Normilize, def_k_norm_dimension, prevLayer.Neurons());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_Normilize, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Normalize: %d", GetLastError());
return false;
}
float temp[];
if(prevLayer.getGradient(temp) <= 0)
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronAttentionOCL::updateInputWeights(CNeuronBaseOCL *prevLayer)
{
if(!Querys.UpdateInputWeights(prevLayer))
return false;
//if(!Keys.UpdateInputWeights(prevLayer))
// return false;
if(!Values.UpdateInputWeights(prevLayer))
return false;
if(!FF1.UpdateInputWeights(AttentionOut))
return false;
if(!FF2.UpdateInputWeights(FF1))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBufferFloat::BufferToCSV(const string file_name)
{
BufferRead();
int h = FileOpen(file_name, FILE_CSV | FILE_WRITE);
if(h == INVALID_HANDLE)
return;
//---
for(int i = 0; i < m_data_total; i++)
FileWrite(h, m_data[i]);
FileFlush(h);
FileClose(h);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronAttentionOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
if(CheckPointer(Querys) == POINTER_INVALID || !Querys.Save(file_handle))
return false;
//if(CheckPointer(Keys)==POINTER_INVALID || !Keys.Save(file_handle))
// return false;
if(CheckPointer(Values) == POINTER_INVALID || !Values.Save(file_handle))
return false;
if(CheckPointer(Scores) == POINTER_INVALID || !Scores.Save(file_handle))
return false;
if(CheckPointer(AttentionOut) == POINTER_INVALID || !AttentionOut.Save(file_handle))
return false;
if(CheckPointer(FF1) == POINTER_INVALID || !FF1.Save(file_handle))
return false;
if(CheckPointer(FF2) == POINTER_INVALID || !FF2.Save(file_handle))
return false;
if(FileWriteInteger(file_handle, iWindow, INT_VALUE) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, iUnits, INT_VALUE) < INT_VALUE)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronAttentionOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//---
if(CheckPointer(Querys) == POINTER_INVALID)
Querys = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !Querys.Load(file_handle))
return false;
//---
//if(CheckPointer(Keys)==POINTER_INVALID)
// Keys=new CNeuronConvOCL();
//if(FileReadInteger(file_handle,INT_VALUE)!=defNeuronConvOCL || !Keys.Load(file_handle))
// return false;
//---
if(CheckPointer(Values) == POINTER_INVALID)
Values = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !Values.Load(file_handle))
return false;
//---
if(CheckPointer(Scores) == POINTER_INVALID)
Scores = new CBufferFloat();
if(Scores.GetIndex() >= 0)
Scores.BufferFree();
if(!Scores.Load(file_handle))
return false;
if(!Scores.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(AttentionOut) == POINTER_INVALID)
AttentionOut = new CNeuronBaseOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronBaseOCL || !AttentionOut.Load(file_handle))
return false;
//---
if(CheckPointer(FF1) == POINTER_INVALID)
FF1 = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !FF1.Load(file_handle))
return false;
if(CheckPointer(FF2) == POINTER_INVALID)
FF2 = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !FF2.Load(file_handle))
return false;
iWindow = FileReadInteger(file_handle);
iUnits = FileReadInteger(file_handle);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronAttentionOCL::GetLayerInfo()
{
CLayerDescription* result = CNeuronBaseOCL::GetLayerInfo();
if(!result)
return result;
result.window = (int)iWindow;
result.count = (int)iUnits;
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConvOCL::Load(const int file_handle)
{
if(!CNeuronProofOCL::Load(file_handle))
return false;
//---
if(CheckPointer(WeightsConv) == POINTER_INVALID)
WeightsConv = new CBufferFloat();
if(WeightsConv.GetIndex() >= 0)
WeightsConv.BufferFree();
if(!WeightsConv.Load(file_handle))
return false;
if(!WeightsConv.BufferCreate(OpenCL))
return false;
//---
if(optimization == SGD)
{
if(CheckPointer(DeltaWeightsConv) == POINTER_INVALID)
DeltaWeightsConv = new CBufferFloat();
if(DeltaWeightsConv.GetIndex() >= 0)
DeltaWeightsConv.BufferFree();
if(!DeltaWeightsConv.Load(file_handle))
return false;
if(!DeltaWeightsConv.BufferCreate(OpenCL))
return false;
}
else
{
if(CheckPointer(FirstMomentumConv) == POINTER_INVALID)
FirstMomentumConv = new CBufferFloat();
if(FirstMomentumConv.GetIndex() >= 0)
FirstMomentumConv.BufferFree();
if(!FirstMomentumConv.Load(file_handle))
return false;
if(!FirstMomentumConv.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(SecondMomentumConv) == POINTER_INVALID)
SecondMomentumConv = new CBufferFloat();
if(SecondMomentumConv.GetIndex() >= 0)
SecondMomentumConv.BufferFree();
if(!SecondMomentumConv.Load(file_handle))
return false;
if(!SecondMomentumConv.BufferCreate(OpenCL))
return false;
}
iWindowOut = FileReadInteger(file_handle);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConvOCL::Save(const int file_handle)
{
if(!CNeuronProofOCL::Save(file_handle))
return false;
//---
if(CheckPointer(WeightsConv) == POINTER_INVALID || !WeightsConv.Save(file_handle))
return false;
if(optimization == SGD && (CheckPointer(DeltaWeightsConv) == POINTER_INVALID || !DeltaWeightsConv.Save(file_handle)))
return false;
if(optimization != SGD && (CheckPointer(FirstMomentumConv) == POINTER_INVALID || !FirstMomentumConv.Save(file_handle)))
return false;
if(optimization != SGD && (CheckPointer(SecondMomentumConv) == POINTER_INVALID || !SecondMomentumConv.Save(file_handle)))
return false;
if(FileWriteInteger(file_handle, iWindowOut, INT_VALUE) < INT_VALUE)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProofOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
if(FileWriteInteger(file_handle, iWindow, INT_VALUE) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, iStep, INT_VALUE) < INT_VALUE)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronProofOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
iWindow = FileReadInteger(file_handle);
iStep = FileReadInteger(file_handle);
//---
return true;
}
//+------------------------------------------------------------------+
///\ingroup neuron_base
///\class CNeuronMHAttentionOCL
///\brief Class of Multi-Head Self-Attention layer GPU calculation
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/8909#para52">the link.</A>
//+------------------------------------------------------------------+
class CNeuronMHAttentionOCL : public CNeuronAttentionOCL
{
protected:
CNeuronConvOCL *Querys2; ///< Convolution layer for Querys Head 2
CNeuronConvOCL *Querys3; ///< Convolution layer for Querys Head 3
CNeuronConvOCL *Querys4; ///< Convolution layer for Querys Head 4
CNeuronConvOCL *Keys2; ///< Convolution layer for Keys Head 2
CNeuronConvOCL *Keys3; ///< Convolution layer for Keys Head 3
CNeuronConvOCL *Keys4; ///< Convolution layer for Keys Head 4
CNeuronConvOCL *Values2; ///< Convolution layer for Values Head 2
CNeuronConvOCL *Values3; ///< Convolution layer for Values Head 3
CNeuronConvOCL *Values4; ///< Convolution layer for Values Head 4
CBufferFloat *Scores2; ///< Buffer for Scores matrix Head 2
CBufferFloat *Scores3; ///< Buffer for Scores matrix Head 3
CBufferFloat *Scores4; ///< Buffer for Scores matrix Head 4
CNeuronBaseOCL *AttentionOut2; ///< Layer of Self-Attention Out
CNeuronBaseOCL *AttentionOut3; ///< Layer of Self-Attention Out
CNeuronBaseOCL *AttentionOut4; ///< Layer of Self-Attention Out
CNeuronBaseOCL *AttentionConcatenate;///< Layer of Concatenate Self-Attention Out
CNeuronConvOCL *Weights0; ///< Convolution layer for Weights0
//---
virtual bool feedForward(CNeuronBaseOCL *prevLayer); ///< Feed Forward method.@param prevLayer Pointer to previos layer.
virtual bool updateInputWeights(CNeuronBaseOCL *prevLayer); ///< Method for updating weights.@param prevLayer Pointer to previos layer.
/// Method to transfer gradients inside Head Self-Attention
virtual bool calcHeadGradient(CNeuronConvOCL *query, CNeuronConvOCL *value, CBufferFloat *score, CNeuronBaseOCL *attention, CNeuronBaseOCL *prevLayer);
public:
/** Constructor */
CNeuronMHAttentionOCL(void) {};
/** Destructor */~CNeuronMHAttentionOCL(void);
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint units_count, ENUM_OPTIMIZATION optimization_type, uint batch);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object.@param[in] window Size of in/out window and step.@param[in] units_countNumber of neurons.@param[in] optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer); ///< Method to transfer gradients to previous layer @param[in] prevLayer Pointer to previous layer.
//---
virtual int Type(void) const { return defNeuronMHAttentionOCL; }///< Identificator of class.@return Type of class
//--- methods for working with files
virtual bool Save(int const file_handle); ///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle); ///< Load method @param[in] file_handle handle of file @return logical result of operation
virtual CLayerDescription* GetLayerInfo(void);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronMHAttentionOCL::~CNeuronMHAttentionOCL(void)
{
if(CheckPointer(Querys2) != POINTER_INVALID)
delete Querys2;
if(CheckPointer(Querys3) != POINTER_INVALID)
delete Querys3;
if(CheckPointer(Querys4) != POINTER_INVALID)
delete Querys4;
if(CheckPointer(Keys2) != POINTER_INVALID)
delete Keys2;
if(CheckPointer(Keys3) != POINTER_INVALID)
delete Keys3;
if(CheckPointer(Keys4) != POINTER_INVALID)
delete Keys4;
if(CheckPointer(Values2) != POINTER_INVALID)
delete Values2;
if(CheckPointer(Values3) != POINTER_INVALID)
delete Values3;
if(CheckPointer(Values4) != POINTER_INVALID)
delete Values4;
if(CheckPointer(Scores2) != POINTER_INVALID)
delete Scores2;
if(CheckPointer(Scores3) != POINTER_INVALID)
delete Scores3;
if(CheckPointer(Scores4) != POINTER_INVALID)
delete Scores4;
if(CheckPointer(Weights0) != POINTER_INVALID)
delete Weights0;
if(CheckPointer(AttentionOut2) != POINTER_INVALID)
delete AttentionOut2;
if(CheckPointer(AttentionOut3) != POINTER_INVALID)
delete AttentionOut3;
if(CheckPointer(AttentionOut4) != POINTER_INVALID)
delete AttentionOut4;
if(CheckPointer(AttentionConcatenate) != POINTER_INVALID)
delete AttentionConcatenate;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMHAttentionOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint units_count, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronAttentionOCL::Init(numOutputs, myIndex, open_cl, window, units_count, optimization_type, batch))
return false;
//---
if(CheckPointer(Querys2) == POINTER_INVALID)
{
Querys2 = new CNeuronConvOCL();
if(CheckPointer(Querys2) == POINTER_INVALID)
return false;
if(!Querys2.Init(0, 6, open_cl, window, window, window, units_count, optimization_type, batch))
return false;
Querys2.SetActivationFunction(None);
}
//---
if(CheckPointer(Querys3) == POINTER_INVALID)
{
Querys3 = new CNeuronConvOCL();
if(CheckPointer(Querys3) == POINTER_INVALID)
return false;
if(!Querys3.Init(0, 7, open_cl, window, window, window, units_count, optimization_type, batch))
return false;
Querys3.SetActivationFunction(None);
}
//---
if(CheckPointer(Querys4) == POINTER_INVALID)
{
Querys4 = new CNeuronConvOCL();
if(CheckPointer(Querys4) == POINTER_INVALID)
return false;
if(!Querys4.Init(0, 8, open_cl, window, window, window, units_count, optimization_type, batch))
return false;
Querys4.SetActivationFunction(None);
}
//---
if(CheckPointer(Values2) == POINTER_INVALID)
{
Values2 = new CNeuronConvOCL();
if(CheckPointer(Values2) == POINTER_INVALID)
return false;
if(!Values2.Init(0, 9, open_cl, window, window, window, units_count, optimization_type, batch))
return false;
Values2.SetActivationFunction(None);
}
//---
if(CheckPointer(Values3) == POINTER_INVALID)
{
Values3 = new CNeuronConvOCL();
if(CheckPointer(Values3) == POINTER_INVALID)
return false;
if(!Values3.Init(0, 10, open_cl, window, window, window, units_count, optimization_type, batch))
return false;
Values3.SetActivationFunction(None);
}
//---
if(CheckPointer(Values4) == POINTER_INVALID)
{
Values4 = new CNeuronConvOCL();
if(CheckPointer(Values4) == POINTER_INVALID)
return false;
if(!Values4.Init(0, 11, open_cl, window, window, window, units_count, optimization_type, batch))
return false;
Values4.SetActivationFunction(None);
}
//---
if(CheckPointer(Scores2) == POINTER_INVALID)
{
Scores2 = new CBufferFloat();
if(CheckPointer(Scores2) == POINTER_INVALID)
return false;
}
if(!Scores2.BufferInit(units_count * units_count, 0.0))
return false;
if(!Scores2.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(Scores3) == POINTER_INVALID)
{
Scores3 = new CBufferFloat();
if(CheckPointer(Scores3) == POINTER_INVALID)
return false;
}
if(!Scores3.BufferInit(units_count * units_count, 0.0))
return false;
if(!Scores3.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(Scores4) == POINTER_INVALID)
{
Scores4 = new CBufferFloat();
if(CheckPointer(Scores4) == POINTER_INVALID)
return false;
}
if(!Scores4.BufferInit(units_count * units_count, 0.0))
return false;
if(!Scores4.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(AttentionOut2) == POINTER_INVALID)
{
AttentionOut2 = new CNeuronBaseOCL();
if(CheckPointer(AttentionOut2) == POINTER_INVALID)
return false;
if(!AttentionOut2.Init(0, 12, open_cl, window * units_count, optimization_type, batch))
return false;
AttentionOut2.SetActivationFunction(None);
}
//---
if(CheckPointer(AttentionOut3) == POINTER_INVALID)
{
AttentionOut3 = new CNeuronBaseOCL();
if(CheckPointer(AttentionOut3) == POINTER_INVALID)
return false;
if(!AttentionOut3.Init(0, 13, open_cl, window * units_count, optimization_type, batch))
return false;
AttentionOut3.SetActivationFunction(None);
}
//---
if(CheckPointer(AttentionOut4) == POINTER_INVALID)
{
AttentionOut4 = new CNeuronBaseOCL();
if(CheckPointer(AttentionOut4) == POINTER_INVALID)
return false;
if(!AttentionOut4.Init(0, 14, open_cl, window * units_count, optimization_type, batch))
return false;
AttentionOut4.SetActivationFunction(None);
}
//---
if(CheckPointer(AttentionConcatenate) == POINTER_INVALID)
{
AttentionConcatenate = new CNeuronBaseOCL();
if(CheckPointer(AttentionConcatenate) == POINTER_INVALID)
return false;
if(!AttentionConcatenate.Init(0, 15, open_cl, 4 * window * units_count, optimization_type, batch))
return false;
AttentionConcatenate.SetActivationFunction(None);
}
//---
if(CheckPointer(Weights0) == POINTER_INVALID)
{
Weights0 = new CNeuronConvOCL();
if(CheckPointer(Weights0) == POINTER_INVALID)
return false;
if(!Weights0.Init(0, 16, open_cl, 4 * window, 4 * window, window, units_count, optimization_type, batch))
return false;
Weights0.SetActivationFunction(None);
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMHAttentionOCL::feedForward(CNeuronBaseOCL *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1] = {1};
OpenCL.SetArgumentBuffer(def_k_Normilize, def_k_norm_buffer, prevLayer.getOutputIndex());
OpenCL.SetArgument(def_k_Normilize, def_k_norm_dimension, prevLayer.Neurons());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_Normilize, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Normalize: %d", GetLastError());
return false;
}
//if(!prevLayer.Output.BufferRead())
// return false;
}
//---
if(CheckPointer(Querys) == POINTER_INVALID || !Querys.FeedForward(prevLayer))
return false;
if(CheckPointer(Querys2) == POINTER_INVALID || !Querys2.FeedForward(prevLayer))
return false;
if(CheckPointer(Querys3) == POINTER_INVALID || !Querys3.FeedForward(prevLayer))
return false;
if(CheckPointer(Querys4) == POINTER_INVALID || !Querys4.FeedForward(prevLayer))
return false;
if(CheckPointer(Values) == POINTER_INVALID || !Values.FeedForward(prevLayer))
return false;
if(CheckPointer(Values2) == POINTER_INVALID || !Values2.FeedForward(prevLayer))
return false;
if(CheckPointer(Values3) == POINTER_INVALID || !Values3.FeedForward(prevLayer))
return false;
if(CheckPointer(Values4) == POINTER_INVALID || !Values4.FeedForward(prevLayer))
return false;
//--- Scores Head 1
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_querys, Querys.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_keys, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_score, Scores.GetIndex());
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_dimension, iWindow);
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_mask, 0);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionScore, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel AttentionScore: %d", GetLastError());
return false;
}
//if(!Scores.BufferRead())
// return false;
}
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iWindow;
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_scores, Scores.GetIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_inputs, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_values, Values.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_out, AttentionOut.getOutputIndex());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionOut, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel Attention Out: %d", GetLastError());
return false;
}
float temp[];
if(!AttentionOut.getOutputVal(temp))
return false;
}
//--- Scores Head 2
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_querys, Querys2.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_keys, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_score, Scores2.GetIndex());
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_dimension, iWindow);
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_mask, 0);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionScore, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel AttentionScore: %d", GetLastError());
return false;
}
//if(!Scores2.BufferRead())
// return false;
}
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iWindow;
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_scores, Scores2.GetIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_inputs, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_values, Values2.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_out, AttentionOut2.getOutputIndex());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionOut, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel Attention Out: %d", GetLastError());
return false;
}
//float temp[];
//if(!AttentionOut2.getOutputVal(temp))
// return false;
}
//--- Scores Head 3
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_querys, Querys3.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_keys, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_score, Scores3.GetIndex());
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_dimension, iWindow);
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_mask, 0);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionScore, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel AttentionScore: %d", GetLastError());
return false;
}
//if(!Scores3.BufferRead())
// return false;
}
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iWindow;
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_scores, Scores3.GetIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_inputs, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_values, Values3.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_out, AttentionOut3.getOutputIndex());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionOut, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel Attention Out: %d", GetLastError());
return false;
}
float temp[];
if(!AttentionOut3.getOutputVal(temp))
return false;
}
//--- Scores Head 4
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_querys, Querys4.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_keys, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionScore, def_k_as_score, Scores4.GetIndex());
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_dimension, iWindow);
OpenCL.SetArgument(def_k_AttentionScore, def_k_as_mask, 0);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionScore, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel AttentionScore: %d", GetLastError());
return false;
}
//if(!Scores4.BufferRead())
// return false;
}
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iWindow;
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_scores, Scores4.GetIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_inputs, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_values, Values4.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionOut, def_k_aout_out, AttentionOut4.getOutputIndex());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionOut, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel Attention Out: %d", GetLastError());
return false;
}
float temp[];
if(!AttentionOut4.getOutputVal(temp))
return false;
}
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_ConcatenateMatrix, def_k_conc_input1, AttentionOut.getOutputIndex());
OpenCL.SetArgument(def_k_ConcatenateMatrix, def_k_conc_window1, iWindow);
OpenCL.SetArgumentBuffer(def_k_ConcatenateMatrix, def_k_conc_input2, AttentionOut2.getOutputIndex());
OpenCL.SetArgument(def_k_ConcatenateMatrix, def_k_conc_window2, iWindow);
OpenCL.SetArgumentBuffer(def_k_ConcatenateMatrix, def_k_conc_input3, AttentionOut3.getOutputIndex());
OpenCL.SetArgument(def_k_ConcatenateMatrix, def_k_conc_window3, iWindow);
OpenCL.SetArgumentBuffer(def_k_ConcatenateMatrix, def_k_conc_input4, AttentionOut4.getOutputIndex());
OpenCL.SetArgument(def_k_ConcatenateMatrix, def_k_conc_window4, iWindow);
OpenCL.SetArgumentBuffer(def_k_ConcatenateMatrix, def_k_conc_out, AttentionConcatenate.getOutputIndex());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_ConcatenateMatrix, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Concatenate Matrix: %d", GetLastError());
return false;
}
float temp[];
if(!AttentionConcatenate.getOutputVal(temp))
return false;
}
//---
if(CheckPointer(Weights0) == POINTER_INVALID || !Weights0.FeedForward(AttentionConcatenate))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, Weights0.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, Weights0.getOutputIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 0.5f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
//if(!Output.BufferRead())
// return false;
}
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = 1;
OpenCL.SetArgumentBuffer(def_k_Normilize, def_k_norm_buffer, Weights0.getOutputIndex());
OpenCL.SetArgument(def_k_Normilize, def_k_norm_dimension, Weights0.Neurons());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_Normilize, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Normalize: %d", GetLastError());
return false;
}
float temp[];
if(!Weights0.getOutputVal(temp))
return false;
}
//---
if(!FF1.FeedForward(Weights0))
return false;
if(!FF2.FeedForward(FF1))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, Weights0.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, FF2.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, Output.GetIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 0.5f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
//if(!Output.BufferRead())
// return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMHAttentionOCL::calcInputGradients(CNeuronBaseOCL *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
if(!FF2.calcInputGradients(FF1))
return false;
if(!FF1.calcInputGradients(Weights0))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, Weights0.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, Gradient.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, Weights0.getGradientIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 0.5f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
float temp[];
if(Weights0.getGradient(temp) <= 0)
return false;
}
//---
if(!Weights0.calcInputGradients(AttentionConcatenate))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_DeconcatenateMatrix, def_k_dconc_output1, AttentionOut.getGradientIndex());
OpenCL.SetArgument(def_k_DeconcatenateMatrix, def_k_dconc_window1, iWindow);
OpenCL.SetArgumentBuffer(def_k_DeconcatenateMatrix, def_k_dconc_output2, AttentionOut2.getGradientIndex());
OpenCL.SetArgument(def_k_DeconcatenateMatrix, def_k_dconc_window2, iWindow);
OpenCL.SetArgumentBuffer(def_k_DeconcatenateMatrix, def_k_dconc_output3, AttentionOut3.getGradientIndex());
OpenCL.SetArgument(def_k_DeconcatenateMatrix, def_k_dconc_window3, iWindow);
OpenCL.SetArgumentBuffer(def_k_DeconcatenateMatrix, def_k_dconc_output4, AttentionOut4.getGradientIndex());
OpenCL.SetArgument(def_k_DeconcatenateMatrix, def_k_dconc_window4, iWindow);
OpenCL.SetArgumentBuffer(def_k_DeconcatenateMatrix, def_k_dconc_inputs, AttentionConcatenate.getGradientIndex());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_DeconcatenateMatrix, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Deconcantenate Matrix: %d", GetLastError());
return false;
}
float temp[];
if(AttentionConcatenate.getGradient(temp) <= 0)
return false;
}
//---
if(!calcHeadGradient(Querys, Values, Scores, AttentionOut, prevLayer))
return false;
if(!calcHeadGradient(Querys2, Values2, Scores2, AttentionOut2, prevLayer))
return false;
if(!calcHeadGradient(Querys3, Values3, Scores3, AttentionOut3, prevLayer))
return false;
if(!calcHeadGradient(Querys4, Values4, Scores4, AttentionOut4, prevLayer))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_Matrix5Sum, def_k_sum5_matrix1, AttentionOut.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_Matrix5Sum, def_k_sum5_matrix2, AttentionOut2.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_Matrix5Sum, def_k_sum5_matrix3, AttentionOut3.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_Matrix5Sum, def_k_sum5_matrix4, AttentionOut4.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_Matrix5Sum, def_k_sum5_matrix5, Weights0.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_Matrix5Sum, def_k_sum5_matrix_out, prevLayer.getGradientIndex());
OpenCL.SetArgument(def_k_Matrix5Sum, def_k_sum5_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_Matrix5Sum, def_k_sum5_multiplyer, (float)0.2);
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_Matrix5Sum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Matrix5Sum: %d", GetLastError());
return false;
}
float temp[];
if(prevLayer.getGradient(temp) <= 0)
return false;
}
//---
{
//uint global_work_offset[1]={0};
//uint global_work_size[1];
//global_work_size[0]=1;
//OpenCL.SetArgumentBuffer(def_k_Normilize,def_k_norm_buffer,prevLayer.getGradientIndex());
//OpenCL.SetArgument(def_k_Normilize,def_k_norm_dimension,prevLayer.Neurons());
//if(!OpenCL.Execute(def_k_Normilize,1,global_work_offset,global_work_size))
// {
// printf("Error of execution kernel Normalize: %d",GetLastError());
// return false;
// }
//float temp[];
//if(prevLayer.getGradient(temp)<=0)
// return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMHAttentionOCL::calcHeadGradient(CNeuronConvOCL *query, CNeuronConvOCL *value, CBufferFloat *score, CNeuronBaseOCL *attention, CNeuronBaseOCL *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iWindow;
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_gradient, attention.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_keys, prevLayer.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_keys_g, prevLayer.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_querys, query.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_querys_g, query.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_values, value.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_values_g, value.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_AttentionGradients, def_k_ag_scores, score.GetIndex());
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_AttentionGradients, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel AttentionGradients: %d", GetLastError());
return false;
}
float temp[];
if(query.getGradient(temp) <= 0)
return false;
}
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, prevLayer.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, prevLayer.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, attention.getGradientIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 0.5f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
float temp[];
if(attention.getGradient(temp) <= 0)
return false;
}
//---
if(!query.calcInputGradients(prevLayer))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, attention.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, prevLayer.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, attention.getGradientIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 1.0f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
float temp[];
if(attention.getGradient(temp) <= 0)
return false;
}
//---
if(!value.calcInputGradients(prevLayer))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = iUnits;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, attention.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, prevLayer.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, attention.getGradientIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)iWindow + 1);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 0.33f);
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
float temp[];
if(prevLayer.getGradient(temp) <= 0)
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMHAttentionOCL::updateInputWeights(CNeuronBaseOCL *prevLayer)
{
if(!Querys.UpdateInputWeights(prevLayer) || !Querys2.UpdateInputWeights(prevLayer) ||
!Querys3.UpdateInputWeights(prevLayer) || !Querys4.UpdateInputWeights(prevLayer))
return false;
//---
if(!Values.UpdateInputWeights(prevLayer) || !Values2.UpdateInputWeights(prevLayer) ||
!Values3.UpdateInputWeights(prevLayer) || !Values4.UpdateInputWeights(prevLayer))
return false;
if(!Weights0.UpdateInputWeights(AttentionConcatenate))
return false;
if(!FF1.UpdateInputWeights(Weights0))
return false;
if(!FF2.UpdateInputWeights(FF1))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMHAttentionOCL::Save(const int file_handle)
{
if(!CNeuronAttentionOCL::Save(file_handle))
return false;
//---
if(CheckPointer(Querys2) == POINTER_INVALID || !Querys2.Save(file_handle))
return false;
if(CheckPointer(Values2) == POINTER_INVALID || !Values2.Save(file_handle))
return false;
if(CheckPointer(Scores2) == POINTER_INVALID || !Scores2.Save(file_handle))
return false;
if(CheckPointer(AttentionOut2) == POINTER_INVALID || !AttentionOut2.Save(file_handle))
return false;
//---
if(CheckPointer(Querys3) == POINTER_INVALID || !Querys3.Save(file_handle))
return false;
if(CheckPointer(Values3) == POINTER_INVALID || !Values3.Save(file_handle))
return false;
if(CheckPointer(Scores3) == POINTER_INVALID || !Scores3.Save(file_handle))
return false;
if(CheckPointer(AttentionOut3) == POINTER_INVALID || !AttentionOut3.Save(file_handle))
return false;
//---
if(CheckPointer(Querys4) == POINTER_INVALID || !Querys4.Save(file_handle))
return false;
if(CheckPointer(Values4) == POINTER_INVALID || !Values4.Save(file_handle))
return false;
if(CheckPointer(Scores4) == POINTER_INVALID || !Scores4.Save(file_handle))
return false;
if(CheckPointer(AttentionOut4) == POINTER_INVALID || !AttentionOut4.Save(file_handle))
return false;
//---
if(CheckPointer(AttentionConcatenate) == POINTER_INVALID || !AttentionConcatenate.Save(file_handle))
return false;
if(CheckPointer(Weights0) == POINTER_INVALID || !Weights0.Save(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMHAttentionOCL::Load(const int file_handle)
{
if(!CNeuronAttentionOCL::Load(file_handle))
return false;
//---
if(CheckPointer(Querys2) == POINTER_INVALID)
Querys2 = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !Querys2.Load(file_handle))
return false;
//---
if(CheckPointer(Values2) == POINTER_INVALID)
Values2 = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !Values2.Load(file_handle))
return false;
//---
if(CheckPointer(Scores2) == POINTER_INVALID)
Scores2 = new CBufferFloat();
if(Scores2.GetIndex() >= 0)
Scores2.BufferFree();
if(!Scores2.Load(file_handle))
return false;
if(!Scores2.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(AttentionOut2) == POINTER_INVALID)
AttentionOut2 = new CNeuronBaseOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronBaseOCL || !AttentionOut2.Load(file_handle))
return false;
//---
if(CheckPointer(Querys3) == POINTER_INVALID)
Querys3 = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !Querys3.Load(file_handle))
return false;
//---
if(CheckPointer(Values3) == POINTER_INVALID)
Values3 = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !Values3.Load(file_handle))
return false;
//---
if(CheckPointer(Scores3) == POINTER_INVALID)
Scores3 = new CBufferFloat();
if(Scores3.GetIndex() >= 0)
Scores3.BufferFree();
if(!Scores3.Load(file_handle))
return false;
if(!Scores3.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(AttentionOut3) == POINTER_INVALID)
AttentionOut3 = new CNeuronBaseOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronBaseOCL || !AttentionOut3.Load(file_handle))
return false;
//---
if(CheckPointer(Querys4) == POINTER_INVALID)
Querys4 = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !Querys4.Load(file_handle))
return false;
//---
if(CheckPointer(Values4) == POINTER_INVALID)
Values4 = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !Values4.Load(file_handle))
return false;
//---
if(CheckPointer(Scores4) == POINTER_INVALID)
Scores4 = new CBufferFloat();
if(Scores4.GetIndex() >= 0)
Scores4.BufferFree();
if(!Scores4.Load(file_handle))
return false;
if(!Scores4.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(AttentionOut4) == POINTER_INVALID)
AttentionOut4 = new CNeuronBaseOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronBaseOCL || !AttentionOut4.Load(file_handle))
return false;
//---
if(CheckPointer(AttentionConcatenate) == POINTER_INVALID)
AttentionConcatenate = new CNeuronBaseOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronBaseOCL || !AttentionConcatenate.Load(file_handle))
return false;
//---
if(CheckPointer(Weights0) == POINTER_INVALID)
Weights0 = new CNeuronConvOCL();
if(FileReadInteger(file_handle, INT_VALUE) != defNeuronConvOCL || !Weights0.Load(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronMHAttentionOCL::GetLayerInfo(void)
{
CLayerDescription* result = CNeuronAttentionOCL::GetLayerInfo();
if(!result)
return result;
result.step = 4;
//---
return result;
}
//+------------------------------------------------------------------+
///\class CCollection
///\brief Class of objects collection.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/9025#para41">the link.</A>
//+------------------------------------------------------------------+
class CCollection : public CArrayObj
{
public:
CCollection(void) {};
~CCollection(void) {};
//---
virtual bool CreateElement(const int index)
{
if(index < 0)
return false;
//---
if(index >= m_data_max)
{
if(!Reserve(index - m_data_total))
return false;
}
m_data[index] = new CBufferFloat();
return(CheckPointer(m_data[index]) != POINTER_INVALID);
}
//---
virtual bool SetOpenCL(COpenCLMy *open_cl)
{
if(!open_cl)
return false;
bool result = true;
for(int i = 0; (i < m_data_total && result); i++)
{
CBufferFloat* temp = m_data[i];
if(!temp || !temp.BufferCreate(open_cl))
{
result = false;
break;
}
}
//---
return result;
}
//---
};
//+------------------------------------------------------------------+
///\ingroup neuron_base
///\class CNeuronMLMHAttentionOCL
///\brief Class of Multilayer multi-headed attention neuron.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/9025#para41">the link.</A>
//+------------------------------------------------------------------+
class CNeuronMLMHAttentionOCL : public CNeuronBaseOCL
{
protected:
uint iLayers; ///< Number of inner layers
uint iHeads; ///< Number of heads
uint iWindow; ///< Input window size
uint iUnits; ///< Number of units
uint iWindowKey; ///< Size of Key/Query window
//---
CCollection *QKV_Tensors; ///< The collection of tensors of Queries, Keys and Values
CCollection *QKV_Weights; ///< The collection of Matrix of weights to previous layer
CCollection *S_Tensors; ///< The collection of Scores tensors
CCollection *AO_Tensors; ///< The collection of Attention Out tensors
CCollection *FF_Tensors; ///< The collection of tensors of Feed Forward output
CCollection *FF_Weights; ///< The collection of Matrix of Feed Forward weights
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
virtual bool ConvolutionForward(CBufferFloat *weights, CBufferFloat *inputs, CBufferFloat *outputs, uint window, uint window_out, ENUM_ACTIVATION activ, uint step = 0);
///< \brief Convolution Feed Forward method of calling kernel ::FeedForwardConv().
virtual bool AttentionScore(CBufferFloat *qkv, CBufferFloat *scores, bool mask = true);
///< \brief Multi-heads attention scores method of calling kernel ::MHAttentionScore().
virtual bool AttentionOut(CBufferFloat *qkv, CBufferFloat *scores, CBufferFloat *out);
///< \brief Multi-heads attention out method of calling kernel ::MHAttentionOut().
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL); ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
virtual bool ConvolutuionUpdateWeights(CBufferFloat *weights, CBufferFloat *gradient, CBufferFloat *inputs, CBufferFloat *momentum1, CBufferFloat *momentum2, uint window, uint window_out, uint step = 0);
virtual bool ConvolutuionUpdateWeights(CBufferFloat *weights, CBufferFloat *source, CBufferFloat *momentum1, CBufferFloat *momentum2, float tau);
///< Method for updating weights in convolution layer.\details Calling one of kernels ::UpdateWeightsConvMomentum() or ::UpdateWeightsConvAdam() in depends of optimization type (#ENUM_OPTIMIZATION).
virtual bool ConvolutionInputGradients(CBufferFloat *weights, CBufferFloat *gradient, CBufferFloat *inputs, CBufferFloat *inp_gradient, uint window, uint window_out, uint activ, uint shift_out = 0, uint step = 0);
///< Method of passing gradients through a convolutional layer.
virtual bool AttentionInsideGradients(CBufferFloat *qkv, CBufferFloat *qkv_g, CBufferFloat *scores, CBufferFloat *scores_g, CBufferFloat *gradient);
///< Method of passing gradients through attention layer.
public:
/** Constructor */
CNeuronMLMHAttentionOCL(void);
/** Destructor */~CNeuronMLMHAttentionOCL(void);
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint heads, uint units_count, uint layers, ENUM_OPTIMIZATION optimization_type, uint batch);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object.@param[in] window Size of in/out window and step.@param[in] units_countNumber of neurons.@param[in] optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer); ///< Method to transfer gradients to previous layer @param[in] prevLayer Pointer to previous layer.
//---
virtual int Type(void) const { return defNeuronMLMHAttentionOCL; }///< Identificator of class.@return Type of class
//--- methods for working with files
virtual bool Save(int const file_handle); ///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle); ///< Load method @param[in] file_handle handle of file @return logical result of operation
virtual CLayerDescription* GetLayerInfo(void);
virtual bool WeightsUpdate(CNeuronBaseOCL *net, float tau);
virtual void SetOpenCL(COpenCLMy *obj);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronMLMHAttentionOCL::CNeuronMLMHAttentionOCL(void) : iLayers(0),
iHeads(0),
iWindow(0),
iWindowKey(0),
iUnits(0)
{
QKV_Tensors = new CCollection();
QKV_Weights = new CCollection();
S_Tensors = new CCollection();
AO_Tensors = new CCollection();
FF_Tensors = new CCollection();
FF_Weights = new CCollection();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronMLMHAttentionOCL::~CNeuronMLMHAttentionOCL(void)
{
if(CheckPointer(QKV_Tensors) != POINTER_INVALID)
delete QKV_Tensors;
if(CheckPointer(QKV_Weights) != POINTER_INVALID)
delete QKV_Weights;
if(CheckPointer(S_Tensors) != POINTER_INVALID)
delete S_Tensors;
if(CheckPointer(AO_Tensors) != POINTER_INVALID)
delete AO_Tensors;
if(CheckPointer(FF_Tensors) != POINTER_INVALID)
delete FF_Tensors;
if(CheckPointer(FF_Weights) != POINTER_INVALID)
delete FF_Weights;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint heads, uint units_count, uint layers, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, window * units_count, optimization_type, batch))
return false;
//---
iWindow = fmax(window, 1);
iWindowKey = fmax(window_key, 1);
iUnits = fmax(units_count, 1);
iHeads = fmax(heads, 1);
iLayers = fmax(layers, 1);
//---
uint num = 3 * iWindowKey * iHeads * iUnits; //Size of QKV tensor
uint qkv_weights = 3 * (iWindow + 1) * iWindowKey * iHeads; //Size of weights' matrix of QKV tenzor
uint scores = iUnits * iUnits * iHeads; //Size of Score tensor
uint mh_out = iWindowKey * iHeads * iUnits; //Size of multi-heads self-attention
uint out = iWindow * iUnits; //Size of our tensore
uint w0 = (iWindowKey + 1) * iHeads * iWindow; //Size W0 tensor
uint ff_1 = 4 * (iWindow + 1) * iWindow; //Size of weights' matrix 1-st feed forward layer
uint ff_2 = (4 * iWindow + 1) * iWindow; //Size of weights' matrix 2-nd feed forward layer
//---
for(uint i = 0; i < iLayers; i++)
{
CBufferFloat *temp = NULL;
for(int d = 0; d < 2; d++)
{
//--- Initilize QKV tensor
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(num, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Tensors.Add(temp))
return false;
//--- Initialize scores
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(scores, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!S_Tensors.Add(temp))
return false;
//--- Initialize multi-heads attention out
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(mh_out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!AO_Tensors.Add(temp))
return false;
//--- Initialize attention out
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Tensors.Add(temp))
return false;
//--- Initialize Feed Forward 1
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(4 * out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Tensors.Add(temp))
return false;
//--- Initialize Feed Forward 2
if(i == iLayers - 1)
{
if(!FF_Tensors.Add(d == 0 ? Output : Gradient))
return false;
continue;
}
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Tensors.Add(temp))
return false;
}
//--- Initilize QKV weights
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(qkv_weights))
return false;
float k = (float)(1 / sqrt(iWindow + 1));
for(uint w = 0; w < qkv_weights; w++)
{
if(!temp.Add(GenerateWeight() * 2 * k - k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
//--- Initilize Weights0
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(w0))
return false;
for(uint w = 0; w < w0; w++)
{
if(!temp.Add(GenerateWeight() * 2 * k - k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//--- Initilize FF Weights
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(ff_1))
return false;
for(uint w = 0; w < ff_1; w++)
{
if(!temp.Add(GenerateWeight() * 2 * k - k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//---
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(ff_2))
return false;
k = (float)(1 / sqrt(4 * iWindow + 1));
for(uint w = 0; w < ff_2; w++)
{
if(!temp.Add(GenerateWeight() * 2 * k - k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//---
for(int d = 0; d < (optimization == SGD ? 1 : 2); d++)
{
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(qkv_weights, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(w0, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//--- Initilize FF Weights
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(ff_1, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(ff_2, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
//---
for(uint i = 0; (i < iLayers && !IsStopped()); i++)
{
//--- Calculate Queries, Keys, Values
CBufferFloat *inputs = (i == 0 ? NeuronOCL.getOutput() : FF_Tensors.At(6 * i - 4));
CBufferFloat *qkv = QKV_Tensors.At(i * 2);
if(IsStopped() || !ConvolutionForward(QKV_Weights.At(i * (optimization == SGD ? 2 : 3)), inputs, qkv, iWindow, 3 * iWindowKey * iHeads, None))
return false;
//--- Score calculation
CBufferFloat *temp = S_Tensors.At(i * 2);
if(IsStopped() || !AttentionScore(qkv, temp, true))
return false;
//--- Multi-heads attention calculation
CBufferFloat *out = AO_Tensors.At(i * 2);
if(IsStopped() || !AttentionOut(qkv, temp, out))
return false;
//--- Attention out calculation
temp = FF_Tensors.At(i * 6);
if(IsStopped() || !ConvolutionForward(FF_Weights.At(i * (optimization == SGD ? 6 : 9)), out, temp, iWindowKey * iHeads, iWindow, None))
return false;
//--- Sum and normilize attention
if(IsStopped() || !SumAndNormilize(temp, inputs, temp, iWindow))
return false;
//--- Feed Forward
inputs = temp;
temp = FF_Tensors.At(i * 6 + 1);
if(IsStopped() || !ConvolutionForward(FF_Weights.At(i * (optimization == SGD ? 6 : 9) + 1), inputs, temp, iWindow, 4 * iWindow, LReLU))
return false;
out = FF_Tensors.At(i * 6 + 2);
if(IsStopped() || !ConvolutionForward(FF_Weights.At(i * (optimization == SGD ? 6 : 9) + 2), temp, out, 4 * iWindow, iWindow, activation))
return false;
//--- Sum and normilize out
if(IsStopped() || !SumAndNormilize(out, inputs, out, iWindow))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::ConvolutionForward(CBufferFloat *weights, CBufferFloat *inputs, CBufferFloat *outputs, uint window, uint window_out, ENUM_ACTIVATION activ, uint step = 0)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(weights) == POINTER_INVALID || CheckPointer(inputs) == POINTER_INVALID
|| CheckPointer(outputs) == POINTER_INVALID)
return false;
//---
if(weights.GetIndex() < 0)
return false;
if(inputs.GetIndex() < 0)
return false;
if(outputs.GetIndex() < 0)
return false;
if(step == 0)
step = window;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = outputs.Total() / window_out;
OpenCL.SetArgumentBuffer(def_k_FeedForwardConv, def_k_ffc_matrix_w, weights.GetIndex());
OpenCL.SetArgumentBuffer(def_k_FeedForwardConv, def_k_ffc_matrix_i, inputs.GetIndex());
OpenCL.SetArgumentBuffer(def_k_FeedForwardConv, def_k_ffc_matrix_o, outputs.GetIndex());
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffc_inputs, (int)inputs.Total());
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffc_step, (int)step);
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffc_window_in, (int)window);
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffс_window_out, (int)window_out);
OpenCL.SetArgument(def_k_FeedForwardConv, def_k_ffc_activation, (int)activ);
if(!OpenCL.Execute(def_k_FeedForwardConv, 1, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s: %s", __FUNCSIG__, error);
return false;
}
//---
//vector<float> temp;
//outputs.GetData(temp);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::AttentionScore(CBufferFloat *qkv, CBufferFloat *scores, bool mask = true)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(qkv) == POINTER_INVALID || CheckPointer(scores) == POINTER_INVALID)
return false;
//---
if(qkv.GetIndex() < 0)
return false;
if(scores.GetIndex() < 0)
return false;
//---
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iHeads;
OpenCL.SetArgumentBuffer(def_k_MHAttentionScore, def_k_mhas_qkv, qkv.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHAttentionScore, def_k_mhas_score, scores.GetIndex());
OpenCL.SetArgument(def_k_MHAttentionScore, def_k_mhas_dimension, (int)iWindowKey);
OpenCL.SetArgument(def_k_MHAttentionScore, def_k_mhas_mask, (int)mask);
if(!OpenCL.Execute(def_k_MHAttentionScore, 2, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s: %s", __FUNCSIG__, error);
return false;
}
//---
//vector<float> temp;
//scores.GetData(temp);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::AttentionOut(CBufferFloat *qkv, CBufferFloat *scores, CBufferFloat *out)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(qkv) == POINTER_INVALID || CheckPointer(scores) == POINTER_INVALID
|| CheckPointer(out) == POINTER_INVALID)
return false;
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iHeads;
if(qkv.GetIndex() < 0)
return false;
if(scores.GetIndex() < 0)
return false;
if(out.GetIndex() < 0)
return false;
//---
OpenCL.SetArgumentBuffer(def_k_MHAttentionOut, def_k_mhao_qkv, qkv.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHAttentionOut, def_k_mhao_score, scores.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHAttentionOut, def_k_mhao_out, out.GetIndex());
OpenCL.SetArgument(def_k_MHAttentionOut, def_k_mhao_dimension, (int)iWindowKey);
if(!OpenCL.Execute(def_k_MHAttentionOut, 2, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s: %s", __FUNCSIG__, error);
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::SumAndNormilize(CBufferFloat *tensor1, CBufferFloat *tensor2, CBufferFloat *out, int dimension, bool normilize = true, int shift_in1 = 0, int shift_in2 = 0, int shift_out = 0)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(tensor1) == POINTER_INVALID || CheckPointer(tensor2) == POINTER_INVALID
|| CheckPointer(out) == POINTER_INVALID)
return false;
if(tensor1.GetIndex() < 0)
return false;
if(tensor2.GetIndex() < 0)
return false;
if(out.GetIndex() < 0)
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
int size = MathMin(MathMin(tensor1.Total() - shift_in1, tensor2.Total() - shift_in2), out.Total() - shift_out);
if(size <= 0)
return false;
global_work_size[0] = size / dimension;
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, tensor1.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, tensor2.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, out.GetIndex());
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, dimension);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, shift_in1);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, shift_in2);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, shift_out);
OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 0.5f);
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s MatrixSum: %s", __FUNCSIG__, error);
return false;
}
//---
//vector<float> temp;
//out.GetData(temp);
if(!normilize)
return true;
//---
global_work_size[0] = 1;
if(!OpenCL.SetArgumentBuffer(def_k_Normilize, def_k_norm_buffer, out.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_Normilize, def_k_norm_dimension, out.Total()))
return false;
if(!OpenCL.Execute(def_k_Normilize, 1, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s Normalize: %s", __FUNCSIG__, error);
return false;
}
//---
//out.GetData(temp);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::calcInputGradients(CNeuronBaseOCL *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
CBufferFloat *out_grad = Gradient;
//---
for(int i = int(iLayers - 1); (i >= 0 && !IsStopped()); i--)
{
//--- Passing gradient through feed forward layers
if(IsStopped() || !ConvolutionInputGradients(FF_Weights.At(i * (optimization == SGD ? 6 : 9) + 2), out_grad, FF_Tensors.At(i * 6 + 1), FF_Tensors.At(i * 6 + 4), 4 * iWindow, iWindow, None))
return false;
CBufferFloat *temp = FF_Tensors.At(i * 8 + 3);
if(IsStopped() || !ConvolutionInputGradients(FF_Weights.At(i * (optimization == SGD ? 6 : 9) + 1), FF_Tensors.At(i * 6 + 4), FF_Tensors.At(i * 6), temp, iWindow, 4 * iWindow, LReLU))
return false;
//--- Sum and normilize gradients
if(IsStopped() || !SumAndNormilize(out_grad, temp, temp, iWindow))
return false;
out_grad = temp;
//--- Split gradient to multi-heads
if(IsStopped() || !ConvolutionInputGradients(FF_Weights.At(i * (optimization == SGD ? 6 : 9)), out_grad, AO_Tensors.At(i * 2), AO_Tensors.At(i * 2 + 1), iWindowKey * iHeads, iWindow, None))
return false;
//--- Passing gradient to query, key and value
if(IsStopped() || !AttentionInsideGradients(QKV_Tensors.At(i * 2), QKV_Tensors.At(i * 2 + 1), S_Tensors.At(i * 2), S_Tensors.At(i * 2 + 1), AO_Tensors.At(i * 2 + 1)))
return false;
//---
CBufferFloat *inp = NULL;
if(i == 0)
{
inp = prevLayer.getOutput();
temp = prevLayer.getGradient();
}
else
{
temp = FF_Tensors.At(i * 6 - 1);
inp = FF_Tensors.At(i * 6 - 4);
}
if(IsStopped() || !ConvolutionInputGradients(QKV_Weights.At(i * (optimization == SGD ? 2 : 3)), QKV_Tensors.At(i * 2 + 1), inp, temp, iWindow, 3 * iWindowKey * iHeads, None))
return false;
//--- Sum and normilize gradients
if(IsStopped() || !SumAndNormilize(out_grad, temp, temp, iWindow))
return false;
if(i > 0)
out_grad = temp;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::ConvolutionInputGradients(CBufferFloat *weights, CBufferFloat *gradient, CBufferFloat *inputs, CBufferFloat *inp_gradient, uint window, uint window_out, uint activ, uint shift_out = 0, uint step = 0)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(weights) == POINTER_INVALID || CheckPointer(gradient) == POINTER_INVALID || CheckPointer(inputs) == POINTER_INVALID
|| CheckPointer(inp_gradient) == POINTER_INVALID)
return false;
//---
if(weights.GetIndex() < 0)
return false;
if(gradient.GetIndex() < 0)
return false;
if(inputs.GetIndex() < 0)
return false;
if(inp_gradient.GetIndex() < 0)
return false;
if(step == 0)
step = window;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = inputs.Total();
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientConv, def_k_chgc_matrix_w, weights.GetIndex());
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientConv, def_k_chgc_matrix_g, gradient.GetIndex());
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientConv, def_k_chgc_matrix_o, inputs.GetIndex());
OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientConv, def_k_chgc_matrix_ig, inp_gradient.GetIndex());
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_outputs, gradient.Total() - shift_out);
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_step, (int)step);
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_window_in, (int)window);
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_window_out, (int)window_out);
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_activation, (int)activ);
OpenCL.SetArgument(def_k_CalcHiddenGradientConv, def_k_chgc_shift_out, (int)shift_out);
if(!OpenCL.Execute(def_k_CalcHiddenGradientConv, 1, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s: %s", __FUNCSIG__, error);
return false;
}
//---
return true;//inp_gradient.BufferRead();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::AttentionInsideGradients(CBufferFloat *qkv, CBufferFloat *qkv_g, CBufferFloat *scores, CBufferFloat *scores_g, CBufferFloat *gradient)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(qkv) == POINTER_INVALID || CheckPointer(qkv_g) == POINTER_INVALID ||
CheckPointer(scores) == POINTER_INVALID || CheckPointer(scores_g) == POINTER_INVALID || CheckPointer(gradient) == POINTER_INVALID)
return false;
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iHeads;
if(qkv.GetIndex() < 0)
return false;
if(qkv_g.GetIndex() < 0)
return false;
if(scores.GetIndex() < 0)
return false;
if(scores_g.GetIndex() < 0)
return false;
if(gradient.GetIndex() < 0)
return false;
//---
OpenCL.SetArgumentBuffer(def_k_MHAttentionGradients, def_k_mhag_qkv, qkv.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHAttentionGradients, def_k_mhag_qkv_g, qkv_g.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHAttentionGradients, def_k_mhag_score, scores.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHAttentionGradients, def_k_mhag_score_g, scores_g.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHAttentionGradients, def_k_mhag_gradient, gradient.GetIndex());
OpenCL.SetArgument(def_k_MHAttentionGradients, def_k_mhag_dimension, (int)iWindowKey);
if(!OpenCL.Execute(def_k_MHAttentionGradients, 2, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s: %s", __FUNCSIG__, error);
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
CBufferFloat *inputs = NeuronOCL.getOutput();
for(uint l = 0; l < iLayers; l++)
{
if(IsStopped() || !ConvolutuionUpdateWeights(QKV_Weights.At(l * (optimization == SGD ? 2 : 3)), QKV_Tensors.At(l * 2 + 1), inputs, (optimization == SGD ? QKV_Weights.At(l * 2 + 1) : QKV_Weights.At(l * 3 + 1)), (optimization == SGD ? NULL : QKV_Weights.At(l * 3 + 2)), iWindow, 3 * iWindowKey * iHeads))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 6 : 9)), FF_Tensors.At(l * 6 + 3), AO_Tensors.At(l * 2), (optimization == SGD ? FF_Weights.At(l * 6 + 3) : FF_Weights.At(l * 9 + 3)), (optimization == SGD ? NULL : FF_Weights.At(l * 9 + 6)), iWindowKey * iHeads, iWindow))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 6 : 9) + 1), FF_Tensors.At(l * 6 + 4), FF_Tensors.At(l * 6), (optimization == SGD ? FF_Weights.At(l * 6 + 4) : FF_Weights.At(l * 9 + 4)), (optimization == SGD ? NULL : FF_Weights.At(l * 9 + 7)), iWindow, 4 * iWindow))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 6 : 9) + 2), FF_Tensors.At(l * 6 + 5), FF_Tensors.At(l * 6 + 1), (optimization == SGD ? FF_Weights.At(l * 6 + 5) : FF_Weights.At(l * 9 + 5)), (optimization == SGD ? NULL : FF_Weights.At(l * 9 + 8)), 4 * iWindow, iWindow))
return false;
inputs = FF_Tensors.At(l * 6 + 2);
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::ConvolutuionUpdateWeights(CBufferFloat *weights, CBufferFloat *gradient, CBufferFloat *inputs, CBufferFloat *momentum1, CBufferFloat *momentum2, uint window, uint window_out, uint step = 0)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(weights) == POINTER_INVALID || CheckPointer(gradient) == POINTER_INVALID || CheckPointer(inputs) == POINTER_INVALID || CheckPointer(momentum1) == POINTER_INVALID)
return false;
if(step == 0)
step = window;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = weights.Total();
if(weights.GetIndex() < 0)
return false;
if(optimization == SGD)
{
if(gradient.GetIndex() < 0)
return false;
if(inputs.GetIndex() < 0)
return false;
if(momentum1.GetIndex() < 0)
return false;
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvMomentum, def_k_uwcm_matrix_w, weights.GetIndex());
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvMomentum, def_k_uwcm_matrix_g, gradient.GetIndex());
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvMomentum, def_k_uwcm_matrix_i, inputs.GetIndex());
OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvMomentum, def_k_uwcm_matrix_dw, momentum1.GetIndex());
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_inputs, inputs.Total());
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_learning_rates, lr);
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_momentum, alpha);
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_window_in, (int)window);
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_window_out, (int)window_out);
OpenCL.SetArgument(def_k_UpdateWeightsConvMomentum, def_k_uwcm_step, (int)step);
ResetLastError();
if(!OpenCL.Execute(def_k_UpdateWeightsConvMomentum, 1, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s Momentum: %s", __FUNCSIG__, error);
return false;
}
}
else
{
global_work_size[0] = window + 1;
if(CheckPointer(momentum2) == POINTER_INVALID)
return false;
if(gradient.GetIndex() < 0)
return false;
if(inputs.GetIndex() < 0)
return false;
if(momentum1.GetIndex() < 0)
return false;
if(momentum2.GetIndex() < 0)
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_w, weights.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_g, gradient.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_i, inputs.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_m, momentum1.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateWeightsConvAdam, def_k_uwca_matrix_v, momentum2.GetIndex()))
return false;
float lt = (float)(lr * sqrt(1 - pow(b2, t)) / (1 - pow(b1, t)));
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwa_inputs, inputs.Total()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_l, lt))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_b1, b1))
return false;
if(!OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_b2, b2))
return false;
OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_window_in, (int)window);
OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_window_out, (int)window_out);
OpenCL.SetArgument(def_k_UpdateWeightsConvAdam, def_k_uwca_step, (int)step);
ResetLastError();
if(!OpenCL.Execute(def_k_UpdateWeightsConvAdam, 1, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s Adam: %s", __FUNCSIG__, error);
return false;
}
t++;
}
//---
global_work_size[0] = window_out;
OpenCL.SetArgumentBuffer(def_k_NormilizeWeights, def_k_norm_buffer, weights.GetIndex());
OpenCL.SetArgument(def_k_NormilizeWeights, def_k_norm_dimension, (int)window + 1);
if(!OpenCL.Execute(def_k_NormilizeWeights, 1, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s Normalize: %s", __FUNCSIG__, error);
return false;
}
//---
return true;//weights.BufferRead();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
//--- Saving constants
if(!FileWriteInteger(file_handle, iLayers, INT_VALUE) || !FileWriteInteger(file_handle, iHeads, INT_VALUE) || !FileWriteInteger(file_handle, iWindow, INT_VALUE) ||
!FileWriteInteger(file_handle, iUnits, INT_VALUE) || !FileWriteInteger(file_handle, iWindowKey, INT_VALUE))
return false;
//--- Saving objects
if(!QKV_Tensors.Save(file_handle) || !QKV_Weights.Save(file_handle) || !S_Tensors.Save(file_handle) || !AO_Tensors.Save(file_handle) ||
!FF_Tensors.Save(file_handle) || !FF_Weights.Save(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//--- Loading constants
iLayers = FileReadInteger(file_handle, INT_VALUE);
iHeads = FileReadInteger(file_handle, INT_VALUE);
iWindow = FileReadInteger(file_handle, INT_VALUE);
iUnits = FileReadInteger(file_handle, INT_VALUE);
iWindowKey = FileReadInteger(file_handle, INT_VALUE);
//--- Loading objects
if(!QKV_Tensors.Load(file_handle) || !QKV_Weights.Load(file_handle) || !S_Tensors.Load(file_handle) || !AO_Tensors.Load(file_handle) ||
!FF_Tensors.Load(file_handle) || !FF_Weights.Load(file_handle))
return false;
if(!QKV_Tensors.SetOpenCL(OpenCL) || !QKV_Weights.SetOpenCL(OpenCL) || !S_Tensors.SetOpenCL(OpenCL) || !AO_Tensors.SetOpenCL(OpenCL) ||
!FF_Tensors.SetOpenCL(OpenCL) || !FF_Weights.SetOpenCL(OpenCL))
return false;
//---
Output = FF_Tensors.At(iLayers * 6 - 4);
Gradient = FF_Tensors.At(iLayers * 6 - 1);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronMLMHAttentionOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
QKV_Tensors.SetOpenCL(OpenCL);
QKV_Weights.SetOpenCL(OpenCL);
S_Tensors.SetOpenCL(OpenCL);
AO_Tensors.SetOpenCL(OpenCL);
FF_Tensors.SetOpenCL(OpenCL);
FF_Weights.SetOpenCL(OpenCL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronMLMHAttentionOCL::GetLayerInfo(void)
{
CLayerDescription* result = CNeuronBaseOCL::GetLayerInfo();
if(!result)
return result;
//---
result.window = (int)iWindow;
result.step = (int)iHeads;
result.window_out = (int)iWindowKey;
result.count = (int)iUnits;
result.layers = (int)iLayers;
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
float CNeuronBaseOCL::GenerateWeight(void)
{
xor128;
float result = (float)rnd_w / UINT_MAX;
if(result == 0)
result = GenerateWeight();
//---
return result;
}
//+------------------------------------------------------------------+
///\ingroup neuron_base
///\class CNeuronDropoutOCL
///\brief The Dropout neuron for GPU calculation.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/9112#para2">the link.</A>
//+------------------------------------------------------------------+
class CNeuronDropoutOCL : public CNeuronBaseOCL
{
protected:
CNeuronBaseOCL *PrevLayer;
float OutProbability;
int OutNumber;
CBufferFloat *DropOutMultiplier;
float dInitValue;
//---
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< \brief Feed Forward method.@param NeuronOCL Pointer to previos layer.
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) {return true;} ///< Blank method for updating weights.@param NeuronOCL Pointer to previos layer.
//---
int RND(void) { xor128; return (int)((float)(Neurons() - 1) / UINT_MAX * rnd_w); } ///< Generates a random neuron position to turn off
public:
/** Constructor */
CNeuronDropoutOCL(void);
/** Destructor */
~CNeuronDropoutOCL(void);
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, float out_prob, ENUM_OPTIMIZATION optimization_type, uint batch);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object. #param[in] numNeurons Number of neurons in layer #param[in] out_prob Probability of neurons shutdown @param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
//---
virtual int getOutputIndex(void) { return (bTrain ? Output.GetIndex() : PrevLayer.getOutputIndex()); } ///< Get index of output buffer @return Index
virtual int getGradientIndex(void) { return (bTrain ? Gradient.GetIndex() : PrevLayer.getGradientIndex()); } ///< Get index of gradient buffer @return Index
//---
virtual int getOutputVal(float &values[]) { return (bTrain ? Output.GetData(values) : PrevLayer.getOutputVal(values)); } ///< Get values of output buffer @param[out] values Array of data @return number of items
virtual int getOutputVal(CArrayFloat *values) { return (bTrain ? Output.GetData(values) : PrevLayer.getOutputVal(values)); } ///< Get values of output buffer @param[out] values Array of data @return number of items
virtual int getGradient(float &values[]) { return (bTrain ? Gradient.GetData(values) : PrevLayer.getGradient(values)); } ///< Get values of gradient buffer @param[out] values Array of data @return number of items
virtual CBufferFloat *getOutput(void) { return (bTrain ? Output : PrevLayer.getOutput()); } ///< Get pointer of output buffer @return Pointer to object
virtual CBufferFloat *getGradient(void) { return (bTrain ? Gradient : PrevLayer.getGradient()); } ///< Get pointer of gradient buffer @return Pointer to object
//---
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
//---
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) const { return defNeuronDropoutOCL; }///< Identificator of class.@return Type of class
virtual CLayerDescription* GetLayerInfo(void);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronDropoutOCL::CNeuronDropoutOCL(void) : OutProbability((float)0.1),
OutNumber(0),
dInitValue(1.0)
{
PrevLayer = NULL;
DropOutMultiplier = new CBufferFloat();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronDropoutOCL::~CNeuronDropoutOCL(void)
{
if(CheckPointer(DropOutMultiplier) != POINTER_INVALID)
delete DropOutMultiplier;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDropoutOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, float out_prob, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons, optimization_type, batch))
return false;
OutProbability = out_prob;
OutNumber = (int)(numNeurons * out_prob);
dInitValue = 1 / (1 - OutProbability);
if(CheckPointer(DropOutMultiplier) == POINTER_INVALID)
DropOutMultiplier = new CBufferFloat();
if(!DropOutMultiplier.BufferInit(numNeurons + 1, dInitValue))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDropoutOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
//---
activation = (ENUM_ACTIVATION)NeuronOCL.Activation();
PrevLayer = NeuronOCL;
if(!bTrain)
return true;
//---
if(CheckPointer(DropOutMultiplier) == POINTER_INVALID)
DropOutMultiplier = new CBufferFloat();
if(!DropOutMultiplier.BufferInit(NeuronOCL.Neurons(), dInitValue))
return false;
for(int i = 0; i < OutNumber; i++)
{
uint p = RND();
float val = DropOutMultiplier.At(p);
if(val == 0 || val == DBL_MAX)
{
i--;
continue;
}
if(!DropOutMultiplier.Update(RND(), 0))
return false;
}
//---
if(!DropOutMultiplier.BufferCreate(OpenCL))
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
int i = Neurons() % 4;
global_work_size[0] = (Neurons() - i) / 4 + (i > 0 ? 1 : 0);
if(!OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_input, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_map, DropOutMultiplier.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_out, Output.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_Dropout, def_k_dout_dimension, Neurons()))
return false;
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_Dropout, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Dropout: %d", GetLastError());
return false;
}
//if(!Output.BufferRead())
// return false;
//DropOutMultiplier.BufferFree();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDropoutOCL::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
//---
if(!bTrain)
return true;
//---
if(CheckPointer(DropOutMultiplier) == POINTER_INVALID)
return false;
//---
if(!DropOutMultiplier.BufferCreate(OpenCL))
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
int i = Neurons() % 4;
global_work_size[0] = (Neurons() - i) / 4 + (i > 0 ? 1 : 0);
if(!OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_input, Gradient.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_map, DropOutMultiplier.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_out, NeuronOCL.getGradientIndex()))
return false;
if(!OpenCL.SetArgument(def_k_Dropout, def_k_dout_dimension, Neurons()))
return false;
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_Dropout, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Dropout: %d", GetLastError());
return false;
}
//if(!NeuronOCL.getGradient().BufferRead())
// return false;
//DropOutMultiplier.BufferFree();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDropoutOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
//---
if(FileWriteDouble(file_handle, OutProbability) <= 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDropoutOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//---
OutProbability = (float)FileReadDouble(file_handle);
OutNumber = (int)(Neurons() * OutProbability);
dInitValue = 1 / (1 - OutProbability);
if(CheckPointer(DropOutMultiplier) == POINTER_INVALID)
DropOutMultiplier = new CBufferFloat();
if(!DropOutMultiplier.BufferInit(Neurons() + 1, dInitValue))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronDropoutOCL::GetLayerInfo(void)
{
CLayerDescription* result = CNeuronBaseOCL::GetLayerInfo();
if(!result)
return result;
//---
result.probability = OutProbability;
//---
return result;
}
//+------------------------------------------------------------------+
///\class CNeuronBatchNormOCL
///\brief The class of Batch Normalization neuron for GPU calculation.
///\details Detailed description on <A HREF="https://www.mql5.com/en/articles/9207#para4">the link.</A>
//+------------------------------------------------------------------+
class CNeuronBatchNormOCL : public CNeuronBaseOCL
{
protected:
CNeuronBaseOCL *PrevLayer; ///< Pointer to the object of the previous layer
int iBatchSize; ///< Batch size
int iBatchCount; ///< Batch count
CBufferFloat *BatchOptions; ///< Container of method parameters
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< \brief Feed Forward method of calling kernel ::BatchFeedForward().@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL); ///< Method for updating weights.\details Calling one of kernels ::UpdateBatchOptionsMomentum() or ::UpdateBatchOptionsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
public:
/** Constructor */
CNeuronBatchNormOCL(void);
/** Destructor */~CNeuronBatchNormOCL(void);
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, uint batchSize, ENUM_OPTIMIZATION optimization_type);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object. #param[in] numNeurons Number of neurons in layer @param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
//---
virtual int getOutputIndex(void) { return (iBatchSize > 1 ? Output.GetIndex() : PrevLayer.getOutputIndex()); } ///< Get index of output buffer @return Index
virtual int getGradientIndex(void) { return (iBatchSize > 1 ? Gradient.GetIndex() : PrevLayer.getGradientIndex()); } ///< Get index of gradient buffer @return Index
//---
virtual int getOutputVal(float &values[]) { return (iBatchSize > 1 ? Output.GetData(values) : PrevLayer.getOutputVal(values)); } ///< Get values of output buffer @param[out] values Array of data @return number of items
virtual int getOutputVal(CArrayFloat *values) { return (iBatchSize > 1 ? Output.GetData(values) : PrevLayer.getOutputVal(values)); } ///< Get values of output buffer @param[out] values Array of data @return number of items
virtual int getGradient(float &values[]) { return (iBatchSize > 1 ? Gradient.GetData(values) : PrevLayer.getGradient(values)); } ///< Get values of gradient buffer @param[out] values Array of data @return number of items
virtual CBufferFloat *getOutput(void) { return (iBatchSize > 1 ? Output : PrevLayer.getOutput()); } ///< Get pointer of output buffer @return Pointer to object
virtual CBufferFloat *getGradient(void) { return (iBatchSize > 1 ? Gradient : PrevLayer.getGradient()); } ///< Get pointer of gradient buffer @return Pointer to object
virtual CBufferFloat *getBatchOptions(void) { return (iBatchSize > 1 ? BatchOptions : NULL); } ///< Get pointer of Batch Options buffer @return Pointer to object
//---
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradientBatch(). @param NeuronOCL Pointer to next layer.
//---
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) const { return defNeuronBatchNormOCL; }///< Identificator of class.@return Type of class
virtual CLayerDescription* GetLayerInfo(void);
virtual void SetOpenCL(COpenCLMy *obj);
//---
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronBatchNormOCL::CNeuronBatchNormOCL(void) : iBatchSize(1)
{
PrevLayer = NULL;
BatchOptions = NULL;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronBatchNormOCL::~CNeuronBatchNormOCL(void)
{
if(CheckPointer(PrevLayer) != POINTER_INVALID)
PrevLayer = NULL;
if(CheckPointer(BatchOptions) != POINTER_INVALID)
delete BatchOptions;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBatchNormOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, uint batchSize, ENUM_OPTIMIZATION optimization_type)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons, optimization_type, batchSize))
return false;
activation = None;
iBatchSize = (int)batchSize;
//---
if(CheckPointer(BatchOptions) != POINTER_INVALID)
delete BatchOptions;
int count = (int)numNeurons * (optimization_type == SGD ? 7 : 9);
BatchOptions = new CBufferFloat();
if(!BatchOptions.BufferInit(count, 0.0f))
return false;
if(!BatchOptions.BufferCreate(OpenCL))
return false;
iBatchCount = 1;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBatchNormOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
//---
PrevLayer = NeuronOCL;
if(iBatchSize <= 1)
{
activation = (ENUM_ACTIVATION)NeuronOCL.Activation();
return true;
}
//---
if(CheckPointer(BatchOptions) == POINTER_INVALID)
{
int count = Neurons() * (optimization == SGD ? 7 : 9);
BatchOptions = new CBufferFloat();
if(!BatchOptions.BufferInit(count, 0))
return false;
}
//if(!BatchOptions.BufferCreate(OpenCL))
// return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Neurons();
iBatchCount = MathMin(iBatchCount, iBatchSize);
if(!OpenCL.SetArgumentBuffer(def_k_BatchFeedForward, def_k_bff_inputs, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_BatchFeedForward, def_k_bff_options, BatchOptions.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_BatchFeedForward, def_k_bff_output, Output.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_BatchFeedForward, def_k_bff_batch, (int)iBatchCount))
return false;
if(!OpenCL.SetArgument(def_k_BatchFeedForward, def_k_bff_optimization, (int)optimization))
return false;
if(!OpenCL.SetArgument(def_k_BatchFeedForward, def_k_bff_activation, (int)activation))
return false;
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_BatchFeedForward, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Batch Feed Forward: %d", GetLastError());
return false;
}
iBatchCount++;
//vector<float> temp;
//Output.GetData(temp);
//float delta = MathAbs(temp - prev_output).Sum();
//prev_output = temp;
//if(temp.HasNan()>0)
// Sleep(0);
//string error;
//CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
//BatchOptions.GetData(temp);
//if(temp.HasNan()>0)
// Sleep(0);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBatchNormOCL::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
//---
if(iBatchSize <= 1)
return (CheckPointer(PrevLayer) != POINTER_INVALID);
//---
if(CheckPointer(BatchOptions) == POINTER_INVALID || BatchOptions.GetIndex() < 0)
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Neurons();
if(!OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientBatch, def_k_bchg_matrix_i, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientBatch, def_k_bchg_options, BatchOptions.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientBatch, def_k_bchg_matrix_g, Gradient.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientBatch, def_k_bchg_matrix_ig, NeuronOCL.getGradientIndex()))
return false;
if(!OpenCL.SetArgument(def_k_CalcHiddenGradientBatch, def_k_bchg_activation, NeuronOCL.Activation()))
return false;
if(!OpenCL.SetArgument(def_k_CalcHiddenGradientBatch, def_k_bchg_batch, (int)iBatchCount))
return false;
if(!OpenCL.SetArgument(def_k_CalcHiddenGradientBatch, def_k_bchg_optimization, (int)optimization))
return false;
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_CalcHiddenGradientBatch, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Batch CalcHiddenGradient: %d", GetLastError());
return false;
}
//if(!NeuronOCL.getGradient().BufferRead())
// return false;
//BatchOptions.BufferFree();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBatchNormOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
//---
if(iBatchSize <= 1)
return (CheckPointer(PrevLayer) != POINTER_INVALID);
//---
if(CheckPointer(BatchOptions) == POINTER_INVALID || BatchOptions.GetIndex() < 0)
return false;
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Neurons();
//---
if(optimization == SGD)
{
if(!OpenCL.SetArgumentBuffer(def_k_UpdateBatchOptionsMomentum, def_k_buom_options, BatchOptions.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateBatchOptionsMomentum, def_k_buom_matrix_g, Gradient.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsMomentum, def_k_buom_learning_rates, lr))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsMomentum, def_k_buom_momentum, alpha))
return false;
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_UpdateBatchOptionsMomentum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateBatchOptionsMomentum %d", GetLastError());
return false;
}
}
else
{
if(!OpenCL.SetArgumentBuffer(def_k_UpdateBatchOptionsAdam, def_k_buoa_options, BatchOptions.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateBatchOptionsAdam, def_k_buoa_matrix_g, Gradient.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsAdam, def_k_buoa_l, lr))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsAdam, def_k_buoa_b1, b1))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsAdam, def_k_buoa_b2, b2))
return false;
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_UpdateBatchOptionsAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateBatchOptionsAdam %d", GetLastError());
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBatchNormOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
//---
if(FileWriteInteger(file_handle, iBatchSize, INT_VALUE) <= 0)
return false;
return BatchOptions.Save(file_handle);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBatchNormOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//---
iBatchSize = FileReadInteger(file_handle, INT_VALUE);
if(!BatchOptions.Load(file_handle))
return false;
if(!!OpenCL && !BatchOptions.BufferCreate(OpenCL))
return false;
iBatchCount = iBatchSize;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronBatchNormOCL::GetLayerInfo(void)
{
CLayerDescription* result = CNeuronBaseOCL::GetLayerInfo();
if(!result)
return result;
//---
result.batch = (int)iBatchSize;
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronBatchNormOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
if(!!BatchOptions)
BatchOptions.BufferCreate(obj); ///< Container of method parameters
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::GetLayerOutput(uint layer, CBufferFloat *&result)
{
if(!layers || layers.Total() <= (int)layer)
return false;
CLayer *Layer = layers.At(layer);
if(!Layer)
return false;
//---
if(!result)
{
result = new CBufferFloat();
if(!result)
return false;
}
//---
CNeuronBaseOCL *temp = Layer.At(0);
if(!temp || temp.getOutputVal(result) <= 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::GetLayerOutput(uint layer, vector<float> &result)
{
if(!layers || layers.Total() <= (int)layer)
return false;
CLayer *Layer = layers.At(layer);
if(!Layer)
return false;
//---
//---
CNeuronBaseOCL *temp = Layer.At(0);
if(!temp || temp.getOutputVal(result) <= 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNet::SetOpenCL(COpenCLMy *obj)
{
if(!!opencl && opencl != obj)
delete opencl;
//---
if(!obj || !layers)
return;
//---
opencl = obj;
for(int i = 0; i < layers.Total(); i++)
{
CLayer *layer = layers.At(i);
if(!layer)
continue;
layer.SetOpenCL(obj);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronLSTMOCL : public CNeuronBaseOCL
{
protected:
CBufferFloat m_cWeightsLSTM;
CBufferFloat m_cFirstMomentumLSTM; ///< Buffer of first momentum matrix (#ADAM) or last delta weights matrix (#SGD)
CBufferFloat m_cSecondMomentumLSTM; ///< Buffer of second momentum matrix (#ADAM)
int m_iMemory;
int m_iConcatenated;
int m_iConcatenatedGradient;
int m_iHiddenState;
int m_iInputs;
int m_iWeightsGradient;
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; ///< \brief Feed Forward method.@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; ///< Method for updating weights.
public:
CNeuronLSTMOCL(void);
~CNeuronLSTMOCL(void);
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, ENUM_OPTIMIZATION optimization_type, uint batch) override;
virtual bool SetInputs(int count);
//---
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
///@}
//---
virtual bool Save(int const file_handle) override;///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle) override;///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) override const { return defNeuronLSTMOCL; }///< Identificator of class.@return Type of class
virtual bool Clear(void);
virtual CBufferFloat *getLSTMWeights(void) { return GetPointer(m_cWeightsLSTM);}
virtual void SetOpenCL(COpenCLMy *obj);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronLSTMOCL::CNeuronLSTMOCL(void) : m_iMemory(-1),
m_iConcatenated(-1),
m_iConcatenatedGradient(-1),
m_iHiddenState(-1),
m_iInputs(-1)
{}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronLSTMOCL::~CNeuronLSTMOCL(void)
{
if(!OpenCL)
return;
OpenCL.BufferFree(m_iConcatenated);
OpenCL.BufferFree(m_iConcatenatedGradient);
OpenCL.BufferFree(m_iHiddenState);
OpenCL.BufferFree(m_iMemory);
OpenCL.BufferFree(m_iWeightsGradient);
m_cFirstMomentumLSTM.BufferFree();
m_cSecondMomentumLSTM.BufferFree();
m_cWeightsLSTM.BufferFree();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTMOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons, optimization_type, batch))
return false;
//---
m_iMemory = OpenCL.AddBuffer(sizeof(float) * numNeurons * 2, CL_MEM_READ_WRITE);
if(m_iMemory < 0)
return false;
m_iHiddenState = OpenCL.AddBuffer(sizeof(float) * numNeurons, CL_MEM_READ_WRITE);
if(m_iHiddenState < 0)
return false;
m_iConcatenated = OpenCL.AddBuffer(sizeof(float) * numNeurons * 4, CL_MEM_READ_WRITE);
if(m_iConcatenated < 0)
return false;
m_iConcatenatedGradient = OpenCL.AddBuffer(sizeof(float) * numNeurons * 4, CL_MEM_READ_WRITE);
if(m_iConcatenatedGradient < 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTMOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL || NeuronOCL.Neurons() <= 0 ||
NeuronOCL.getOutputIndex() < 0 || !OpenCL)
return false;
//---
if(m_iInputs != NeuronOCL.Neurons())
{
if(!SetInputs(NeuronOCL.Neurons()))
return false;
}
//---
if(m_iMemory < 0 || m_iConcatenated < 0)
return false;
//---
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_FeedForward, def_k_lstmff_inputs, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_FeedForward, def_k_lstmff_concatenated, m_iConcatenated))
return false;
if(!OpenCL.SetArgument(def_k_LSTM_FeedForward, def_k_lstmff_inputs_size, m_iInputs))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_FeedForward, def_k_lstmff_memory, m_iMemory))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_FeedForward, def_k_lstmff_outputs, getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_FeedForward, def_k_lstmff_weights, m_cWeightsLSTM.GetIndex()))
return false;
uint global_work_offset[] = {0, 0};
uint global_work_size[] = {Neurons(), 4};
uint local_work_size[] = {1, 4};
if(!OpenCL.Execute(def_k_LSTM_FeedForward, 2, global_work_offset, global_work_size, local_work_size))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTMOCL::SetInputs(int count)
{
m_iInputs = count;
count = (int)((m_iInputs + Neurons() + 1) * Neurons());
if(!m_cWeightsLSTM.Reserve(count))
return false;
float k = (float)(1 / sqrt(Neurons() + 1));
for(int i = 0; i < count; i++)
{
if(!m_cWeightsLSTM.Add((2 * GenerateWeight()*k - k)*WeightsMultiplier))
return false;
}
if(!m_cWeightsLSTM.BufferCreate(OpenCL))
return false;
//---
if(!m_cFirstMomentumLSTM.BufferInit(count, 0))
return false;
if(!m_cFirstMomentumLSTM.BufferCreate(OpenCL))
return false;
//---
if(!m_cSecondMomentumLSTM.BufferInit(count, 0))
return false;
if(!m_cSecondMomentumLSTM.BufferCreate(OpenCL))
return false;
if(m_iWeightsGradient >= 0)
OpenCL.BufferFree(m_iWeightsGradient);
m_iWeightsGradient = OpenCL.AddBuffer(sizeof(float) * count, CL_MEM_READ_WRITE);
if(m_iWeightsGradient < 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTMOCL::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL || NeuronOCL.Neurons() <= 0 || NeuronOCL.getGradientIndex() < 0 ||
NeuronOCL.getOutputIndex() < 0 || !OpenCL)
return false;
//---
if(m_cWeightsLSTM.GetIndex() < 0 || m_cFirstMomentumLSTM.GetIndex() < 0 ||
m_cSecondMomentumLSTM.GetIndex() < 0)
return false;
if(m_iInputs < 0 || m_iConcatenated < 0 || m_iMemory < 0 ||
m_iConcatenatedGradient < 0 || m_iHiddenState < 0 || m_iInputs != NeuronOCL.Neurons())
return false;
//---
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_ConcatenatedGradient, def_k_lstmcg_concatenated, m_iConcatenated))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_ConcatenatedGradient, def_k_lstmcg_concatenated_gradient, m_iConcatenatedGradient))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_ConcatenatedGradient, def_k_lstmcg_gradient, getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_ConcatenatedGradient, def_k_lstmcg_memory, m_iMemory))
return false;
uint global_work_offset[] = {0};
uint global_work_size[] = {Neurons()};
if(!OpenCL.Execute(def_k_LSTM_ConcatenatedGradient, 1, global_work_offset, global_work_size))
return false;
//---
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_HiddenGradient, def_k_lstmhg_concatenated_gradient, m_iConcatenatedGradient))
return false;
if(!OpenCL.SetArgument(def_k_LSTM_HiddenGradient, def_k_lstmhg_hidden_size, Neurons()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_HiddenGradient, def_k_lstmhg_hidden_state, m_iHiddenState))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_HiddenGradient, def_k_lstmhg_inputs, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_HiddenGradient, def_k_lstmhg_inputs_gradient, NeuronOCL.getGradientIndex()))
return false;
if(!OpenCL.SetArgument(def_k_LSTM_HiddenGradient, def_k_lstmhg_inputs_size, m_iInputs))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_HiddenGradient, def_k_lstmhg_output, getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_HiddenGradient, def_k_lstmhg_weeights, m_cWeightsLSTM.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_HiddenGradient, def_k_lstmhg_weights_gradient, m_iWeightsGradient))
return false;
if(!OpenCL.Execute(def_k_LSTM_HiddenGradient, 1, global_work_offset, global_work_size))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTMOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(!OpenCL || m_cWeightsLSTM.GetIndex() < 0 || m_iWeightsGradient < 0 ||
m_cFirstMomentumLSTM.GetIndex() < 0 || m_cSecondMomentumLSTM.GetIndex() < 0)
return false;
//---
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_UpdateWeightsAdam, def_k_lstmuw_weights, m_cWeightsLSTM.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_UpdateWeightsAdam, def_k_lstmuw_weights_gradient, m_iWeightsGradient))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_UpdateWeightsAdam, def_k_lstmuw_matrix_m, m_cFirstMomentumLSTM.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_LSTM_UpdateWeightsAdam, def_k_lstmuw_matrix_v, m_cSecondMomentumLSTM.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_LSTM_UpdateWeightsAdam, def_k_lstmuw_l, lr))
return false;
if(!OpenCL.SetArgument(def_k_LSTM_UpdateWeightsAdam, def_k_lstmuw_b1, b1))
return false;
if(!OpenCL.SetArgument(def_k_LSTM_UpdateWeightsAdam, def_k_lstmuw_b2, b2))
return false;
uint global_work_offset[] = {0, 0};
uint global_work_size[] = {m_iInputs + Neurons() + 1, Neurons()};
if(!OpenCL.Execute(def_k_LSTM_UpdateWeightsAdam, 2, global_work_offset, global_work_size))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTMOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
if(FileWriteInteger(file_handle, m_iInputs, INT_VALUE) < sizeof(m_iInputs))
return false;
if((m_cWeightsLSTM.GetIndex() >= 0 && !m_cWeightsLSTM.BufferRead()) || !m_cWeightsLSTM.Save(file_handle))
return false;
if((m_cFirstMomentumLSTM.GetIndex() >= 0 && !m_cFirstMomentumLSTM.BufferRead()) || !m_cFirstMomentumLSTM.Save(file_handle))
return false;
if((m_cSecondMomentumLSTM.GetIndex() >= 0 && !m_cSecondMomentumLSTM.BufferRead()) || !m_cSecondMomentumLSTM.Save(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTMOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
m_iInputs = FileReadInteger(file_handle);
//---
m_cWeightsLSTM.BufferFree();
if(!m_cWeightsLSTM.Load(file_handle) || !m_cWeightsLSTM.BufferCreate(OpenCL))
return false;
//---
m_cFirstMomentumLSTM.BufferFree();
if(!m_cFirstMomentumLSTM.Load(file_handle) || !m_cFirstMomentumLSTM.BufferCreate(OpenCL))
return false;
//---
m_cSecondMomentumLSTM.BufferFree();
if(!m_cSecondMomentumLSTM.Load(file_handle) || !m_cSecondMomentumLSTM.BufferCreate(OpenCL))
return false;
//---
if(m_iMemory >= 0)
OpenCL.BufferFree(m_iMemory);
m_iMemory = OpenCL.AddBuffer(sizeof(float) * 2 * Neurons(), CL_MEM_READ_WRITE);
if(m_iMemory < 0)
return false;
//---
if(m_iConcatenated >= 0)
OpenCL.BufferFree(m_iConcatenated);
m_iConcatenated = OpenCL.AddBuffer(sizeof(float) * 4 * Neurons(), CL_MEM_READ_WRITE);
if(m_iConcatenated < 0)
return false;
//---
if(m_iConcatenatedGradient >= 0)
OpenCL.BufferFree(m_iConcatenatedGradient);
m_iConcatenatedGradient = OpenCL.AddBuffer(sizeof(float) * 4 * Neurons(), CL_MEM_READ_WRITE);
if(m_iConcatenatedGradient < 0)
return false;
//---
if(m_iHiddenState >= 0)
OpenCL.BufferFree(m_iHiddenState);
m_iHiddenState = OpenCL.AddBuffer(sizeof(float) * Neurons(), CL_MEM_READ_WRITE);
if(m_iHiddenState < 0)
return false;
//---
if(m_iWeightsGradient >= 0)
OpenCL.BufferFree(m_iWeightsGradient);
m_iWeightsGradient = OpenCL.AddBuffer(sizeof(float) * m_cWeightsLSTM.Total(), CL_MEM_READ_WRITE);
if(m_iWeightsGradient < 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronLSTMOCL::Clear(void)
{
float emp[];
ArrayResize(emp, Neurons() * 2);
ArrayInitialize(emp, 0);
if(!OpenCL.BufferWrite(m_iHiddenState, emp, 0, 0, Neurons()))
return false;
if(!OpenCL.BufferWrite(m_iMemory, emp, 0, 0, Neurons() * 2))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronLSTMOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
m_cWeightsLSTM.BufferCreate(OpenCL);
m_cFirstMomentumLSTM.BufferCreate(OpenCL);
m_cSecondMomentumLSTM.BufferCreate(OpenCL);
m_iWeightsGradient = OpenCL.AddBuffer(sizeof(float) * m_cWeightsLSTM.Total(), CL_MEM_READ_WRITE);
int numNeurons = Neurons();
m_iMemory = OpenCL.AddBuffer(sizeof(float) * numNeurons * 2, CL_MEM_READ_WRITE);
m_iHiddenState = OpenCL.AddBuffer(sizeof(float) * numNeurons, CL_MEM_READ_WRITE);
m_iConcatenated = OpenCL.AddBuffer(sizeof(float) * numNeurons * 4, CL_MEM_READ_WRITE);
m_iConcatenatedGradient = OpenCL.AddBuffer(sizeof(float) * numNeurons * 4, CL_MEM_READ_WRITE);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#ifndef class_vae
#include "..\Unsupervised\AE\VAE.mqh"
#endif
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronSoftMaxOCL : public CNeuronBaseOCL
{
protected:
uint iHeads;
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override { return true; } ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
public:
CNeuronSoftMaxOCL(void) : iHeads(1) {};
~CNeuronSoftMaxOCL(void) {};
//---
///\ingroup neuron_base_gr
///@{
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
virtual bool calcOutputGradients(CArrayFloat *Target, float &error) override; ///< Method of output gradients calculation by calling kernel ::CalcOutputGradient().@param Target Traget value
virtual void SetHeads(int heads) { iHeads = heads; }
///@}
//---
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual CLayerDescription* GetLayerInfo(void) override;
virtual int Type(void) override const { return defNeuronSoftMaxOCL; }///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftMaxOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(!OpenCL || !NeuronOCL)
return false;
uint global_work_offset[2] = {0, 0};
uint size = Output.Total() / iHeads;
uint global_work_size[2] = { size, iHeads };
uint local_work_size[2] = { size, 1 };
OpenCL.SetArgumentBuffer(def_k_SoftMax_FeedForward, def_k_softmaxff_inputs, NeuronOCL.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_SoftMax_FeedForward, def_k_softmaxff_outputs, getOutputIndex());
OpenCL.SetArgument(def_k_SoftMax_FeedForward, def_k_softmaxff_total, (int)size);
if(!OpenCL.Execute(def_k_SoftMax_FeedForward, 2, global_work_offset, global_work_size, local_work_size))
{
printf("Error of execution kernel SoftMax FeedForward: %d", GetLastError());
string error;
if(CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error))
Print(error);
return false;
}
//vector<float> temp;
//Output.GetData(temp);
//float delta = MathAbs((temp - prev_output)).Sum();
//prev_output = temp;
//string error;
//CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftMaxOCL::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[2] = {0, 0};
uint size = Output.Total() / iHeads;
uint global_work_size[2] = {size, iHeads};
OpenCL.SetArgumentBuffer(def_k_SoftMax_HiddenGradient, def_k_softmaxhg_input_gr, NeuronOCL.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_SoftMax_HiddenGradient, def_k_softmaxhg_output_gr, getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_SoftMax_HiddenGradient, def_k_softmaxhg_outputs, getOutputIndex());
if(!OpenCL.Execute(def_k_SoftMax_HiddenGradient, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel SoftMax InputGradients: %d", GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftMaxOCL::calcOutputGradients(CArrayFloat *Target, float &error)
{
if(!OpenCL || !Target)
return false;
//---
if(!Output.BufferRead())
return false;
if(Output.Total() != Target.Total())
return false;
error = 0;
for(int i = 0; i < Output.Total(); i++)
{
if(Output[i] > 0)
error += -MathAbs(Target[i]) * MathLog(Output[i]);
Gradient.Update(i, Target[i]);
}
error /= (float)iHeads;
if(!Gradient.BufferWrite())
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Output.Total();
OpenCL.SetArgumentBuffer(def_k_SoftMax_OutputGradient, def_k_softmaxog_targets, getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_SoftMax_OutputGradient, def_k_softmaxog_output_gr, getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_SoftMax_OutputGradient, def_k_softmaxog_outputs, getOutputIndex());
if(!OpenCL.Execute(def_k_SoftMax_OutputGradient, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel SoftMax OutputGradients: %d", GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronSoftMaxOCL::GetLayerInfo(void)
{
CLayerDescription* result = CNeuronBaseOCL::GetLayerInfo();
if(!result)
return result;
result.step = (int)iHeads;
result.count = (int)(Output.Total() / iHeads);
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftMaxOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
if(FileWriteInteger(file_handle, iHeads) <= 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftMaxOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
iHeads = (uint)FileReadInteger(file_handle);
if(iHeads <= 0)
iHeads = 1;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronFQF : protected CNeuronBaseOCL
{
protected:
//--- Fractal Net
CNeuronBaseOCL cFraction;
CNeuronSoftMaxOCL cSoftMax;
//--- Cosine embeding
CNeuronBaseOCL cCosine;
CNeuronBaseOCL cCosineEmbeding;
//--- Quantile Net
CNeuronBaseOCL cQuantile0;
CNeuronBaseOCL cQuantile1;
CNeuronBaseOCL cQuantile2;
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
public:
CNeuronFQF();
~CNeuronFQF();
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint actions, uint quantiles, uint numInputs, ENUM_OPTIMIZATION optimization_type, uint batch);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object. #param[in] numNeurons Number of neurons in layer @param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
//---
virtual bool Save(int const file_handle) override;///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle) override;///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) override const { return defNeuronFQF; }///< Identificator of class.@return Type of class
virtual CLayerDescription* GetLayerInfo(void) override;
virtual CObject* AsObject(void) { return GetPointer(this); }
virtual void SetOpenCL(COpenCLMy *obj);
virtual void SetActivationFunction(ENUM_ACTIVATION function) { CNeuronBaseOCL::SetActivationFunction(function); }
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronFQF::CNeuronFQF(void)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronFQF::~CNeuronFQF(void)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFQF::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint actions, uint quantiles, uint numInputs, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, actions, optimization_type, batch))
return false;
SetActivationFunction(None);
//---
if(!cFraction.Init(0, myIndex, open_cl, actions * quantiles, optimization, batch))
return false;
cFraction.SetActivationFunction(None);
//---
if(!cSoftMax.Init(0, myIndex, open_cl, actions * quantiles, optimization, batch))
return false;
cSoftMax.SetHeads(actions);
cSoftMax.SetActivationFunction(None);
//---
if(!cCosine.Init(numInputs, myIndex, open_cl, actions * quantiles, optimization, batch))
return false;
cCosine.SetActivationFunction(None);
//---
if(!cCosineEmbeding.Init(0, myIndex, open_cl, numInputs, optimization, batch))
return false;
cCosineEmbeding.SetActivationFunction(LReLU);
//---
if(!cQuantile0.Init(4 * actions * quantiles, myIndex, open_cl, numInputs, optimization, batch))
return false;
cQuantile0.SetActivationFunction(None);
//---
if(!cQuantile1.Init(actions * quantiles, myIndex, open_cl, 4 * actions * quantiles, optimization, batch))
return false;
cQuantile1.SetActivationFunction(LReLU);
//---
if(!cQuantile2.Init(0, myIndex, open_cl, actions * quantiles, optimization, batch))
return false;
cQuantile2.SetActivationFunction(None);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFQF::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(!cFraction.FeedForward(NeuronOCL))
return false;
if(!cSoftMax.FeedForward(GetPointer(cFraction)))
return false;
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[1] = Output.Total();
global_work_size[0] = cSoftMax.Neurons() / global_work_size[1];
OpenCL.SetArgumentBuffer(def_k_FQF_Cosine, def_k_fqf_cosine_softmax, cSoftMax.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_Cosine, def_k_fqf_cosine_outputs, cCosine.getOutputIndex());
if(!OpenCL.Execute(def_k_FQF_Cosine, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel FQF_Cosine: %d", GetLastError());
return false;
}
}
//---
if(!cCosineEmbeding.FeedForward(GetPointer(cCosine)))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1] = {(cCosine.Neurons() + 3) / 4};
OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_input, NeuronOCL.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_map, cCosineEmbeding.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_out, cQuantile0.getOutputIndex());
OpenCL.SetArgument(def_k_Dropout, def_k_dout_dimension, (int)cCosine.Neurons());
if(!OpenCL.Execute(def_k_Dropout, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel Dropout: %d", GetLastError());
return false;
}
}
//---
if(!cQuantile1.FeedForward(GetPointer(cQuantile0)))
return false;
//---
if(!cQuantile2.FeedForward(GetPointer(cQuantile1)))
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1] = { Neurons() };
OpenCL.SetArgumentBuffer(def_k_FQF_Output, def_k_fqfout_quantiles, cQuantile2.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_Output, def_k_fqfout_delta_taus, cSoftMax.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_Output, def_k_fqfout_output, getOutputIndex());
OpenCL.SetArgument(def_k_FQF_Output, def_k_fqfout_total, (int)(cQuantile2.Neurons() / global_work_size[0]));
if(!OpenCL.Execute(def_k_FQF_Output, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel FQF_Output: %d", GetLastError());
return false;
}
//Output.BufferInit(Output.Total(),0);
//vector<float> temp;
//Output.GetData(temp);
//float delta = MathAbs(temp - prev_output).Sum();
//prev_output = temp;
//string error;
//CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFQF::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL || !Gradient || !Output)
return false;
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2] = { cSoftMax.Neurons() / Neurons(), Neurons() };
OpenCL.SetArgumentBuffer(def_k_FQF_OutputGradient, def_k_fqfoutgr_quantiles, cQuantile2.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_OutputGradient, def_k_fqfoutgr_taus, cSoftMax.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_OutputGradient, def_k_fqfoutgr_output_gr, getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_OutputGradient, def_k_fqfoutgr_quantiles_gr, cQuantile2.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_OutputGradient, def_k_fqfoutgr_taus_gr, cSoftMax.getGradientIndex());
if(!OpenCL.Execute(def_k_FQF_OutputGradient, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel FQF_OutputGradient: %d", GetLastError());
return false;
}
}
//---
if(!cQuantile1.calcHiddenGradients(GetPointer(cQuantile2)))
return false;
if(!cQuantile0.calcHiddenGradients(GetPointer(cQuantile1)))
return false;
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2] = { cCosineEmbeding.Neurons(), 1 };
OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_state_enbeding, NeuronOCL.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_taus_embedding, cCosineEmbeding.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_quantiles_gr, cQuantile0.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_state_gr, NeuronOCL.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_taus_gr, cCosineEmbeding.getGradientIndex());
if(!OpenCL.Execute(def_k_FQF_QuantileGradient, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel FQF_OutputGradient: %d", GetLastError());
return false;
}
}
//---
if(!cCosine.calcHiddenGradients(GetPointer(cCosineEmbeding)))
return false;
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2] = { cSoftMax.Neurons() / Neurons(), Neurons() };
OpenCL.SetArgumentBuffer(def_k_FQF_CosineGradient, def_k_fqfcosgr_softmax, cSoftMax.getOutputIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_CosineGradient, def_k_fqfcosgr_output_gr, cCosine.getGradientIndex());
OpenCL.SetArgumentBuffer(def_k_FQF_CosineGradient, def_k_fqfcosgr_softmax_gr, cSoftMax.getGradientIndex());
if(!OpenCL.Execute(def_k_FQF_CosineGradient, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel FQF_CosineGradient: %d", GetLastError());
return false;
}
}
//---
//cSoftMax.getGradient().BufferRead();
if(!cSoftMax.calcInputGradients(GetPointer(cFraction)))
return false;
//cFraction.getGradient().BufferRead();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFQF::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(!cFraction.UpdateInputWeights(NeuronOCL))
return false;
if(!cCosineEmbeding.UpdateInputWeights(GetPointer(cCosine)))
return false;
if(!cQuantile1.UpdateInputWeights(GetPointer(cQuantile0)))
return false;
if(!cQuantile2.UpdateInputWeights(GetPointer(cQuantile1)))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFQF::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
if(!cFraction.Save(file_handle))
return false;
if(!cSoftMax.Save(file_handle))
return false;
if(!cCosine.Save(file_handle))
return false;
if(!cCosineEmbeding.Save(file_handle))
return false;
if(!cQuantile0.Save(file_handle))
return false;
if(!cQuantile1.Save(file_handle))
return false;
if(!cQuantile2.Save(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFQF::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cFraction.Type() ||
!cFraction.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cSoftMax.Type() ||
!cSoftMax.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cCosine.Type() ||
!cCosine.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cCosineEmbeding.Type() ||
!cCosineEmbeding.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cQuantile0.Type() ||
!cQuantile0.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cQuantile1.Type() ||
!cQuantile1.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cQuantile2.Type() ||
!cQuantile2.Load(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CLayerDescription* CNeuronFQF::GetLayerInfo(void)
{
CLayerDescription *result = CNeuronBaseOCL::GetLayerInfo();
if(!result)
return result;
result.window_out = cSoftMax.Neurons() / Neurons();
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronFQF::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
cFraction.SetOpenCL(OpenCL);
cSoftMax.SetOpenCL(OpenCL);
cCosine.SetOpenCL(OpenCL);
cCosineEmbeding.SetOpenCL(OpenCL);
cQuantile0.SetOpenCL(OpenCL);
cQuantile1.SetOpenCL(OpenCL);
cQuantile2.SetOpenCL(OpenCL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNet::getResults(vector<float> &resultVals)
{
CBufferFloat* temp;
getResults(temp);
temp.GetData(resultVals);
delete temp;
return;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNet::getResults(float &resultVals[])
{
CBufferFloat* temp;
getResults(temp);
if(!temp.GetData(resultVals))
{
delete temp;
return;
}
delete temp;
return;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronMLMHSparseAttention : public CNeuronMLMHAttentionOCL
{
protected:
float m_dSparse;
//---
virtual bool AttentionScore(CBufferFloat *qkv, CBufferFloat *scores, bool mask = true);
///< \brief Multi-heads attention scores method of calling kernel ::MHAttentionScore().
virtual bool AttentionOut(CBufferFloat *qkv, CBufferFloat *scores, CBufferFloat *out);
///< \brief Multi-heads attention out method of calling kernel ::MHAttentionOut().
public:
CNeuronMLMHSparseAttention(void) : m_dSparse(0.3f) {};
~CNeuronMLMHSparseAttention(void) {};
//---
void Sparse(float value) { m_dSparse = value;}
float Sparse(void) { return m_dSparse; }
virtual int Type(void) const { return defNeuronMLMHSparseAttentionOCL; }///< Identificator of class.@return Type of class
//--- methods for working with files
virtual bool Save(int const file_handle); ///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle); ///< Load method @param[in] file_handle handle of file @return logical result of operation
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHSparseAttention::AttentionScore(CBufferFloat *qkv, CBufferFloat *scores, bool mask = true)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(qkv) == POINTER_INVALID || CheckPointer(scores) == POINTER_INVALID)
return false;
//---
if(qkv.GetIndex() < 0)
return false;
if(scores.GetIndex() < 0)
return false;
//---
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iHeads;
OpenCL.SetArgumentBuffer(def_k_MHSparseAttentionScore, def_k_mhas_qkv, qkv.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHSparseAttentionScore, def_k_mhas_score, scores.GetIndex());
OpenCL.SetArgument(def_k_MHSparseAttentionScore, def_k_mhas_dimension, (int)iWindowKey);
OpenCL.SetArgument(def_k_MHSparseAttentionScore, def_k_mhas_sparse, m_dSparse);
if(!OpenCL.Execute(def_k_MHSparseAttentionScore, 2, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s: %s", __FUNCSIG__, error);
return false;
}
//---
//vector<float> temp;
//scores.GetData(temp);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHSparseAttention::AttentionOut(CBufferFloat *qkv, CBufferFloat *scores, CBufferFloat *out)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(qkv) == POINTER_INVALID || CheckPointer(scores) == POINTER_INVALID
|| CheckPointer(out) == POINTER_INVALID)
return false;
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = iUnits;
global_work_size[1] = iHeads;
if(qkv.GetIndex() < 0)
return false;
if(scores.GetIndex() < 0)
return false;
if(out.GetIndex() < 0)
return false;
//---
OpenCL.SetArgumentBuffer(def_k_MHSparseAttentionOut, def_k_mhao_qkv, qkv.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHSparseAttentionOut, def_k_mhao_score, scores.GetIndex());
OpenCL.SetArgumentBuffer(def_k_MHSparseAttentionOut, def_k_mhao_out, out.GetIndex());
OpenCL.SetArgument(def_k_MHSparseAttentionOut, def_k_mhao_dimension, (int)iWindowKey);
if(!OpenCL.Execute(def_k_MHSparseAttentionOut, 2, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel %s: %s", __FUNCSIG__, error);
return false;
}
//---
//vector<float> temp;
//out.GetData(temp);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHSparseAttention::Save(const int file_handle)
{
if(!CNeuronMLMHAttentionOCL::Save(file_handle))
return false;
if(FileWriteFloat(file_handle, m_dSparse) < sizeof(float))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHSparseAttention::Load(const int file_handle)
{
if(!CNeuronMLMHAttentionOCL::Load(file_handle))
return false;
m_dSparse = FileReadFloat(file_handle);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronMultiModel : public CNeuronBaseOCL
{
protected:
int iModels;
int iUpdateModel;
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL); ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
public:
CNeuronMultiModel(void) {};
~CNeuronMultiModel(void) {};
virtual bool Init(uint numInputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, ENUM_OPTIMIZATION optimization_type, int models);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object. #param[in] numNeurons Number of neurons in layer @param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
virtual void SetActivationFunction(ENUM_ACTIVATION value) { activation = value; } ///< Set the type of activation function (#ENUM_ACTIVATION)
//---
///\ingroup neuron_base_gr
///@{
virtual bool calcHiddenGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
///@}
//---
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) const { return defNeuronMultiModels; }///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMultiModel::Init(uint numInputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, ENUM_OPTIMIZATION optimization_type, int models)
{
if(CheckPointer(open_cl) == POINTER_INVALID || numNeurons <= 0)
return false;
OpenCL = open_cl;
optimization = ADAM;
iBatch = 1;
iModels = models;
//---
if(CheckPointer(Output) == POINTER_INVALID)
{
Output = new CBufferFloat();
if(CheckPointer(Output) == POINTER_INVALID)
return false;
}
if(!Output.BufferInit(numNeurons * models, 0.0))
return false;
if(!Output.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(PrevOutput) == POINTER_INVALID)
{
PrevOutput = new CBufferFloat();
if(CheckPointer(PrevOutput) == POINTER_INVALID)
return false;
}
if(!PrevOutput.BufferInit(numNeurons * models, 1.0))
return false;
if(!PrevOutput.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(Gradient) == POINTER_INVALID)
{
Gradient = new CBufferFloat();
if(CheckPointer(Gradient) == POINTER_INVALID)
return false;
}
if(!Gradient.BufferInit((numNeurons + 1)*models, 0.0))
return false;
if(!Gradient.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(Weights) == POINTER_INVALID)
{
Weights = new CBufferFloat();
if(CheckPointer(Weights) == POINTER_INVALID)
return false;
}
int count = (int)((numInputs + 1) * numNeurons * models);
if(!Weights.Reserve(count))
return false;
float k = (float)(1 / sqrt(numInputs + 1));
for(int i = 0; i < count; i++)
{
if(!Weights.Add((2 * GenerateWeight()*k - k)*WeightsMultiplier))
return false;
}
if(!Weights.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(DeltaWeights) != POINTER_INVALID)
delete DeltaWeights;
//---
if(CheckPointer(FirstMomentum) == POINTER_INVALID)
{
FirstMomentum = new CBufferFloat();
if(CheckPointer(FirstMomentum) == POINTER_INVALID)
return false;
}
if(!FirstMomentum.BufferInit(count, 0))
return false;
if(!FirstMomentum.BufferCreate(OpenCL))
return false;
//---
if(CheckPointer(SecondMomentum) == POINTER_INVALID)
{
SecondMomentum = new CBufferFloat();
if(CheckPointer(SecondMomentum) == POINTER_INVALID)
return false;
}
if(!SecondMomentum.BufferInit(count, 0))
return false;
if(!SecondMomentum.BufferCreate(OpenCL))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMultiModel::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = Output.Total() / iModels;
global_work_size[1] = iModels;
if(!OpenCL.SetArgumentBuffer(def_k_FFMultiModels, def_k_ff_matrix_w, getWeightsIndex()))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FFMultiModels, def_k_ff_matrix_i, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FFMultiModels, def_k_ff_matrix_o, Output.GetIndex()))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_FFMultiModels, def_k_ff_inputs, NeuronOCL.Neurons() / iModels))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_FFMultiModels, def_k_ff_activation, (int)activation))
{
printf("Error of set parameter kernel FeedForward: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_FFMultiModels, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel FeedForward: %d", GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMultiModel::calcHiddenGradients(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = NeuronOCL.Neurons() / iModels;
global_work_size[1] = iModels;
if(!OpenCL.SetArgumentBuffer(def_k_HGMultiModels, def_k_chg_matrix_w, getWeightsIndex()))
{
printf("Error of set parameter kernel calcHiddenGradients: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_HGMultiModels, def_k_chg_matrix_g, getGradientIndex()))
{
printf("Error of set parameter kernel calcHiddenGradients: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_HGMultiModels, def_k_chg_matrix_o, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel calcHiddenGradients: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_HGMultiModels, def_k_chg_matrix_ig, NeuronOCL.getGradientIndex()))
{
printf("Error of set parameter kernel calcHiddenGradients: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_HGMultiModels, def_k_chg_outputs, Neurons() / iModels))
{
printf("Error of set parameter kernel calcHiddenGradients: %d; line %d", GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_HGMultiModels, def_k_chg_activation, NeuronOCL.Activation()))
{
printf("Error of set parameter kernel calcHiddenGradients: %d; line %d", GetLastError(), __LINE__);
return false;
}
iUpdateModel = (int)MathRound(MathRand() / 32767.0 * (iModels - 1));
if(!OpenCL.SetArgument(def_k_HGMultiModels, def_k_chg_model, iUpdateModel))
{
printf("Error of set parameter kernel calcHiddenGradients: %d; line %d", GetLastError(), __LINE__);
return false;
}
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_HGMultiModels, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel CalcHiddenGradient: %d", GetLastError());
return false;
}
//if(!Gradient.BufferRead())
// return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMultiModel::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(OpenCL) == POINTER_INVALID || CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = Neurons() / iModels;
global_work_size[1] = NeuronOCL.Neurons() / iModels + 1;
uint rest = 0;
float lt = lr;
if(!OpenCL.SetArgumentBuffer(def_k_UWMultiModels, def_k_uwa_matrix_w, getWeightsIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UWMultiModels, def_k_uwa_matrix_g, getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UWMultiModels, def_k_uwa_matrix_i, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UWMultiModels, def_k_uwa_matrix_m, getFirstMomentumIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UWMultiModels, def_k_uwa_matrix_v, getSecondMomentumIndex()))
return false;
lt = (float)(lr * sqrt(1 - pow(b2, (float)t)) / (1 - pow(b1, (float)t)));
if(!OpenCL.SetArgument(def_k_UWMultiModels, def_k_uwa_inputs, NeuronOCL.Neurons() / iModels))
return false;
if(!OpenCL.SetArgument(def_k_UWMultiModels, def_k_uwa_l, lt))
return false;
if(!OpenCL.SetArgument(def_k_UWMultiModels, def_k_uwa_b1, b1))
return false;
if(!OpenCL.SetArgument(def_k_UWMultiModels, def_k_uwa_b2, b2))
return false;
if(!OpenCL.SetArgument(def_k_UWMultiModels, def_k_uwa_model, iUpdateModel))
return false;
global_work_size[1] = (global_work_size[1] + 3) / 4;
////Comment(com+"\n UpdateWeightsAdam");
ResetLastError();
//Comment(com+"\n "+(string)__LINE__+"-"__FUNCTION__);
if(!OpenCL.Execute(def_k_UWMultiModels, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
t++;
//---
return true;//NeuronOCL.Weights.BufferRead();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMultiModel::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
if(FileWriteInteger(file_handle, iModels) <= 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMultiModel::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
iModels = FileReadInteger(file_handle);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronConcatenate : public CNeuronBaseOCL
{
protected:
int i_SecondInputs;
CBufferFloat *ConcWeights; ///< Buffer of weights matrix
CBufferFloat *ConcDeltaWeights; ///< Buffer of last delta weights matrix (#SGD)
CBufferFloat *ConcFirstMomentum; ///< Buffer of first momentum matrix (#ADAM)
CBufferFloat *ConcSecondMomentum; ///< Buffer of second momentum matrix (#ADAM)
public:
CNeuronConcatenate(void);
/** Destructor */~CNeuronConcatenate(void);
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, uint inputs1, uint inputs2, ENUM_OPTIMIZATION optimization_type, uint batch);
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput); ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
virtual bool calcHiddenGradients(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput, CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = None); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput); ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
//--- methods for working with files
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) const { return defNeuronConcatenate; }///< Identificator of class.@return Type of class
virtual void SetOpenCL(COpenCLMy *obj);
//---
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
virtual CBufferFloat *getConcatWeights(void) { return ConcWeights; } ///< Get pointer of gradient buffer @return Pointer to object
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronConcatenate::CNeuronConcatenate(void) : i_SecondInputs(0)
{
ConcWeights = new CBufferFloat();
ConcDeltaWeights = new CBufferFloat();
ConcFirstMomentum = new CBufferFloat();
ConcSecondMomentum = new CBufferFloat;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronConcatenate::~CNeuronConcatenate()
{
if(!!ConcWeights)
delete ConcWeights;
if(!!ConcDeltaWeights)
delete ConcDeltaWeights;
if(!!ConcFirstMomentum)
delete ConcFirstMomentum;
if(!!ConcSecondMomentum)
delete ConcSecondMomentum;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConcatenate::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint numNeurons, uint numInputs1, uint numInputs2, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons, optimization_type, batch))
return false;
//---
i_SecondInputs = (int)numInputs2;
if(!ConcWeights)
{
ConcWeights = new CBufferFloat();
if(!ConcWeights)
return false;
}
int count = (int)((numInputs1 + numInputs2 + 1) * numNeurons);
if(!ConcWeights.Reserve(count))
return false;
float k = (float)(1 / sqrt(numNeurons + 1));
for(int i = 0; i < count; i++)
{
if(!ConcWeights.Add((2 * GenerateWeight()*k - k)*WeightsMultiplier))
return false;
}
if(!ConcWeights.BufferCreate(OpenCL))
return false;
//---
if(optimization == SGD)
{
if(!ConcDeltaWeights)
{
ConcDeltaWeights = new CBufferFloat();
if(!ConcDeltaWeights)
return false;
}
if(!ConcDeltaWeights.BufferInit(count, 0))
return false;
if(!ConcDeltaWeights.BufferCreate(OpenCL))
return false;
if(!!ConcFirstMomentum)
delete ConcFirstMomentum;
if(!!ConcSecondMomentum)
delete ConcSecondMomentum;
}
else
{
if(!!ConcDeltaWeights)
delete ConcDeltaWeights;
//---
if(!ConcFirstMomentum)
{
ConcFirstMomentum = new CBufferFloat();
if(CheckPointer(ConcFirstMomentum) == POINTER_INVALID)
return false;
}
if(!ConcFirstMomentum.BufferInit(count, 0))
return false;
if(!ConcFirstMomentum.BufferCreate(OpenCL))
return false;
//---
if(!ConcSecondMomentum)
{
ConcSecondMomentum = new CBufferFloat();
if(!ConcSecondMomentum)
return false;
}
if(!ConcSecondMomentum.BufferInit(count, 0))
return false;
if(!ConcSecondMomentum.BufferCreate(OpenCL))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConcatenate::feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput)
{
if(!OpenCL || !NeuronOCL || !SecondInput)
return false;
if(SecondInput.Total() < i_SecondInputs)
return false;
if(SecondInput.GetIndex() < 0 && !SecondInput.BufferCreate(OpenCL))
return false;
//---
if(!OpenCL.SetArgumentBuffer(def_k_ConcatFeedForward, def_k_cff_matrix_w, ConcWeights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatFeedForward, def_k_cff_matrix_i1, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatFeedForward, def_k_cff_matrix_i2, SecondInput.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatFeedForward, def_k_cff_matrix_o, Output.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatFeedForward, def_k_cff_inputs1, (int)NeuronOCL.Neurons()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatFeedForward, def_k_cff_inputs2, (int)i_SecondInputs))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatFeedForward, def_k_cff_activation, (int)activation))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Output.Total();
if(!OpenCL.Execute(def_k_ConcatFeedForward, 1, global_work_offset, global_work_size))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
//---
//vector<float> temp;
//Output.GetData(temp);
//float delta = MathAbs(temp - prev_output).Sum();
//prev_output = temp;
//string error;
//CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConcatenate::calcHiddenGradients(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput, CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = None)
{
if(!OpenCL || !NeuronOCL || !SecondInput || !SecondGradient)
return false;
if(SecondInput.Total() < i_SecondInputs || SecondGradient.Total() < i_SecondInputs)
return false;
if(SecondInput.GetIndex() < 0 && !SecondInput.BufferCreate(OpenCL))
return false;
if(SecondGradient.GetIndex() < 0 && !SecondGradient.BufferCreate(OpenCL))
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = NeuronOCL.Neurons() + i_SecondInputs;
if(!OpenCL.SetArgumentBuffer(def_k_ConcatCalcHiddenGradient, def_k_cchg_matrix_w, ConcWeights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatCalcHiddenGradient, def_k_cchg_matrix_g, Gradient.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatCalcHiddenGradient, def_k_cchg_matrix_ig1, NeuronOCL.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatCalcHiddenGradient, def_k_cchg_matrix_ig2, SecondGradient.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatCalcHiddenGradient, def_k_cchg_matrix_o1, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatCalcHiddenGradient, def_k_cchg_matrix_o2, SecondInput.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatCalcHiddenGradient, def_k_cchg_inputs1, NeuronOCL.Neurons()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatCalcHiddenGradient, def_k_cchg_inputs2, i_SecondInputs))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatCalcHiddenGradient, def_k_cchg_outputs, Neurons()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatCalcHiddenGradient, def_k_cchg_activation1, NeuronOCL.Activation()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatCalcHiddenGradient, def_k_cchg_activation2, (int)SecondActivation))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_ConcatCalcHiddenGradient, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel CalcHiddenGradient: %d", GetLastError());
return false;
}
//Gradient.BufferRead();
//if(!!SecondGradient)
// SecondGradient.BufferRead();
//NeuronOCL.getGradient().BufferRead();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConcatenate::updateInputWeights(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput)
{
if(!OpenCL || !NeuronOCL || !SecondInput)
return false;
if(SecondInput.Total() < i_SecondInputs)
return false;
if(SecondInput.GetIndex() < 0 && !SecondInput.BufferCreate(OpenCL))
return false;
//---
uint global_work_offset[2] = {0, 0};
uint global_work_size[2];
global_work_size[0] = Neurons();
global_work_size[1] = NeuronOCL.Neurons() + i_SecondInputs + 1;
float lt = lr;
ResetLastError();
switch(NeuronOCL.Optimization())
{
case SGD:
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsMomentum, def_k_cuwm_matrix_w, ConcWeights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsMomentum, def_k_cuwm_matrix_g, getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsMomentum, def_k_cuwm_matrix_i1, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsMomentum, def_k_cuwm_matrix_i2, SecondInput.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsMomentum, def_k_cuwm_matrix_dw, ConcDeltaWeights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatUpdWeightsMomentum, def_k_cuwm_inputs1, NeuronOCL.Neurons()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatUpdWeightsMomentum, def_k_cuwm_inputs1, i_SecondInputs))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatUpdWeightsMomentum, def_k_cuwm_learning_rates, lr))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatUpdWeightsMomentum, def_k_cuwm_momentum, alpha))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
ResetLastError();
if(!OpenCL.Execute(def_k_ConcatUpdWeightsMomentum, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateWeightsMomentum: %d", GetLastError());
return false;
}
break;
case ADAM:
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsAdam, def_k_cuwa_matrix_w, ConcWeights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsAdam, def_k_cuwa_matrix_g, getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsAdam, def_k_cuwa_matrix_i1, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsAdam, def_k_cuwa_matrix_i2, SecondInput.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsAdam, def_k_cuwa_matrix_m, ConcFirstMomentum.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_ConcatUpdWeightsAdam, def_k_cuwa_matrix_v, ConcSecondMomentum.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
lt = (float)(lr * sqrt(1 - pow(b2, (float)t)) / (1 - pow(b1, (float)t)));
if(!OpenCL.SetArgument(def_k_ConcatUpdWeightsAdam, def_k_cuwa_inputs1, NeuronOCL.Neurons()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatUpdWeightsAdam, def_k_cuwa_inputs2, i_SecondInputs))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatUpdWeightsAdam, def_k_cuwa_l, lt))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatUpdWeightsAdam, def_k_cuwa_b1, b1))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_ConcatUpdWeightsAdam, def_k_cuwa_b2, b2))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_ConcatUpdWeightsAdam, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel ConcatUpdateWeightsAdam: %d", GetLastError());
return false;
}
t++;
break;
default:
return false;
break;
}
//---
return true;//NeuronOCL.Weights.BufferRead();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConcatenate::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
//---
if(FileWriteInteger(file_handle, i_SecondInputs) < INT_VALUE)
return false;
if(!ConcWeights.Save(file_handle))
return false;
if(optimization == SGD)
{
if(!ConcDeltaWeights.Save(file_handle))
return false;
}
else
{
if(!ConcFirstMomentum.Save(file_handle))
return false;
if(!ConcSecondMomentum.Save(file_handle))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConcatenate::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//---
i_SecondInputs = FileReadInteger(file_handle);
if(!ConcWeights.Load(file_handle))
return false;
ConcWeights.BufferCreate(OpenCL);
if(optimization == SGD)
{
if(!ConcDeltaWeights.Load(file_handle))
return false;
ConcDeltaWeights.BufferCreate(OpenCL);
}
else
{
if(!ConcFirstMomentum.Load(file_handle))
return false;
if(!ConcSecondMomentum.Load(file_handle))
return false;
ConcFirstMomentum.BufferCreate(OpenCL);
ConcSecondMomentum.BufferCreate(OpenCL);
}
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronConcatenate::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
if(!ConcWeights)
return;
ConcWeights.BufferCreate(OpenCL);
if(optimization == SGD)
{
if(!ConcDeltaWeights)
return;
ConcDeltaWeights.BufferCreate(OpenCL);
}
else
{
if(!ConcFirstMomentum || !ConcSecondMomentum)
return;
ConcFirstMomentum.BufferCreate(OpenCL);
ConcSecondMomentum.BufferCreate(OpenCL);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::WeightsUpdate(CNet *net, float tau)
{
if(!layers || !net || !net.layers || layers.Total() != net.layers.Total())
return false;
if(tau < 0)
return false;
if(tau > 1)
return true;
//---
for(int l = 0; l < layers.Total(); l++)
{
CLayer *layer = layers.At(l);
if(!layer.WeightsUpdate(net.layers.At(l), tau))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CLayer::WeightsUpdate(CLayer *source, float tau)
{
if(!source || m_data_total != source.Total())
return false;
//---
for(int i = 0; i < m_data_total; i++)
{
CNeuronBaseOCL *temp = m_data[i];
if(temp == source.At(i))
continue;
//---
if(!temp.WeightsUpdate(source.At(i), tau))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(tau != 1.0f && optimization == ADAM)
return WeightsUpdateAdam(source, tau);
//---
if(!OpenCL || !source)
return false;
if(Type() != source.Type())
return false;
if(!Weights || Weights.Total() == 0)
return true;
if(!source.Weights || Weights.Total() != source.Weights.Total())
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {Weights.Total()};
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_target, Weights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_source, source.getWeightsIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdate, def_k_su_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdate, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::WeightsUpdateAdam(CNeuronBaseOCL *source, float tau)
{
if(GetPointer(this) == source)
return true;
//---
if(!OpenCL || !source)
return false;
if(Type() != source.Type())
return false;
if(!Weights || Weights.Total() == 0)
return true;
if(!source.Weights || Weights.Total() != source.Weights.Total())
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {Weights.Total()};
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_target, getWeightsIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_source, source.getWeightsIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_m, getFirstMomentumIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_v, getSecondMomentumIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b1, (float)b1))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b2, (float)b2))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdateAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConcatenate::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
//---
CNeuronConcatenate *temp = source;
if(ConcWeights.Total() != temp.ConcWeights.Total())
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {ConcWeights.Total()};
ResetLastError();
if(tau != 1.0f && optimization == ADAM)
{
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_target, ConcWeights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_source, temp.ConcWeights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_m, ConcFirstMomentum.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_v, ConcSecondMomentum.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b1, (float)b1))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b2, (float)b2))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdateAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
}
else
{
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_target, ConcWeights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_source, temp.ConcWeights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdate, def_k_su_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdate, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronConvOCL::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
//---
CNeuronConvOCL *temp = source;
if(WeightsConv.Total() != temp.WeightsConv.Total())
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {WeightsConv.Total()};
ResetLastError();
if(tau != 1.0f && optimization == ADAM)
{
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_target, WeightsConv.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_source, temp.WeightsConv.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_m, FirstMomentumConv.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_v, SecondMomentumConv.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b1, (float)b1))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b2, (float)b2))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdateAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
}
else
{
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_target, WeightsConv.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_source, temp.WeightsConv.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdate, def_k_su_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdate, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBatchNormOCL::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
//---
CNeuronBatchNormOCL *temp = source;
if(BatchOptions.Total() != temp.BatchOptions.Total())
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {BatchOptions.Total()};
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_target, BatchOptions.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_source, temp.BatchOptions.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdate, def_k_su_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdate, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::feedForward(CNet *inputNet, int inputLayer = -1, CNet *secondNet = NULL, int secondLayer = -1)
{
if(!inputNet || !opencl)
return false;
if(inputLayer < 0)
inputLayer = inputNet.layers.Total() - 1;
//---
CBufferFloat *second = NULL;
bool del_second = false;
if(!!secondNet)
{
if(secondLayer < 0)
secondLayer = secondNet.layers.Total() - 1;
if(secondNet.GetOpenCL() != opencl)
{
secondNet.GetLayerOutput(secondLayer, second);
if(!!second)
{
if(!second.BufferCreate(opencl))
{
delete second;
return false;
}
del_second = true;
}
}
else
{
if(secondNet.layers.Total() <= secondLayer)
return false;
CLayer *layer = secondNet.layers.At(secondLayer);
CNeuronBaseOCL *neuron = layer.At(0);
second = neuron.getOutput();
}
}
//---
if(inputNet.opencl != opencl)
{
CBufferFloat *inputs;
if(!inputNet.GetLayerOutput(inputLayer, inputs))
{
if(del_second)
delete second;
delete inputs;
return false;
}
bool result = feedForward(inputs, 1, false, second);
if(del_second)
delete second;
delete inputs;
return result;
}
//---
CLayer *layer = inputNet.layers.At(inputLayer);
if(!layer)
{
if(del_second)
delete second;
return false;
}
CNeuronBaseOCL *neuron = layer.At(0);
layer = layers.At(0);
if(!layer)
{
if(del_second)
delete second;
return false;
}
if(layer.At(0) != neuron)
{
CNeuronBaseOCL *temp = layer.At(0);
if(temp.getConnections() <= 0)
{
if(!layer.Update(0, neuron))
{
if(del_second)
delete second;
return false;
}
else
layer.FreeMode(false);
}
else
{
if(neuron.getOutputIndex() != temp.getOutputIndex())
temp.getOutput().BufferSet(neuron.getOutputIndex());
if(neuron.getGradientIndex() != temp.getGradientIndex())
temp.getGradient().BufferSet(neuron.getGradientIndex());
}
}
//---
for(int l = 1; l < layers.Total(); l++)
{
layer = layers.At(l);
neuron = layer.At(0);
layer = layers.At(l - 1);
if(!neuron.FeedForward(layer.At(0), second))
{
if(del_second)
delete second;
return false;
}
}
//---
if(del_second)
delete second;
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::feedForward(CNet *inputNet, int inputLayer = -1, CBufferFloat *SecondInput = NULL)
{
if(!inputNet || !opencl)
return false;
if(inputLayer < 0)
inputLayer = inputNet.layers.Total() - 1;
//---
if(!!SecondInput)
{
if(SecondInput.GetIndex() < 0)
if(!SecondInput.BufferCreate(opencl))
return false;
}
//---
if(inputNet.opencl != opencl)
{
CBufferFloat *inputs;
if(!inputNet.GetLayerOutput(inputLayer, inputs))
return false;
bool result = feedForward(inputs, 1, false, SecondInput);
return result;
}
//---
CLayer *layer = inputNet.layers.At(inputLayer);
if(!layer)
return false;
CNeuronBaseOCL *neuron = layer.At(0);
layer = layers.At(0);
if(!layer)
return false;
if(layer.At(0) != neuron)
{
CNeuronBaseOCL *temp = layer.At(0);
if(temp.getConnections() <= 0)
{
if(!layer.Update(0, neuron))
return false;
else
layer.FreeMode(false);
}
else
{
if(neuron.getOutputIndex() != temp.getOutputIndex())
temp.getOutput().BufferSet(neuron.getOutputIndex());
if(neuron.getGradientIndex() != temp.getGradientIndex())
temp.getGradient().BufferSet(neuron.getGradientIndex());
}
}
//---
for(int l = 1; l < layers.Total(); l++)
{
layer = layers.At(l);
neuron = layer.At(0);
layer = layers.At(l - 1);
if(!neuron.FeedForward(layer.At(0), SecondInput))
return false;
neuron.getOutput().BufferRead();
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::backProp(CArrayFloat * targetVals, CNet *secondNet = NULL, int secondLayer = -1)
{
if(!secondNet || !secondNet.layers)
return backPropOCL(targetVals);
//---
if(secondLayer < 0)
secondLayer = secondNet.layers.Total() - 1;
//---
if(opencl != secondNet.GetOpenCL())
{
CBufferFloat *second;
if(!secondNet.GetLayerOutput(secondLayer, second))
return false;
if(!second)
return backPropOCL(targetVals);
CLayer *layer = secondNet.layers.At(secondLayer);
CNeuronBaseOCL *neuron = layer.At(0);
CBufferFloat gradient;
neuron.getGradient().BufferRead();
gradient.AssignArray(neuron.getGradient());
if(!second.BufferCreate(opencl) || !gradient.BufferCreate(opencl))
{
delete second;
return false;
}
bool result = backPropOCL(targetVals, second, GetPointer(gradient));
delete second;
return result;
}
//---
CLayer *layer = secondNet.layers.At(secondLayer);
CNeuronBaseOCL *neuron = layer.At(0);
if(!backPropOCL(targetVals, neuron.getOutput(), neuron.getGradient(), false, (ENUM_ACTIVATION)neuron.Activation()))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::backPropGradient(CBufferFloat *SecondInput = NULL, CBufferFloat *SecondGradient = NULL, int LastLayer = -1, bool load_weights = true)
{
if(CheckPointer(layers) == POINTER_INVALID || CheckPointer(opencl) == POINTER_INVALID)
return false;
if(LastLayer < 0)
LastLayer = layers.Total() - 1;
CLayer *currentLayer = layers.At(LastLayer);
CNeuronBaseOCL *neuron = NULL;
if(CheckPointer(currentLayer) == POINTER_INVALID)
return false;
//--- Calc Hidden Gradients
for(int layerNum = LastLayer - 1; layerNum >= 0; layerNum--)
{
CLayer *nextLayer = currentLayer;
currentLayer = layers.At(layerNum);
if(CheckPointer(currentLayer) == POINTER_INVALID)
return false;
neuron = currentLayer.At(0);
if(!neuron || !neuron.calcHiddenGradients(nextLayer.At(0), SecondInput, SecondGradient))
return false;
}
//---
CLayer *prevLayer = layers.At(LastLayer);
for(int layerNum = LastLayer; layerNum > 0; layerNum--)
{
currentLayer = prevLayer;
prevLayer = layers.At(layerNum - 1);
neuron = currentLayer.At(0);
if(!neuron.UpdateInputWeights(prevLayer.At(0), SecondInput))
return false;
}
//---
if(!load_weights)
return true;
//---
bool result = false;
for(int layerNum = 0; (layerNum < layers.Total() && !result); layerNum++)
{
currentLayer = layers.At(layerNum);
CNeuronBaseOCL *temp = currentLayer.At(0);
CNeuronConvOCL *conv = NULL;
CNeuronConcatenate *conc = NULL;
CNeuronBatchNormOCL *batch = NULL;
CNeuronLSTMOCL *lstm = NULL;
if(!temp)
continue;
if(!temp.TrainMode())
{
if(layerNum == layers.Total() - 1)
result = true;
continue;
}
switch(temp.Type())
{
case defNeuronConvOCL:
conv = temp;
if(!!conv.GetWeightsConv() && conv.GetWeightsConv().BufferRead())
result = true;
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
case defNeuronConcatenate:
if(!!temp.getWeights() && temp.getWeights().BufferRead())
{
result = true;
break;
}
conc = temp;
if(!!conc.getConcatWeights() && conc.getConcatWeights().BufferRead())
result = true;
break;
case defNeuronBatchNormOCL:
batch = temp;
if(!!batch.getBatchOptions() && batch.getBatchOptions().BufferRead())
result = true;
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
case defNeuronLSTMOCL:
lstm = temp;
if(!!lstm.getLSTMWeights() && lstm.getLSTMWeights().BufferRead())
result = true;
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
default:
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
}
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::backPropGradient(CNet *secondNet, int secondLayer = -1, int LastLayer = -1, bool load_weights = true)
{
if(CheckPointer(layers) == POINTER_INVALID || CheckPointer(opencl) == POINTER_INVALID ||
!secondNet)
return false;
if(LastLayer < 0)
LastLayer = layers.Total() - 1;
if(secondLayer < 0)
secondLayer = secondNet.layers.Total() - 1;
CLayer *currentLayer = layers.At(LastLayer);
CNeuronBaseOCL *neuron = NULL;
if(!currentLayer || !secondNet.layers.At(secondLayer))
return false;
CNeuronBaseOCL *secondNeuron = ((CArrayObj *)secondNet.layers.At(secondLayer)).At(0);
if(!secondNeuron)
return false;
//--- Calc Hidden Gradients
for(int layerNum = LastLayer - 1; layerNum >= 0; layerNum--)
{
CLayer *nextLayer = currentLayer;
currentLayer = layers.At(layerNum);
if(CheckPointer(currentLayer) == POINTER_INVALID)
return false;
neuron = currentLayer.At(0);
if(!neuron || !neuron.calcHiddenGradients(nextLayer.At(0), secondNeuron.getOutput(), secondNeuron.getGradient()))
return false;
}
//---
CLayer *prevLayer = layers.At(LastLayer);
for(int layerNum = LastLayer; layerNum > 0; layerNum--)
{
currentLayer = prevLayer;
prevLayer = layers.At(layerNum - 1);
neuron = currentLayer.At(0);
if(!neuron.UpdateInputWeights(prevLayer.At(0), secondNeuron.getOutput()))
return false;
}
//---
if(!load_weights)
return true;
//---
bool result = false;
for(int layerNum = 0; (layerNum < layers.Total() && !result); layerNum++)
{
currentLayer = layers.At(layerNum);
CNeuronBaseOCL *temp = currentLayer.At(0);
CNeuronConvOCL *conv = NULL;
CNeuronConcatenate *conc = NULL;
CNeuronBatchNormOCL *batch = NULL;
CNeuronLSTMOCL *lstm = NULL;
if(!temp)
continue;
if(!temp.TrainMode())
{
if(layerNum == layers.Total() - 1)
result = true;
continue;
}
switch(temp.Type())
{
case defNeuronConvOCL:
conv = temp;
if(!!conv.GetWeightsConv() && conv.GetWeightsConv().BufferRead())
result = true;
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
case defNeuronConcatenate:
if(!!temp.getWeights() && temp.getWeights().BufferRead())
{
result = true;
break;
}
conc = temp;
if(!!conc.getConcatWeights() && conc.getConcatWeights().BufferRead())
result = true;
break;
case defNeuronBatchNormOCL:
batch = temp;
if(!!batch.getBatchOptions() && batch.getBatchOptions().BufferRead())
result = true;
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
case defNeuronLSTMOCL:
lstm = temp;
if(!!lstm.getLSTMWeights() && lstm.getLSTMWeights().BufferRead())
result = true;
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
default:
if(!!temp.getWeights() && temp.getWeights().BufferRead())
result = true;
break;
}
}
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronSoftActorCritic : public CNeuronFQF
{
protected:
CNeuronConcatenate cAlphas;
CBufferFloat cLogProbs;
CBufferFloat cRandomize;
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
public:
CNeuronSoftActorCritic(void) {};
~CNeuronSoftActorCritic(void) {};
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint actions, uint quantiles, uint numInputs, ENUM_OPTIMIZATION optimization_type, uint batch);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object. #param[in] numNeurons Number of neurons in layer @param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL);
virtual bool calcAlphaGradients(CNeuronBaseOCL *NeuronOCL);
virtual bool GetAlphaLogProbs(vector<float> &log_probs) { return (cLogProbs.GetData(log_probs) > 0); }
virtual bool CalcLogProbs(CBufferFloat *buffer);
virtual bool ReCalcLogProbs(void);
//---
virtual bool Save(int const file_handle) override;///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle) override;///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) override const { return defNeuronSoftActorCritic; }///< Identificator of class.@return Type of class
virtual void SetOpenCL(COpenCLMy *obj);
//---
virtual void getCheckData(vector<float> &output, vector<float> &grad, vector<float> &quantiles, vector<float> &probability, vector<float> &alphas);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftActorCritic::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint actions, uint quantiles, uint numInputs, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronFQF::Init(numOutputs, myIndex, open_cl, actions, quantiles, numInputs, optimization_type, batch))
return false;
//---
if(!cAlphas.Init(0, 0, OpenCL, actions, numInputs, cQuantile2.Neurons(), optimization_type, batch))
return false;
cAlphas.SetActivationFunction(SIGMOID);
//---
if(!cLogProbs.BufferInit(actions, 0) || !cLogProbs.BufferCreate(OpenCL))
return false;
//---
if(!cRandomize.BufferInit(actions, 0) || !cRandomize.BufferCreate(OpenCL))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftActorCritic::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(!CNeuronFQF::feedForward(NeuronOCL))
return false;
if(!cAlphas.FeedForward(GetPointer(cQuantile0), cQuantile2.getOutput()))
return false;
//---
int actions = cRandomize.Total();
for(int i = 0; i < actions; i++)
{
float probability = (float)MathRand() / 32767.0f;
cRandomize.Update(i, probability);
}
if(!cRandomize.BufferWrite())
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {Neurons()};
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaLogProbs, def_k_sac_alp_alphas, cAlphas.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaLogProbs, def_k_sac_alp_log_probs, cLogProbs.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaLogProbs, def_k_sac_alp_outputs, getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaLogProbs, def_k_sac_alp_probs, cSoftMax.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaLogProbs, def_k_sac_alp_quantiles, cQuantile2.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaLogProbs, def_k_sac_alp_random, cRandomize.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SAC_AlphaLogProbs, def_k_sac_alp_count_quants, (int)(cSoftMax.Neurons() / global_work_size[0])))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SAC_AlphaLogProbs, def_k_sac_alp_activation, (int)activation))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SAC_AlphaLogProbs, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftActorCritic::calcAlphaGradients(CNeuronBaseOCL *NeuronOCL)
{
if(!OpenCL || !NeuronOCL || !NeuronOCL.getGradient() ||
NeuronOCL.getGradientIndex() < 0)
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {Neurons()};
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaGradients, def_k_sac_alg_outputs, cAlphas.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaGradients, def_k_sac_alg_alphas_grad, cAlphas.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaGradients, def_k_sac_alg_gradient, NeuronOCL.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_AlphaGradients, def_k_sac_alg_log_probs, cLogProbs.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SAC_AlphaGradients, def_k_sac_alg_activation, (int)cAlphas.Activation()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SAC_AlphaGradients, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return cAlphas.calcHiddenGradients(GetPointer(cQuantile0), cQuantile2.getOutput(), cQuantile2.getGradient());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftActorCritic::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(!CNeuronFQF::updateInputWeights(NeuronOCL))
return false;
//---
return cAlphas.UpdateInputWeights(cQuantile0.AsObject(), cQuantile2.getOutput());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronSoftActorCritic::SetOpenCL(COpenCLMy *obj)
{
CNeuronFQF::SetOpenCL(obj);
cAlphas.SetOpenCL(OpenCL);
if(cLogProbs.Total() != Neurons())
cLogProbs.BufferInit(Neurons(), 0);
cLogProbs.BufferCreate(OpenCL);
if(cRandomize.Total() != Neurons())
cRandomize.BufferInit(Neurons(), 0);
cRandomize.BufferCreate(OpenCL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::AlphasGradient(CNet *PolicyNet)
{
if(!PolicyNet || !PolicyNet.layers)
return false;
int total = PolicyNet.layers.Total();
if(total <= 0)
return false;
CLayer *layer = PolicyNet.layers.At(total - 1);
if(!layer || !layer.At(0))
return false;
if(layer.At(0).Type() != defNeuronSoftActorCritic)
return true;
//---
CNeuronSoftActorCritic *neuron = layer.At(0);
if(!layers)
return false;
total = layers.Total();
if(total <= 0 || !layers.At(total - 1))
return false;
layer = layers.At(total - 1);
//---
return neuron.calcAlphaGradients((CNeuronBaseOCL*) layer.At(0));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftActorCritic::Save(const int file_handle)
{
if(!CNeuronFQF::Save(file_handle))
return false;
return cAlphas.Save(file_handle);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftActorCritic::Load(const int file_handle)
{
if(!CNeuronFQF::Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cAlphas.Type() ||
!cAlphas.Load(file_handle))
return false;
//---
if(cLogProbs.Total() != Neurons())
{
cLogProbs.BufferFree();
if(!cLogProbs.BufferInit(Neurons(), 0) ||
(!!OpenCL && !cLogProbs.BufferCreate(OpenCL)))
return false;
}
//---
if(cRandomize.Total() != Neurons())
{
cRandomize.BufferFree();
if(!cRandomize.BufferInit(Neurons(), 0) ||
(!!OpenCL && !cRandomize.BufferCreate(OpenCL)))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::GetLogProbs(vectorf &log_probs)
{
//---
if(!layers)
return false;
int total = layers.Total();
if(total <= 0 || !layers.At(total - 1))
return false;
CLayer *layer = layers.At(total - 1);
if(!layer.At(0) || layer.At(0).Type() != defNeuronSoftActorCritic)
return false;
//---
CNeuronSoftActorCritic *neuron = layer.At(0);
//---
return neuron.GetAlphaLogProbs(log_probs);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::CalcLogProbs(CBufferFloat *buffer)
{
if(!layers)
return false;
int total = layers.Total();
if(total <= 0 || !layers.At(total - 1))
return false;
CLayer *layer = layers.At(total - 1);
if(!layer.At(0) || layer.At(0).Type() != defNeuronSoftActorCritic)
return false;
//---
CNeuronSoftActorCritic *neuron = layer.At(0);
//---
return neuron.CalcLogProbs(buffer);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftActorCritic::CalcLogProbs(CBufferFloat *buffer)
{
if(!buffer || buffer.Total() < Neurons())
return false;
if(buffer.GetIndex() < 0 && !buffer.BufferCreate(OpenCL))
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {Neurons()};
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_alphas, cAlphas.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_log_probs, buffer.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_outputs, buffer.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_probs, cSoftMax.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_quantiles, cQuantile2.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SAC_CalcLogProbs, def_k_sacclp_count_quants, (int)(cSoftMax.Neurons() / global_work_size[0])))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SAC_CalcLogProbs, def_k_sacclp_activation, (int)Activation()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SAC_CalcLogProbs, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftActorCritic::ReCalcLogProbs(void)
{
if(!OpenCL)
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {Neurons()};
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_alphas, cAlphas.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_log_probs, cLogProbs.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_outputs, Output.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_probs, cSoftMax.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_CalcLogProbs, def_k_sacclp_quantiles, cQuantile2.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SAC_CalcLogProbs, def_k_sacclp_count_quants, (int)(cSoftMax.Neurons() / global_work_size[0])))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SAC_CalcLogProbs, def_k_sacclp_activation, (int)Activation()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SAC_CalcLogProbs, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronSoftActorCritic::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL || !Gradient || !Output)
return false;
//---
{
uint global_work_offset[1] = {0};
uint global_work_size[1] = { Neurons() };
if(!OpenCL.SetArgumentBuffer(def_k_SAC_OutputGradient, def_k_sacoutgr_quantiles, cQuantile2.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_OutputGradient, def_k_sacoutgr_taus, cSoftMax.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_OutputGradient, def_k_sacoutgr_output_gr, getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_OutputGradient, def_k_sacoutgr_quantiles_gr, cQuantile2.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_OutputGradient, def_k_sacoutgr_taus_gr, cSoftMax.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SAC_OutputGradient, def_k_sacoutgr_outputs, getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SAC_OutputGradient, def_k_sacoutgr_activation, (int)Activation()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SAC_OutputGradient, def_k_sacoutgr_count_quants, (int)(cSoftMax.Neurons() / Neurons())))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SAC_OutputGradient, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel SAC_OutputGradient: %d", GetLastError());
return false;
}
}
//---
if(!cQuantile1.calcHiddenGradients(GetPointer(cQuantile2)))
return false;
if(!cQuantile0.calcHiddenGradients(GetPointer(cQuantile1)))
return false;
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2] = { cCosineEmbeding.Neurons(), 1 };
if(!OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_state_enbeding, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_taus_embedding, cCosineEmbeding.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_quantiles_gr, cQuantile0.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_state_gr, NeuronOCL.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FQF_QuantileGradient, def_k_fqfqgr_taus_gr, cCosineEmbeding.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_FQF_QuantileGradient, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel FQF_OutputGradient: %d", GetLastError());
return false;
}
}
//---
if(!cCosine.calcHiddenGradients(GetPointer(cCosineEmbeding)))
return false;
//---
{
uint global_work_offset[2] = {0, 0};
uint global_work_size[2] = { cSoftMax.Neurons() / Neurons(), Neurons() };
if(!OpenCL.SetArgumentBuffer(def_k_FQF_CosineGradient, def_k_fqfcosgr_softmax, cSoftMax.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FQF_CosineGradient, def_k_fqfcosgr_output_gr, cCosine.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_FQF_CosineGradient, def_k_fqfcosgr_softmax_gr, cSoftMax.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_FQF_CosineGradient, 2, global_work_offset, global_work_size))
{
printf("Error of execution kernel FQF_CosineGradient: %d", GetLastError());
return false;
}
}
//---
//cSoftMax.getGradient().BufferRead();
if(!cSoftMax.calcInputGradients(GetPointer(cFraction)))
return false;
//cFraction.getGradient().BufferRead();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::SetResult(float &result[])
{
if(!layers || layers.Total() <= 0)
return false;
//---
CNeuronBaseOCL *output = ((CLayer*)layers.At(layers.Total() - 1)).At(0);
if(!output)
return false;
if(!output.getOutput().AssignArray(result) || !output.getOutput().BufferWrite())
return false;
if(output.Type() == defNeuronSoftActorCritic && !output.ReCalcLogProbs())
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronSoftActorCritic::getCheckData(vector<float> &output, vector<float> &grad, vector<float> &quantiles, vector<float> &probability, vector<float> &alphas)
{
Output.GetData(output);
Gradient.GetData(grad);
cQuantile2.getGradient().GetData(quantiles);
cSoftMax.getGradient().GetData(probability);
cAlphas.getGradient().GetData(alphas);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronEmbeddingOCL : public CNeuronBaseOCL
{
protected:
int a_Windows[];
int i_WindowOut;
int i_StackSize;
int i_WindowsBuffer;
int i_STDBuffer;
//---
CBufferFloat WeightsEmbedding;
CBufferFloat FirstMomentumEmbed;
CBufferFloat SecondMomentumEmbed;
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL); ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
public:
CNeuronEmbeddingOCL(void);
~CNeuronEmbeddingOCL(void);
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint stack_size, uint window_out, int &windows[]);
///< Method of initialization class.@param[in] numOutputs Number of connections to next layer.@param[in] myIndex Index of neuron in layer.@param[in] open_cl Pointer to #COpenCLMy object. #param[in] numNeurons Number of neurons in layer @param optimization_type Optimization type (#ENUM_OPTIMIZATION)@return Boolen result of operations.
//---
///\ingroup neuron_base_gr
///@{
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
///@}
//---
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) const { return defNeuronEmbeddingOCL; }///< Identificator of class.@return Type of class
virtual CLayerDescription* GetLayerInfo(void) { return CNeuronBaseOCL::GetLayerInfo(); }
virtual void SetOpenCL(COpenCLMy *obj);
virtual bool Clear(void);
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronEmbeddingOCL::CNeuronEmbeddingOCL(void)
{
ArrayFree(a_Windows);
if(!!OpenCL)
{
if(i_WindowsBuffer >= 0)
OpenCL.BufferFree(i_WindowsBuffer);
if(i_STDBuffer >= 0)
OpenCL.BufferFree(i_STDBuffer);
}
//---
i_WindowsBuffer = INVALID_HANDLE;
i_STDBuffer = INVALID_HANDLE;
i_WindowOut = 0;
i_StackSize = 1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronEmbeddingOCL::~CNeuronEmbeddingOCL(void)
{
ArrayFree(a_Windows);
if(!!OpenCL)
{
if(i_WindowsBuffer >= 0)
OpenCL.BufferFree(i_WindowsBuffer);
if(i_STDBuffer >= 0)
OpenCL.BufferFree(i_STDBuffer);
}
//---
i_WindowsBuffer = INVALID_HANDLE;
i_STDBuffer = INVALID_HANDLE;
i_WindowOut = 0;
i_StackSize = 1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronEmbeddingOCL::SetOpenCL(COpenCLMy *obj)
{
if(OpenCL == obj)
return;
CNeuronBaseOCL::SetOpenCL(obj);
if(!OpenCL)
return;
//---
i_WindowsBuffer = OpenCL.AddBuffer(sizeof(int) * a_Windows.Size(), CL_MEM_READ_WRITE);
if(i_WindowsBuffer >= 0)
OpenCL.BufferWrite(i_WindowsBuffer, a_Windows, 0, 0, a_Windows.Size());
i_STDBuffer = OpenCL.AddBuffer(sizeof(float) * a_Windows.Size(), CL_MEM_READ_WRITE);
//---
WeightsEmbedding.BufferCreate(OpenCL);
FirstMomentumEmbed.BufferCreate(OpenCL);
SecondMomentumEmbed.BufferCreate(OpenCL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronEmbeddingOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint stack_size, uint window_out, int &windows[])
{
if(CheckPointer(open_cl) == POINTER_INVALID || window_out <= 0 || windows.Size() <= 0 || stack_size <= 0)
return false;
if(!!OpenCL && OpenCL != open_cl)
delete OpenCL;
uint numNeurons = window_out * windows.Size() * stack_size;
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons, ADAM, 1))
return false;
//---
uint weights = 0;
ArrayCopy(a_Windows, windows);
i_WindowOut = (int)window_out;
i_StackSize = (int)stack_size;
for(uint i = 0; i < windows.Size(); i++)
weights += (windows[i] + 1) * window_out;
if(!WeightsEmbedding.Reserve(weights))
return false;
float k = 1.0f / sqrt((float)weights / (float)window_out);
for(uint i = 0; i < weights; i++)
if(!WeightsEmbedding.Add(k * (2 * GenerateWeight() - 1.0f)*WeightsMultiplier))
return false;
if(!WeightsEmbedding.BufferCreate(OpenCL))
return false;
//---
if(!FirstMomentumEmbed.BufferInit(weights, 0))
return false;
if(!FirstMomentumEmbed.BufferCreate(OpenCL))
return false;
//---
if(!SecondMomentumEmbed.BufferInit(weights, 0))
return false;
if(!SecondMomentumEmbed.BufferCreate(OpenCL))
return false;
//---
i_WindowsBuffer = OpenCL.AddBuffer(sizeof(int) * a_Windows.Size(), CL_MEM_READ_WRITE);
if(i_WindowsBuffer < 0 || !OpenCL.BufferWrite(i_WindowsBuffer, a_Windows, 0, 0, a_Windows.Size()))
return false;
i_STDBuffer = OpenCL.AddBuffer(sizeof(float) * a_Windows.Size(), CL_MEM_READ_WRITE);
if(i_STDBuffer < 0)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronEmbeddingOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL || !OpenCL)
return false;
//---
if(!OpenCL.SetArgumentBuffer(def_k_Embedding, def_k_emb_inputs, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_Embedding, def_k_emb_outputs, getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_Embedding, def_k_emb_std, i_STDBuffer))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_Embedding, def_k_emb_weights, WeightsEmbedding.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_Embedding, def_k_emb_windows, i_WindowsBuffer))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_Embedding, def_k_emb_stack_size, i_StackSize))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
//---
uint global_work_offset[2] = {0, 0};
uint global_work_size[2] = {i_WindowOut, a_Windows.Size()};
uint local_work_size[2] = {i_WindowOut, 1};
if(!OpenCL.Execute(def_k_Embedding, 2, global_work_offset, global_work_size, local_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
//vector<float> temp;
//Output.GetData(temp);
//float delta = MathAbs(temp - prev_output).Sum();
//prev_output = temp;
//OpenCL.BufferToVector(i_STDBuffer,temp);
//string error;
//CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronEmbeddingOCL::Clear(void)
{
if(!Output.BufferInit(Output.Total(), 0))
return false;
if(!OpenCL)
return true;
//---
return Output.BufferWrite();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronEmbeddingOCL::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL || !OpenCL)
return false;
//---
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingHiddenGradient, def_k_ehg_inputs_gradient, NeuronOCL.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingHiddenGradient, def_k_ehg_outputs_gradient, getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingHiddenGradient, def_k_ehg_std, i_STDBuffer))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingHiddenGradient, def_k_ehg_weights, WeightsEmbedding.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingHiddenGradient, def_k_ehg_windows, i_WindowsBuffer))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_EmbeddingHiddenGradient, def_k_ehg_window_out, i_WindowOut))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {NeuronOCL.Neurons()};
if(!OpenCL.Execute(def_k_EmbeddingHiddenGradient, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
//vector<float> temp;
//NeuronOCL.getGradient().GetData(temp);
//float delta = MathAbs(temp - prev_output).Sum();
//prev_output = temp;
//string error;
//CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronEmbeddingOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL || !OpenCL)
return false;
//---
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_inputs, NeuronOCL.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_gradient, getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_std, i_STDBuffer))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_weights, WeightsEmbedding.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_matrix_m, FirstMomentumEmbed.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_matrix_v, SecondMomentumEmbed.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_windows, i_WindowsBuffer))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_window_out, i_WindowOut))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_learning_rate, lr))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_b1, b1))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_EmbeddingUpdateWeightsAdam, def_k_euw_b2, b2))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {WeightsEmbedding.Total()};
if(!OpenCL.Execute(def_k_EmbeddingUpdateWeightsAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
//vector<float> temp;
//NeuronOCL.getGradient().GetData(temp);
//float delta = MathAbs(temp - prev_output).Sum();
//prev_output = temp;
//string error;
//CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronEmbeddingOCL::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
//---
CNeuronEmbeddingOCL *temp = source;
if(WeightsEmbedding.Total() != temp.WeightsEmbedding.Total())
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {WeightsEmbedding.Total()};
ResetLastError();
if(tau != 1.0f && optimization == ADAM)
{
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_target, WeightsEmbedding.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_source, temp.WeightsEmbedding.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_m, FirstMomentumEmbed.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_v, SecondMomentumEmbed.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b1, (float)b1))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b2, (float)b2))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdateAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
}
else
{
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_target, WeightsEmbedding.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_source, temp.WeightsEmbedding.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdate, def_k_su_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdate, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronEmbeddingOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
//---
if(!WeightsEmbedding.Save(file_handle))
return false;
if(!FirstMomentumEmbed.Save(file_handle))
return false;
if(!SecondMomentumEmbed.Save(file_handle))
return false;
//---
if(FileWriteInteger(file_handle, (int)a_Windows.Size()) != INT_VALUE)
return false;
if(FileWriteArray(file_handle, a_Windows, 0, (int)a_Windows.Size()) != a_Windows.Size())
return false;
//---
if(FileWriteInteger(file_handle, i_WindowOut) != INT_VALUE)
return false;
if(FileWriteInteger(file_handle, i_StackSize) != INT_VALUE)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronEmbeddingOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//---
if(!WeightsEmbedding.Load(file_handle))
return false;
if(!FirstMomentumEmbed.Load(file_handle))
return false;
if(!SecondMomentumEmbed.Load(file_handle))
return false;
//---
int size = FileReadInteger(file_handle);
ArrayResize(a_Windows, size);
if(FileReadArray(file_handle, a_Windows, 0, size) != size)
return false;
//---
i_WindowOut = FileReadInteger(file_handle);
i_StackSize = FileReadInteger(file_handle);
//---
if(!OpenCL)
return true;
//---
if(i_WindowsBuffer != INVALID_HANDLE)
OpenCL.BufferFree(i_WindowsBuffer);
i_WindowsBuffer = OpenCL.AddBuffer(sizeof(int) * a_Windows.Size(), CL_MEM_READ_WRITE);
if(i_WindowsBuffer >= 0)
OpenCL.BufferWrite(i_WindowsBuffer, a_Windows, 0, 0, a_Windows.Size());
if(i_STDBuffer != INVALID_HANDLE)
OpenCL.BufferFree(i_STDBuffer);
i_STDBuffer = OpenCL.AddBuffer(sizeof(float) * a_Windows.Size(), CL_MEM_READ_WRITE);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::Clear(void)
{
if(!opencl)
return true;
if(!layers || layers.Total() <= 0)
return true;
for(int i = 0; i < layers.Total(); i++)
{
CLayer *layer = layers.At(i);
if(!layer)
return false;
for(int n = 0; n < layer.Total(); n++)
{
CNeuronBaseOCL *neuron = layer.At(n);
if(!neuron || !neuron.Clear())
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFQF::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
//---
CNeuronFQF *temp = source;
if(!cFraction.WeightsUpdate(GetPointer(temp.cFraction), tau))
return false;
if(!cSoftMax.WeightsUpdate(GetPointer(temp.cSoftMax), tau))
return false;
if(!cCosine.WeightsUpdate(GetPointer(temp.cCosine), tau))
return false;
if(!cCosineEmbeding.WeightsUpdate(GetPointer(temp.cCosineEmbeding), tau))
return false;
if(!cQuantile0.WeightsUpdate(GetPointer(temp.cQuantile0), tau))
return false;
if(!cQuantile1.WeightsUpdate(GetPointer(temp.cQuantile1), tau))
return false;
if(!cQuantile2.WeightsUpdate(GetPointer(temp.cQuantile2), tau))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
//---
CNeuronMLMHAttentionOCL *temp = source;
if(iLayers != temp.iLayers)
return false;
for(uint l = 0; l < iLayers; l++)
{
if(IsStopped() || !ConvolutuionUpdateWeights(QKV_Weights.At(l * (optimization == SGD ? 2 : 3)), temp.QKV_Weights.At(l * (temp.optimization == SGD ? 2 : 3)), (optimization == SGD ? QKV_Weights.At(l * 2 + 1) : QKV_Weights.At(l * 3 + 1)), (optimization == SGD ? NULL : QKV_Weights.At(l * 3 + 2)), tau))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 6 : 9)), temp.FF_Weights.At(l * (temp.optimization == SGD ? 6 : 9)), (optimization == SGD ? FF_Weights.At(l * 6 + 3) : FF_Weights.At(l * 9 + 3)), (optimization == SGD ? NULL : FF_Weights.At(l * 9 + 6)), tau))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 6 : 9) + 1), temp.FF_Weights.At(l * (temp.optimization == SGD ? 6 : 9) + 1), (optimization == SGD ? FF_Weights.At(l * 6 + 4) : FF_Weights.At(l * 9 + 4)), (optimization == SGD ? NULL : FF_Weights.At(l * 9 + 7)), tau))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 6 : 9) + 2), temp.FF_Weights.At(l * (temp.optimization == SGD ? 6 : 9) + 2), (optimization == SGD ? FF_Weights.At(l * 6 + 5) : FF_Weights.At(l * 9 + 5)), (optimization == SGD ? NULL : FF_Weights.At(l * 9 + 8)), tau))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMLMHAttentionOCL::ConvolutuionUpdateWeights(CBufferFloat *weights, CBufferFloat *source, CBufferFloat *momentum1, CBufferFloat *momentum2, float tau)
{
uint global_work_offset[1] = {0};
uint global_work_size[1] = {weights.Total()};
ResetLastError();
if(tau != 1.0f && optimization == ADAM)
{
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_target, weights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_source, source.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_m, momentum1.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdateAdam, def_k_sua_matrix_v, momentum2.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b1, (float)b1))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdateAdam, def_k_sua_b2, (float)b2))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdateAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
}
else
{
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_target, weights.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_SoftUpdate, def_k_su_source, source.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_SoftUpdate, def_k_su_tau, (float)tau))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_SoftUpdate, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNet::feedForward(CArrayFloat *inputVals, int window = 1, bool tem = true, CNet *secondNet = NULL, int secondLayer = -1)
{
if(CheckPointer(layers) == POINTER_INVALID || CheckPointer(inputVals) == POINTER_INVALID || layers.Total() <= 1)
return false;
//---
CBufferFloat *SecondInput = NULL;
bool del_second = false;
if(!!secondNet)
{
if(secondLayer < 0)
secondLayer = secondNet.layers.Total() - 1;
if(secondNet.GetOpenCL() != opencl)
{
secondNet.GetLayerOutput(secondLayer, SecondInput);
if(!!SecondInput)
{
if(!SecondInput.BufferCreate(opencl))
{
delete SecondInput;
return false;
}
del_second = true;
}
}
else
{
if(secondNet.layers.Total() <= secondLayer)
return false;
CLayer *layer = secondNet.layers.At(secondLayer);
CNeuronBaseOCL *neuron = layer.At(0);
SecondInput = neuron.getOutput();
}
}
//---
CLayer *previous = NULL;
CLayer *current = layers.At(0);
bool result = true;
int total = MathMin(current.Total(), inputVals.Total());
CNeuronBase *neuron = NULL;
if(CheckPointer(opencl) == POINTER_INVALID)
{
for(int i = 0; i < total; i++)
{
neuron = current.At(i);
if(CheckPointer(neuron) == POINTER_INVALID)
{
result = false;
break;
}
int pos = i;
int d = 0;
if(window > 1)
{
d = i % window;
pos = (i - d) / window;
}
neuron.setOutputVal(inputVals.At(i) + (float)(tem ? (d % 2 == 0 ? sin(pos / pow(10000, (2 * d + 1) / (window + 1))) : cos(pos / pow(10000, (2 * d + 1) / (window + 1)))) : 0));
if(tem)
inputVals.Update(i, neuron.getOutputVal());
}
}
else
{
CNeuronBaseOCL *neuron_ocl = current.At(0);
CBufferFloat *inputs = neuron_ocl.getOutput();
if(tem)
{
int total_data = inputVals.Total();
for(int d = 0; d < total_data; d++)
{
int pos = d;
int dim = 0;
if(window > 1)
{
dim = d % window;
pos = (d - dim) / window;
}
float value = pos / pow(10000, (2 * dim + 1) / (float)(window + 1));
value = (float)(inputVals.At(d) + (dim % 2 == 0 ? sin(value) : cos(value)));
if(!inputVals.Update(d, value))
{
result = false;
break;
}
}
}
if(!result || !inputs.AssignArray(inputVals) || !inputs.BufferWrite())
{
if(del_second)
delete SecondInput;
return false;
}
}
//---
CObject *temp = NULL;
//vector<float> res;
for(int l = 1; (l < layers.Total() && result); l++)
{
previous = current;
current = layers.At(l);
if(CheckPointer(current) == POINTER_INVALID)
{
result = false;
break;
}
//---
if(CheckPointer(opencl) != POINTER_INVALID)
{
CNeuronBaseOCL *current_ocl = current.At(0);
if(!current_ocl.FeedForward(previous.At(0), SecondInput))
{
result = false;
break;
}
//current_ocl.getOutputVal(res);
continue;
}
//---
total = current.Total();
if(current.At(0).Type() == defNeuron)
total--;
//---
for(int n = 0; n < total; n++)
{
neuron = current.At(n);
if(CheckPointer(neuron) == POINTER_INVALID)
{
result = false;
break;
}
if(previous.At(0).Type() == defNeuron)
{
temp = previous;
if(!neuron.feedForward(temp))
{
result = false;
break;
}
continue;
}
if(neuron.Type() == defNeuron)
{
if(n == 0)
{
CLayer *temp_l = new CLayer(total);
if(CheckPointer(temp_l) == POINTER_INVALID)
{
result = false;
break;
}
CNeuronProof *proof = NULL;
for(int p = 0; p < previous.Total(); p++)
{
proof = previous.At(p);
if(CheckPointer(proof) == POINTER_INVALID)
{
result = false;
break;
}
temp_l.AddArray(proof.getOutputLayer());
}
temp = temp_l;
}
if(!neuron.feedForward(temp))
{
result = false;
break;
}
if(n == total - 1)
{
CLayer *temp_l = temp;
temp_l.FreeMode(false);
temp_l.Shutdown();
delete temp_l;
}
continue;
}
temp = previous.At(n);
if(CheckPointer(temp) == POINTER_INVALID)
{
result = false;
break;
}
if(!neuron.feedForward(temp))
{
result = false;
break;
}
}
}
//---
if(del_second)
delete SecondInput;
//---
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronPositionEncoder : public CNeuronBaseOCL
{
protected:
CBufferFloat PositionEncoder;
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) { return true; } ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
public:
CNeuronPositionEncoder(void) {};
~CNeuronPositionEncoder(void) {};
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint count, uint window, ENUM_OPTIMIZATION optimization_type, uint batch);
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) { return true; } ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
//---
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) const { return defNeuronPEOCL; }///< Identificator of class.@return Type of class
virtual void SetOpenCL(COpenCLMy *obj);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronPositionEncoder::Init(uint numOutputs, uint myIndex,
COpenCLMy *open_cl, uint count,
uint window,
ENUM_OPTIMIZATION optimization_type,
uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, count * window, optimization_type, batch))
return false;
//---
matrix<float> pe = matrix<float>::Zeros(count, window);
vector<float> position = vector<float>::Ones(count);
position = position.CumSum() - 1;
float multipl = -MathLog(10000.0f) / window;
for(uint i = 0; i < window; i += 2)
{
vector<float> temp = position * MathExp(i * multipl);
pe.Col(MathSin(temp), i);
if((i + 1) < window)
pe.Col(MathCos(temp), i + 1);
}
if(!PositionEncoder.AssignArray(pe))
return false;
//---
return PositionEncoder.BufferCreate(open_cl);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronPositionEncoder::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL)
return false;
if(!Gradient || Gradient != NeuronOCL.getGradient())
{
if(!!Gradient)
delete Gradient;
Gradient = NeuronOCL.getGradient();
}
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Neurons();
if(!OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix1, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix2, PositionEncoder.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_MatrixSum, def_k_sum_matrix_out, Output.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_dimension, (int)1))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_multiplyer, 1.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in1, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_in2, 0.0f))
return false;
if(!OpenCL.SetArgument(def_k_MatrixSum, def_k_sum_shift_out, 0.0f))
return false;
if(!OpenCL.Execute(def_k_MatrixSum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel MatrixSum: %d", GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronPositionEncoder::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
//---
return PositionEncoder.Save(file_handle);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronPositionEncoder::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//---
if(!PositionEncoder.Load(file_handle))
return false;
if(!PositionEncoder.BufferCreate(OpenCL))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronPositionEncoder::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
if(!!OpenCL)
PositionEncoder.BufferCreate(OpenCL);
else
PositionEncoder.BufferFree();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronTransposeOCL : public CNeuronBaseOCL
{
protected:
uint iWindow;
uint iCount;
///\ingroup neuron_base_ff
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL); ///< \brief Feed Forward method of calling kernel ::FeedForward().@param NeuronOCL Pointer to previos layer.
///\ingroup neuron_base_opt
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) { return true; } ///< Method for updating weights.\details Calling one of kernels ::UpdateWeightsMomentum() or ::UpdateWeightsAdam() in depends of optimization type (#ENUM_OPTIMIZATION).@param NeuronOCL Pointer to previos layer.
public:
CNeuronTransposeOCL(void) {};
~CNeuronTransposeOCL(void) {};
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint count, uint window, ENUM_OPTIMIZATION optimization_type, uint batch);
virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL); ///< Method to transfer gradient to previous layer by calling kernel ::CalcHiddenGradient(). @param NeuronOCL Pointer to next layer.
//---
virtual bool Save(int const file_handle);///< Save method @param[in] file_handle handle of file @return logical result of operation
virtual bool Load(int const file_handle);///< Load method @param[in] file_handle handle of file @return logical result of operation
//---
virtual int Type(void) const { return defNeuronTransposeOCL; }///< Identificator of class.@return Type of class
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronTransposeOCL::Init(uint numOutputs, uint myIndex,
COpenCLMy *open_cl, uint count,
uint window,
ENUM_OPTIMIZATION optimization_type,
uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, count * window,
optimization_type, batch))
return false;
//---
iWindow = window;
iCount = count;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronTransposeOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL)
return false;
//---
uint global_work_offset[2] = {0, 0};
uint global_work_size[2] = {iCount, iWindow};
if(!OpenCL.SetArgumentBuffer(def_k_Transpose, def_k_tr_matrix_in, NeuronOCL.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_Transpose, def_k_tr_matrix_out, Output.GetIndex()))
return false;
if(!OpenCL.Execute(def_k_Transpose, 2, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel Transpose: %d -> %s", GetLastError(), error);
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronTransposeOCL::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL)
return false;
//---
uint global_work_offset[2] = {0, 0};
uint global_work_size[2] = {iWindow, iCount};
if(!OpenCL.SetArgumentBuffer(def_k_Transpose, def_k_tr_matrix_out, NeuronOCL.getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_Transpose, def_k_tr_matrix_in, Gradient.GetIndex()))
return false;
if(!OpenCL.Execute(def_k_Transpose, 2, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("Error of execution kernel Transpose: %d -> %s", GetLastError(), error);
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronTransposeOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
//---
if(FileWriteInteger(file_handle, (int)iCount) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iWindow) < INT_VALUE)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronTransposeOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//---
iCount = (uint)FileReadInteger(file_handle);
iWindow = (uint)FileReadInteger(file_handle);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronMH2AttentionOCL : public CNeuronBaseOCL
{
protected:
uint iHeads; ///< Number of heads
uint iWindow; ///< Input window size
uint iUnits; ///< Number of units
uint iWindowKey; ///< Size of Key/Query window
//---
CNeuronConvOCL Q_Embedding;
CNeuronConvOCL KV_Embedding;
CNeuronTransposeOCL Transpose;
int ScoreIndex;
CNeuronBaseOCL MHAttentionOut;
CNeuronConvOCL W0;
CNeuronBaseOCL AttentionOut;
CNeuronConvOCL FF[2];
//---
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL);
virtual bool attentionOut(void);
//---
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL);
virtual bool AttentionInsideGradients(void);
public:
/** Constructor */
CNeuronMH2AttentionOCL(void);
/** Destructor */~CNeuronMH2AttentionOCL(void) {};
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
uint window, uint window_key, uint heads,
uint units_count, ENUM_OPTIMIZATION optimization_type,
uint batch);
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer);
//---
virtual int Type(void) const { return defNeuronMH2AttentionOCL; }
//--- methods for working with files
virtual bool Save(int const file_handle);
virtual bool Load(int const file_handle);
virtual CLayerDescription* GetLayerInfo(void);
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
virtual void SetOpenCL(COpenCLMy *obj);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CNeuronMH2AttentionOCL::CNeuronMH2AttentionOCL(void) : iHeads(0),
iWindow(0),
iUnits(0),
iWindowKey(0)
{
activation = None;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMH2AttentionOCL::Init(uint numOutputs, uint myIndex,
COpenCLMy *open_cl, uint window,
uint window_key, uint heads,
uint units_count,
ENUM_OPTIMIZATION optimization_type,
uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, window * units_count,
optimization_type, batch))
return false;
//---
iWindow = fmax(window, 1);
iWindowKey = fmax(window_key, 1);
iUnits = fmax(units_count, 1);
iHeads = fmax(heads, 1);
activation = None;
//---
if(!Transpose.Init(0, 0, OpenCL, iUnits, iWindow, optimization_type, batch))
return false;
Transpose.SetActivationFunction(None);
//---
if(!Q_Embedding.Init(0, 0, OpenCL, iWindow, iWindow, iWindowKey * iHeads, iUnits, optimization_type, batch))
return false;
Q_Embedding.SetActivationFunction(None);
if(!KV_Embedding.Init(0, 0, OpenCL, iUnits, iUnits, 2 * iWindowKey * iHeads, iWindow, optimization_type, batch))
return false;
KV_Embedding.SetActivationFunction(None);
//---
ScoreIndex = OpenCL.AddBuffer(sizeof(float) * iUnits * iWindow * iHeads, CL_MEM_READ_WRITE);
if(ScoreIndex == INVALID_HANDLE)
return false;
//---
if(!MHAttentionOut.Init(0, 0, OpenCL, iWindowKey * iUnits * iHeads, optimization_type, batch))
return false;
MHAttentionOut.SetActivationFunction(None);
if(!W0.Init(0, 0, OpenCL, iWindowKey * iHeads, iWindowKey * iHeads, iWindow, iUnits, optimization_type, batch))
return false;
W0.SetActivationFunction(None);
if(!AttentionOut.Init(0, 0, OpenCL, iWindow * iUnits, optimization_type, batch))
return false;
AttentionOut.SetActivationFunction(None);
if(!FF[0].Init(0, 0, OpenCL, iWindow, iWindow, 4 * iWindow, iUnits, optimization_type, batch))
return false;
if(!FF[1].Init(0, 0, OpenCL, 4 * iWindow, 4 * iWindow, iWindow, iUnits, optimization_type, batch))
return false;
for(int i = 0; i < 2; i++)
FF[i].SetActivationFunction(None);
//---
Gradient.BufferFree();
delete Gradient;
Gradient = FF[1].getGradient();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMH2AttentionOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
//---
if(!Q_Embedding.FeedForward(NeuronOCL))
return false;
//---
if(!Transpose.FeedForward(NeuronOCL) || !KV_Embedding.FeedForward(NeuronOCL))
return false;
//---
if(!attentionOut())
return false;
//---
if(!W0.FeedForward(GetPointer(MHAttentionOut)))
return false;
//---
if(!SumAndNormilize(W0.getOutput(), NeuronOCL.getOutput(), AttentionOut.getOutput(), iWindow))
return false;
//---
if(!FF[0].FeedForward(GetPointer(AttentionOut)))
return false;
if(!FF[1].FeedForward(GetPointer(FF[0])))
return false;
//---
if(!SumAndNormilize(FF[1].getOutput(), AttentionOut.getOutput(), Output, iWindow))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMH2AttentionOCL::attentionOut(void)
{
if(!OpenCL)
return false;
//---
uint global_work_offset[3] = {0};
uint global_work_size[3] = {iUnits/*Q units*/, iWindow/*K units*/, iHeads};
uint local_work_size[3] = {1, iWindow, 1};
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_q, Q_Embedding.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_kv, KV_Embedding.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_score, ScoreIndex))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_out, MHAttentionOut.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_MH2AttentionOut, def_k_mh2ao_dimension, (int)iWindowKey))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_MH2AttentionOut, 3, global_work_offset, global_work_size, local_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMH2AttentionOCL::AttentionInsideGradients(void)
{
if(!OpenCL)
return false;
//---
uint global_work_offset[3] = {0};
uint global_work_size[3] = {iUnits, iWindowKey, iHeads};
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_q, Q_Embedding.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_qg, Q_Embedding.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_kv, KV_Embedding.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_kvg, KV_Embedding.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_score, ScoreIndex))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_outg, MHAttentionOut.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_MH2AttentionInsideGradients, def_k_mh2aig_kunits, (int)iWindow))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_MH2AttentionInsideGradients, 3, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMH2AttentionOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(!Q_Embedding.UpdateInputWeights(NeuronOCL))
return false;
if(!KV_Embedding.UpdateInputWeights(GetPointer(Transpose)))
return false;
if(!W0.UpdateInputWeights(GetPointer(MHAttentionOut)))
return false;
if(!FF[0].UpdateInputWeights(GetPointer(AttentionOut)))
return false;
if(!FF[1].UpdateInputWeights(GetPointer(FF[0])))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMH2AttentionOCL::calcInputGradients(CNeuronBaseOCL *prevLayer)
{
if(!FF[1].calcInputGradients(GetPointer(FF[0])))
return false;
if(!FF[0].calcInputGradients(GetPointer(AttentionOut)))
return false;
if(!SumAndNormilize(FF[1].getGradient(), AttentionOut.getGradient(), W0.getGradient(), iWindow, false))
return false;
if(!W0.calcInputGradients(GetPointer(MHAttentionOut)))
return false;
if(!AttentionInsideGradients())
return false;
if(!KV_Embedding.calcInputGradients(GetPointer(Transpose)))
return false;
if(!Q_Embedding.calcInputGradients(prevLayer))
return false;
if(!SumAndNormilize(prevLayer.getGradient(), W0.getGradient(), AttentionOut.getGradient(), iWindow, false))
return false;
if(!Transpose.calcInputGradients(prevLayer))
return false;
if(!SumAndNormilize(prevLayer.getGradient(), AttentionOut.getGradient(), prevLayer.getGradient(), iWindow, false))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMH2AttentionOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
if(!Q_Embedding.Save(file_handle))
return false;
if(!KV_Embedding.Save(file_handle))
return false;
if(!Transpose.Save(file_handle))
return false;
if(!W0.Save(file_handle))
return false;
for(int i = 0; i < 2; i++)
if(!FF[i].Save(file_handle))
return false;
if(FileWriteInteger(file_handle, (int)iUnits) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iWindow) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iHeads) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iWindowKey) < INT_VALUE)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMH2AttentionOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
if(FileReadInteger(file_handle) != Q_Embedding.Type() ||
!Q_Embedding.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != KV_Embedding.Type() ||
!KV_Embedding.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != Transpose.Type() ||
!Transpose.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != W0.Type() ||
!W0.Load(file_handle))
return false;
for(int i = 0; i < 2; i++)
if(FileReadInteger(file_handle) != FF[i].Type() ||
!FF[i].Load(file_handle))
return false;
if(Gradient != FF[1].getGradient())
{
Gradient.BufferFree();
delete Gradient;
Gradient = FF[1].getGradient();
}
iUnits = (uint)FileReadInteger(file_handle);
iWindow = (uint)FileReadInteger(file_handle);
iHeads = (uint)FileReadInteger(file_handle);
iWindowKey = (uint)FileReadInteger(file_handle);
if(!!OpenCL)
{
if(ScoreIndex >= 0)
OpenCL.BufferFree(ScoreIndex);
ScoreIndex = OpenCL.AddBuffer(sizeof(float) * iUnits * iWindow * iHeads, CL_MEM_READ_WRITE);
if(ScoreIndex == INVALID_HANDLE)
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronMH2AttentionOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
Q_Embedding.SetOpenCL(OpenCL);
KV_Embedding.SetOpenCL(OpenCL);
Transpose.SetOpenCL(OpenCL);
MHAttentionOut.SetOpenCL(OpenCL);
W0.SetOpenCL(OpenCL);
AttentionOut.SetOpenCL(OpenCL);
FF[0].SetOpenCL(OpenCL);
FF[1].SetOpenCL(OpenCL);
ScoreIndex = OpenCL.AddBuffer(sizeof(float) * iUnits * iWindow * iHeads, CL_MEM_READ_WRITE);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMH2AttentionOCL::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
CNeuronMH2AttentionOCL *src = source;
if(!Q_Embedding.WeightsUpdate(GetPointer(src.Q_Embedding), tau))
return false;
if(!KV_Embedding.WeightsUpdate(GetPointer(src.KV_Embedding), tau))
return false;
if(!W0.WeightsUpdate(GetPointer(src.W0), tau))
return false;
for(int i = 0; i < 2; i++)
if(!FF[i].WeightsUpdate(GetPointer(src.FF[i]), tau))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronCGConvOCL : public CNeuronBaseOCL
{
protected:
CNeuronBaseOCL cInputF;
CNeuronBaseOCL cInputS;
CNeuronBaseOCL cF;
CNeuronBaseOCL cS;
//---
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL);
//---
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL);
public:
CNeuronCGConvOCL(void) {};
~CNeuronCGConvOCL(void) {};
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
uint window, uint numNeurons,
ENUM_OPTIMIZATION optimization_type,
uint batch);
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer);
//---
virtual int Type(void) const { return defNeuronCGConvOCL; }
//--- methods for working with files
virtual bool Save(int const file_handle);
virtual bool Load(int const file_handle);
virtual CLayerDescription* GetLayerInfo(void);
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
virtual void SetOpenCL(COpenCLMy *obj);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCGConvOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint numNeurons, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, numNeurons, optimization_type, batch))
return false;
activation = None;
//---
if(!cInputF.Init(numNeurons, 0, OpenCL, window, optimization, batch))
return false;
if(!cInputS.Init(numNeurons, 1, OpenCL, window, optimization, batch))
return false;
cInputF.SetActivationFunction(None);
cInputS.SetActivationFunction(None);
//---
if(!cF.Init(0, 2, OpenCL, numNeurons, optimization, batch))
return false;
cF.SetActivationFunction(SIGMOID);
if(!cS.Init(0, 3, OpenCL, numNeurons, optimization, batch))
return false;
cS.SetActivationFunction(LReLU);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCGConvOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(!NeuronOCL || !NeuronOCL.getOutput() || NeuronOCL.getOutputIndex() < 0)
return false;
//---
if(cInputF.getOutputIndex() != NeuronOCL.getOutputIndex())
{
if(!cInputF.getOutput().BufferSet(NeuronOCL.getOutputIndex()))
return false;
cInputF.SetActivationFunction((ENUM_ACTIVATION)NeuronOCL.Activation());
}
if(cInputS.getOutputIndex() != NeuronOCL.getOutputIndex())
{
if(!cInputS.getOutput().BufferSet(NeuronOCL.getOutputIndex()))
return false;
cInputS.SetActivationFunction((ENUM_ACTIVATION)NeuronOCL.Activation());
}
//---
if(!cF.FeedForward(GetPointer(cInputF)))
return false;
if(!cS.FeedForward(GetPointer(cInputS)))
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = int(Neurons() + 3) / 4;
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_input, cF.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_map, cS.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_Dropout, def_k_dout_out, Output.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_Dropout, def_k_dout_dimension, Neurons()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_Dropout, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCGConvOCL::calcInputGradients(CNeuronBaseOCL *prevLayer)
{
if(!prevLayer || !prevLayer.getGradient() || prevLayer.getGradientIndex() < 0)
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = Neurons();
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_CGConv_HiddenGradient, def_k_cgc_matrix_f, cF.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_CGConv_HiddenGradient, def_k_cgc_matrix_fg, cF.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_CGConv_HiddenGradient, def_k_cgc_matrix_s, cS.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_CGConv_HiddenGradient, def_k_cgc_matrix_sg, cS.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_CGConv_HiddenGradient, def_k_cgc_matrix_g, getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_CGConv_HiddenGradient, def_k_cgc_activationf, cF.Activation()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_CGConv_HiddenGradient, def_k_cgc_activations, cS.Activation()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_CGConv_HiddenGradient, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
if(!cInputF.calcHiddenGradients(GetPointer(cF)))
return false;
if(!cInputS.calcHiddenGradients(GetPointer(cS)))
return false;
if(!SumAndNormilize(cF.getOutput(), cS.getOutput(), prevLayer.getOutput(), 1, false))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCGConvOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(!cF.UpdateInputWeights(cInputF.AsObject()))
return false;
if(!cS.UpdateInputWeights(cInputS.AsObject()))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCGConvOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
if(!cInputF.Save(file_handle))
return false;
if(!cInputS.Save(file_handle))
return false;
if(!cF.Save(file_handle))
return false;
if(!cS.Save(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCGConvOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cInputF.Type() || !cInputF.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cInputS.Type() || !cInputS.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cF.Type() || !cF.Load(file_handle))
return false;
if(FileReadInteger(file_handle) != cS.Type() || !cS.Load(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCGConvOCL::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
if(!cInputF.WeightsUpdate(source, tau))
return false;
if(!cInputS.WeightsUpdate(source, tau))
return false;
if(!cF.WeightsUpdate(source, tau))
return false;
if(!cS.WeightsUpdate(source, tau))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronCGConvOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
cInputF.SetOpenCL(OpenCL);
cInputS.SetOpenCL(OpenCL);
cF.SetOpenCL(OpenCL);
cS.SetOpenCL(OpenCL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronMFTOCL : public CNeuronMLMHAttentionOCL
{
protected:
//---
CCollection cTranspose;
//---
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL);
virtual bool Transpose(CBufferFloat *in, CBufferFloat *out, int rows, int cols);
virtual bool MHCA(CBufferFloat *q, CBufferFloat *kv,
CBufferFloat *score, CBufferFloat *out);
//---
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL);
virtual bool MHCAInsideGradients(CBufferFloat *q, CBufferFloat *qg,
CBufferFloat *kv, CBufferFloat *kvg,
CBufferFloat *score, CBufferFloat *aog);
public:
CNeuronMFTOCL(void) {};
~CNeuronMFTOCL(void) {};
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
uint window, uint window_key, uint heads,
uint units_count, uint features,
ENUM_OPTIMIZATION optimization_type,
uint batch);
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer);
//---
virtual int Type(void) const { return defNeuronMFTOCL; }
//--- methods for working with files
virtual bool Save(int const file_handle);
virtual bool Load(int const file_handle);
virtual CLayerDescription* GetLayerInfo(void);
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
virtual void SetOpenCL(COpenCLMy *obj);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint window_key, uint heads, uint units_count, uint features, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, window * units_count * features, optimization_type, batch))
return false;
//---
iWindow = fmax(window, 1);
iWindowKey = fmax(window_key, 1);
iUnits = fmax(units_count, 1);
iHeads = fmax(heads, 1);
iLayers = fmax(features, 1);
//--- MHSA
uint num = 3 * iWindowKey * iHeads * iUnits; //Size of QKV tensor
uint qkv_weights = 3 * (iWindow + 1) * iWindowKey * iHeads; //Size of weights' matrix of QKV tensor
uint scores = iUnits * iUnits * iHeads; //Size of Score tensor
uint mh_out = iWindowKey * iHeads * iUnits; //Size of multi-heads self-attention
uint out = iWindow * iUnits; //Size of output tensor
uint w0 = (iWindowKey + 1) * iHeads * iWindow; //Size W0 tensor
//--- MHCA
uint num_q = iWindowKey * iHeads * iUnits; //Size of Q tensor
uint num_kv = 2 * iWindowKey * iHeads * iUnits; //Size of KV tensor
uint q_weights = (iWindow + 1) * iWindowKey * iHeads; //Size of weights' matrix of Q tenzor
uint kv_weights = 2 * (iUnits + 1) * iWindowKey * iHeads; //Size of weights' matrix of KV tenzor
uint scores_ca = iUnits * iWindow * iHeads; //Size of Score tensor
//--- FF
uint ff_1 = 4 * (iWindow + 1) * iWindow; //Size of weights' matrix 1-st feed forward layer
uint ff_2 = (4 * iWindow + 1) * iWindow; //Size of weights' matrix 2-nd feed forward layer
//---
for(uint i = 0; i < iLayers; i++)
{
CBufferFloat *temp = NULL;
for(int d = 0; d < 2; d++)
{
//--- MHSA
//--- Initilize QKV tensor
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(num, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Tensors.Add(temp))
return false;
//--- Initialize scores
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(scores, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!S_Tensors.Add(temp))
return false;
//--- Initialize multi-heads attention out
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(mh_out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!AO_Tensors.Add(temp))
return false;
//--- Initialize attention out
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Tensors.Add(temp))
return false;
//--- MHCA
//--- Initilize QKV tensor
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(num_q, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Tensors.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!cTranspose.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(num_kv, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Tensors.Add(temp))
return false;
//--- Initialize scores
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(scores_ca, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!S_Tensors.Add(temp))
return false;
//--- Initialize multi-heads cross attention out
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(mh_out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!AO_Tensors.Add(temp))
return false;
//--- Initialize attention out
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Tensors.Add(temp))
return false;
//--- Initialize Feed Forward 1
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(4 * out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Tensors.Add(temp))
return false;
//--- Initialize Feed Forward 2
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Tensors.Add(temp))
return false;
}
//--- MHSA
//--- Initilize QKV weights
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(qkv_weights))
return false;
float k = (float)(1 / sqrt(iWindow + 1));
for(uint w = 0; w < qkv_weights; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
//--- Initilize Weights0
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(w0))
return false;
for(uint w = 0; w < w0; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//--- MHCA
//--- Initilize Q weights
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(q_weights))
return false;
for(uint w = 0; w < q_weights; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
//--- Initilize KV weights
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(kv_weights))
return false;
float kv = (float)(1 / sqrt(iUnits + 1));
for(uint w = 0; w < kv_weights; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* kv))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
//--- Initilize Weights0
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(w0))
return false;
for(uint w = 0; w < w0; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//--- Initilize FF Weights
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(ff_1))
return false;
for(uint w = 0; w < ff_1; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//---
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(ff_2))
return false;
k = (float)(1 / sqrt(4 * iWindow + 1));
for(uint w = 0; w < ff_2; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//---
for(int d = 0; d < (optimization == SGD ? 1 : 2); d++)
{
//--- MHSA
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(qkv_weights, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(w0, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//--- MHCA
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(q_weights, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(kv_weights, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(w0, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//--- FF Weights momentus
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(ff_1, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(ff_2, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::Transpose(CBufferFloat *in, CBufferFloat *out, int rows, int cols)
{
if(!in || !out)
return false;
//---
uint global_work_offset[2] = {0, 0};
uint global_work_size[2] = {rows, cols};
if(!OpenCL.SetArgumentBuffer(def_k_Transpose, def_k_tr_matrix_in, in.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_Transpose, def_k_tr_matrix_out, out.GetIndex()))
return false;
if(!OpenCL.Execute(def_k_Transpose, 2, global_work_offset, global_work_size))
{
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
printf("%s %d Error of execution kernel Transpose: %d -> %s", __FUNCTION__, __LINE__, GetLastError(), error);
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::MHCA(CBufferFloat *q, CBufferFloat *kv, CBufferFloat *score, CBufferFloat *out)
{
if(!q || !kv || !score || !out)
return false;
//---
uint global_work_offset[3] = {0};
uint global_work_size[3] = {iUnits, iWindow, iHeads};
uint local_work_size[3] = {1, iWindow, 1};
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_q, q.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_kv, kv.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_score, score.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_out, out.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_MH2AttentionOut, def_k_mh2ao_dimension, (int)iWindowKey))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_MH2AttentionOut, 3, global_work_offset, global_work_size, local_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
//---
for(uint i = 0; (i < iLayers && !IsStopped()); i++)
{
//--- MHSA
//--- Calculate Queries, Keys, Values
CBufferFloat *inputs = NeuronOCL.getOutput();
CBufferFloat *qkv = QKV_Tensors.At(i * 6);
if(IsStopped() || !ConvolutionForward(QKV_Weights.At(i * (optimization == SGD ? 6 : 9)), inputs, qkv, iWindow, 3 * iWindowKey * iHeads, None))
return false;
//--- Score calculation
CBufferFloat *temp = S_Tensors.At(i * 4);
if(IsStopped() || !AttentionScore(qkv, temp, false))
return false;
//--- Multi-heads attention calculation
CBufferFloat *out = AO_Tensors.At(i * 4);
if(IsStopped() || !AttentionOut(qkv, temp, out))
return false;
//--- Attention out calculation
temp = FF_Tensors.At(i * 8);
if(IsStopped() || !ConvolutionForward(FF_Weights.At(i * (optimization == SGD ? 8 : 12)), out, temp, iWindowKey * iHeads, iWindow, None))
return false;
//--- Sum and normilize attention
if(IsStopped() || !SumAndNormilize(temp, inputs, temp, iWindow))
return false;
//--- MHCA
inputs = temp;
CBufferFloat *q = QKV_Tensors.At(i * 6 + 1);
if(IsStopped() || !ConvolutionForward(QKV_Weights.At(i * (optimization == SGD ? 6 : 9) + 1), inputs, q, iWindow, iWindowKey * iHeads, None))
return false;
CBufferFloat *tr = cTranspose.At(i * 2);
if(IsStopped() || !Transpose(inputs, tr, iUnits, iWindow))
return false;
CBufferFloat *kv = QKV_Tensors.At(i * 6 + 2);
if(IsStopped() || !ConvolutionForward(QKV_Weights.At(i * (optimization == SGD ? 6 : 9) + 2), tr, kv, iUnits, 2 * iWindowKey * iHeads, None))
return false;
//--- Multi-heads cross attention calculation
temp = S_Tensors.At(i * 4 + 1);
out = AO_Tensors.At(i * 4 + 1);
if(IsStopped() || !MHCA(q, kv, temp, out))
return false;
//--- Cross Attention out calculation
temp = FF_Tensors.At(i * 8 + 1);
if(IsStopped() || !ConvolutionForward(FF_Weights.At(i * (optimization == SGD ? 8 : 12) + 1), out, temp, iWindowKey * iHeads, iWindow, None))
return false;
//--- Sum and normilize attention
if(IsStopped() || !SumAndNormilize(temp, inputs, temp, iWindow))
return false;
//--- Feed Forward
inputs = temp;
temp = FF_Tensors.At(i * 8 + 2);
if(IsStopped() || !ConvolutionForward(FF_Weights.At(i * (optimization == SGD ? 8 : 12) + 2), inputs, temp, iWindow, 4 * iWindow, LReLU))
return false;
out = FF_Tensors.At(i * 8 + 3);
if(IsStopped() || !ConvolutionForward(FF_Weights.At(i * (optimization == SGD ? 8 : 12) + 3), temp, out, 4 * iWindow, iWindow, activation))
return false;
//--- Sum and normilize out
if(IsStopped() || !SumAndNormilize(out, inputs, Output, iWindow, true, 0, 0, i * inputs.Total()))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::MHCAInsideGradients(CBufferFloat *q, CBufferFloat *qg, CBufferFloat *kv, CBufferFloat *kvg, CBufferFloat *score, CBufferFloat *aog)
{
if(!q || !qg ||
!kv || !kvg ||
!score || !aog)
return false;
//---
uint global_work_offset[3] = {0};
uint global_work_size[3] = {iUnits, iWindowKey, iHeads};
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_q, q.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_qg, qg.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_kv, kv.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_kvg, kvg.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_score, score.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_outg, aog.GetIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_MH2AttentionInsideGradients, def_k_mh2aig_kunits, (int)iWindow))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_MH2AttentionInsideGradients, 3, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::calcInputGradients(CNeuronBaseOCL *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
CBufferFloat *out_grad = Gradient;
CBufferFloat *inp = prevLayer.getOutput();
CBufferFloat *grad = prevLayer.getGradient();
//---
for(int i = 0; (i < (int)iLayers && !IsStopped()); i++)
{
//--- Passing gradient through feed forward layers
if(IsStopped() || !ConvolutionInputGradients(FF_Weights.At(i * (optimization == SGD ? 8 : 12) + 3), Gradient, FF_Tensors.At(i * 8 + 2), FF_Tensors.At(i * 8 + 6), 4 * iWindow, iWindow, None, i * inp.Total()))
return false;
CBufferFloat *temp = FF_Tensors.At(i * 8 + 5);
if(IsStopped() || !ConvolutionInputGradients(FF_Weights.At(i * (optimization == SGD ? 8 : 12) + 2), FF_Tensors.At(i * 8 + 6), FF_Tensors.At(i * 8 + 1), temp, iWindow, 4 * iWindow, LReLU))
return false;
//--- Sum gradient
if(IsStopped() || !SumAndNormilize(Gradient, temp, temp, iWindow, false, i * inp.Total(), 0, 0))
return false;
out_grad = temp;
//--- MHCA
//--- Split gradient to multi-heads
if(IsStopped() || !ConvolutionInputGradients(FF_Weights.At(i * (optimization == SGD ? 8 : 12) + 1), out_grad, AO_Tensors.At(i * 4 + 1), AO_Tensors.At(i * 4 + 3), iWindowKey * iHeads, iWindow, None))
return false;
if(IsStopped() || !MHCAInsideGradients(QKV_Tensors.At(i * 6 + 1), QKV_Tensors.At(i * 6 + 4), QKV_Tensors.At(i * 6 + 2), QKV_Tensors.At(i * 6 + 5), S_Tensors.At(i * 4 + 1), AO_Tensors.At(i * 4 + 3)))
return false;
CBufferFloat *tr = cTranspose.At(i * 2 + 1);
if(IsStopped() || !Transpose(QKV_Tensors.At(i * 6 + 5), tr, iWindow, iUnits))
return false;
//--- Sum
temp = FF_Tensors.At(i * 8 + 4);
if(IsStopped() || !SumAndNormilize(QKV_Tensors.At(i * 6 + 4), tr, temp, iWindow, false))
return false;
if(IsStopped() || !SumAndNormilize(out_grad, temp, temp, iWindow, false))
return false;
//--- MHSA
//--- Split gradient to multi-heads
out_grad = temp;
if(IsStopped() || !ConvolutionInputGradients(FF_Weights.At(i * (optimization == SGD ? 8 : 12)), out_grad, AO_Tensors.At(i * 4), AO_Tensors.At(i * 4 + 2), iWindowKey * iHeads, iWindow, None))
return false;
//--- Passing gradient to query, key and value
if(IsStopped() || !AttentionInsideGradients(QKV_Tensors.At(i * 6), QKV_Tensors.At(i * 6 + 3), S_Tensors.At(i * 4), S_Tensors.At(i * 4 + 1), AO_Tensors.At(i * 4 + 1)))
return false;
//---
if(IsStopped() || !ConvolutionInputGradients(QKV_Weights.At(i * (optimization == SGD ? 6 : 9)), QKV_Tensors.At(i * 6 + 3), inp, tr, iWindow, 3 * iWindowKey * iHeads, None))
return false;
//--- Sum gradients
if(i > 0)
{
if(IsStopped() || !SumAndNormilize(grad, tr, grad, iWindow, false))
return false;
if(IsStopped() || !SumAndNormilize(out_grad, grad, grad, iWindow, false))
return false;
}
else
if(IsStopped() || !SumAndNormilize(out_grad, tr, grad, iWindow, false))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
CBufferFloat *inputs = NeuronOCL.getOutput();
for(uint l = 0; l < iLayers; l++)
{
if(IsStopped() || !ConvolutuionUpdateWeights(QKV_Weights.At(l * (optimization == SGD ? 6 : 9)), QKV_Tensors.At(l * 6 + 3), inputs, (optimization == SGD ? QKV_Weights.At(l * 6 + 3) : QKV_Weights.At(l * 9 + 3)), (optimization == SGD ? NULL : QKV_Weights.At(l * 9 + 6)), iWindow, 3 * iWindowKey * iHeads))
return false;
if(IsStopped() || !ConvolutuionUpdateWeights(QKV_Weights.At(l * (optimization == SGD ? 6 : 9) + 1), QKV_Tensors.At(l * 6 + 4), inputs, (optimization == SGD ? QKV_Weights.At(l * 6 + 4) : QKV_Weights.At(l * 9 + 4)), (optimization == SGD ? NULL : QKV_Weights.At(l * 9 + 7)), iWindow, iWindowKey * iHeads))
return false;
if(IsStopped() || !ConvolutuionUpdateWeights(QKV_Weights.At(l * (optimization == SGD ? 6 : 9) + 2), QKV_Tensors.At(l * 6 + 5), cTranspose.At(l * 2), (optimization == SGD ? QKV_Weights.At(l * 6 + 5) : QKV_Weights.At(l * 9 + 5)), (optimization == SGD ? NULL : QKV_Weights.At(l * 9 + 8)), iUnits, 2 * iWindowKey * iHeads))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 8 : 12)), FF_Tensors.At(l * 8 + 4), AO_Tensors.At(l * 4), (optimization == SGD ? FF_Weights.At(l * 8 + 4) : FF_Weights.At(l * 12 + 4)), (optimization == SGD ? NULL : FF_Weights.At(l * 12 + 8)), iWindowKey * iHeads, iWindow))
return false;
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 8 : 12) + 1), FF_Tensors.At(l * 8 + 5), AO_Tensors.At(l * 4 + 1), (optimization == SGD ? FF_Weights.At(l * 8 + 5) : FF_Weights.At(l * 12 + 5)), (optimization == SGD ? NULL : FF_Weights.At(l * 12 + 9)), iWindowKey * iHeads, iWindow))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 8 : 12) + 2), FF_Tensors.At(l * 8 + 6), FF_Tensors.At(l * 8 + 1), (optimization == SGD ? FF_Weights.At(l * 8 + 6) : FF_Weights.At(l * 12 + 6)), (optimization == SGD ? NULL : FF_Weights.At(l * 12 + 10)), iWindow, 4 * iWindow))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 8 : 12) + 3), FF_Tensors.At(l * 8 + 7), FF_Tensors.At(l * 8 + 2), (optimization == SGD ? FF_Weights.At(l * 8 + 7) : FF_Weights.At(l * 12 + 7)), (optimization == SGD ? NULL : FF_Weights.At(l * 12 + 11)), 4 * iWindow, iWindow))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::Save(const int file_handle)
{
if(!CNeuronMLMHAttentionOCL::Save(file_handle))
return false;
if(!cTranspose.Save(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//--- Loading constants
iLayers = FileReadInteger(file_handle, INT_VALUE);
iHeads = FileReadInteger(file_handle, INT_VALUE);
iWindow = FileReadInteger(file_handle, INT_VALUE);
iUnits = FileReadInteger(file_handle, INT_VALUE);
iWindowKey = FileReadInteger(file_handle, INT_VALUE);
//--- Loading objects
if(!QKV_Tensors.Load(file_handle) || !QKV_Weights.Load(file_handle) || !S_Tensors.Load(file_handle) || !AO_Tensors.Load(file_handle) ||
!FF_Tensors.Load(file_handle) || !FF_Weights.Load(file_handle) || !cTranspose.Load(file_handle))
return false;
if(!QKV_Tensors.SetOpenCL(OpenCL) || !QKV_Weights.SetOpenCL(OpenCL) || !S_Tensors.SetOpenCL(OpenCL) || !AO_Tensors.SetOpenCL(OpenCL) ||
!FF_Tensors.SetOpenCL(OpenCL) || !FF_Weights.SetOpenCL(OpenCL) || !cTranspose.SetOpenCL(OpenCL))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronMFTOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronMLMHAttentionOCL::SetOpenCL(obj);
cTranspose.SetOpenCL(OpenCL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronMFTOCL::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
//---
CNeuronMFTOCL *temp = source;
if(iLayers != temp.iLayers)
return false;
for(uint l = 0; l < iLayers; l++)
{
if(IsStopped() || !ConvolutuionUpdateWeights(QKV_Weights.At(l * (optimization == SGD ? 6 : 9)), temp.QKV_Weights.At(l * (temp.optimization == SGD ? 6 : 9)), (optimization == SGD ? QKV_Weights.At(l * 6 + 3) : QKV_Weights.At(l * 9 + 3)), (optimization == SGD ? NULL : QKV_Weights.At(l * 9 + 6)), tau))
return false;
if(IsStopped() || !ConvolutuionUpdateWeights(QKV_Weights.At(l * (optimization == SGD ? 6 : 9) + 1), temp.QKV_Weights.At(l * (temp.optimization == SGD ? 6 : 9) + 1), (optimization == SGD ? QKV_Weights.At(l * 6 + 4) : QKV_Weights.At(l * 9 + 4)), (optimization == SGD ? NULL : QKV_Weights.At(l * 9 + 7)), tau))
return false;
if(IsStopped() || !ConvolutuionUpdateWeights(QKV_Weights.At(l * (optimization == SGD ? 6 : 9) + 2), temp.QKV_Weights.At(l * (temp.optimization == SGD ? 6 : 9) + 2), (optimization == SGD ? QKV_Weights.At(l * 6 + 5) : QKV_Weights.At(l * 9 + 5)), (optimization == SGD ? NULL : QKV_Weights.At(l * 9 + 8)), tau))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 8 : 12)), temp.FF_Weights.At(l * (temp.optimization == SGD ? 8 : 12)), (optimization == SGD ? FF_Weights.At(l * 8 + 4) : FF_Weights.At(l * 12 + 4)), (optimization == SGD ? NULL : FF_Weights.At(l * 12 + 8)), tau))
return false;
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 8 : 12) + 1), temp.FF_Weights.At(l * (temp.optimization == SGD ? 8 : 12) + 1), (optimization == SGD ? FF_Weights.At(l * 8 + 5) : FF_Weights.At(l * 12 + 5)), (optimization == SGD ? NULL : FF_Weights.At(l * 12 + 9)), tau))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 8 : 12) + 2), temp.FF_Weights.At(l * (temp.optimization == SGD ? 8 : 12) + 2), (optimization == SGD ? FF_Weights.At(l * 8 + 6) : FF_Weights.At(l * 12 + 6)), (optimization == SGD ? NULL : FF_Weights.At(l * 12 + 10)), tau))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 8 : 12) + 3), temp.FF_Weights.At(l * (temp.optimization == SGD ? 8 : 12) + 3), (optimization == SGD ? FF_Weights.At(l * 8 + 7) : FF_Weights.At(l * 12 + 7)), (optimization == SGD ? NULL : FF_Weights.At(l * 12 + 11)), tau))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronXCiTOCL : public CNeuronMLMHAttentionOCL
{
protected:
//---
uint iLPIWindow;
uint iLPIStep;
uint iBatchCount;
//---
CCollection cLPI;
CCollection cLPI_Weights;
//---
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL);
virtual bool XCiT(CBufferFloat *qkv, CBufferFloat *score, CBufferFloat *out);
virtual bool BatchNorm(CBufferFloat *inputs, CBufferFloat *options, CBufferFloat *out);
//---
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL);
virtual bool XCiTInsideGradients(CBufferFloat *qkv, CBufferFloat *qkvg,
CBufferFloat *score, CBufferFloat *aog);
virtual bool BatchNormInsideGradient(CBufferFloat *inputs, CBufferFloat *inputs_g,
CBufferFloat *options, CBufferFloat *out,
CBufferFloat *out_g, ENUM_ACTIVATION activation);
virtual bool BatchNormUpdateWeights(CBufferFloat *options, CBufferFloat *out_g);
public:
CNeuronXCiTOCL(void) {};
~CNeuronXCiTOCL(void) {};
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
uint window, uint lpi_window, uint heads,
uint units_count, uint layers,
ENUM_OPTIMIZATION optimization_type,
uint batch);
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer);
//---
virtual int Type(void) const { return defNeuronXCiTOCL; }
//--- methods for working with files
virtual bool Save(int const file_handle);
virtual bool Load(int const file_handle);
virtual CLayerDescription* GetLayerInfo(void);
//virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
virtual void SetOpenCL(COpenCLMy *obj);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint lpi_window, uint heads, uint units_count, uint layers, ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, window * units_count, optimization_type, batch))
return false;
//---
iWindow = fmax(window, 1);
iUnits = fmax(units_count, 1);
iHeads = fmax(fmin(heads, iWindow), 1);
iWindowKey = fmax((window + iHeads - 1) / iHeads, 1);
iLayers = fmax(layers, 1);
iLPIWindow = fmax(lpi_window, 1);
iLPIStep = 1;
//--- XCA
uint num = 3 * iWindowKey * iHeads * iUnits; //Size of QKV tensor
uint qkv_weights = 3 * (iWindow + 1) * iWindowKey * iHeads; //Size of weights' matrix of QKV tensor
uint scores = iWindowKey * iWindowKey * iHeads; //Size of Score tensor
uint out = iWindow * iUnits; //Size of output tensor
//--- LPI
uint lpi1_num = iWindow * iHeads * iUnits; //Size of LPI1 tensor
uint lpi1_weights = (iLPIWindow + 1) * iHeads; //Size of weights' matrix of LPI1 tenzor
uint lpi2_weights = (iHeads + 1) * 2; //Size of weights' matrix of LPI2 tenzor
//--- FF
uint ff_1 = 4 * (iWindow + 1) * iWindow; //Size of weights' matrix 1-st feed forward layer
uint ff_2 = (4 * iWindow + 1) * iWindow; //Size of weights' matrix 2-nd feed forward layer
//---
for(uint i = 0; i < iLayers; i++)
{
CBufferFloat *temp = NULL;
for(int d = 0; d < 2; d++)
{
//--- XCiT
//--- Initilize QKV tensor
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(num, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Tensors.Add(temp))
return false;
//--- Initialize scores
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(scores, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!S_Tensors.Add(temp))
return false;
//--- Initialize attention out
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!AO_Tensors.Add(temp))
return false;
//--- LPI
//--- Initilize LPI tensor
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(lpi1_num, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!cLPI.Add(temp)) // LPI1
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(lpi1_num, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!cLPI.Add(temp)) // LPI Normalize
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!cLPI.Add(temp)) // LPI2
return false;
//--- Initialize Feed Forward 1
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(4 * out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Tensors.Add(temp))
return false;
//--- Initialize Feed Forward 2
if(i == iLayers - 1)
{
if(!FF_Tensors.Add(d == 0 ? Output : Gradient))
return false;
continue;
}
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(out, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Tensors.Add(temp))
return false;
}
//--- XCiT
//--- Initilize QKV weights
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(qkv_weights))
return false;
float k = (float)(1 / sqrt(iWindow + 1));
for(uint w = 0; w < qkv_weights; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
//--- Initilize LPI1
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(lpi1_weights))
return false;
for(uint w = 0; w < lpi1_weights; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!cLPI_Weights.Add(temp))
return false;
//--- Normalization
int count = (int)lpi1_num * (optimization_type == SGD ? 7 : 9);
temp = new CBufferFloat();
if(!temp.BufferInit(count, 0.0f))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!cLPI_Weights.Add(temp))
return false;
//--- Initilize LPI2
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(lpi2_weights))
return false;
for(uint w = 0; w < lpi2_weights; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!cLPI_Weights.Add(temp))
return false;
//--- Initilize FF Weights
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(ff_1))
return false;
for(uint w = 0; w < ff_1; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//---
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.Reserve(ff_2))
return false;
k = (float)(1 / sqrt(4 * iWindow + 1));
for(uint w = 0; w < ff_2; w++)
{
if(!temp.Add((GenerateWeight() - 0.5f)* k))
return false;
}
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
//---
for(int d = 0; d < (optimization == SGD ? 1 : 2); d++)
{
//--- XCiT
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(qkv_weights, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!QKV_Weights.Add(temp))
return false;
//--- LPI
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(lpi1_weights, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!cLPI_Weights.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(lpi2_weights, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!cLPI_Weights.Add(temp))
return false;
//--- FF Weights momentus
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(ff_1, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
temp = new CBufferFloat();
if(CheckPointer(temp) == POINTER_INVALID)
return false;
if(!temp.BufferInit(ff_2, 0))
return false;
if(!temp.BufferCreate(OpenCL))
return false;
if(!FF_Weights.Add(temp))
return false;
}
}
iBatchCount = 1;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::XCiT(CBufferFloat *qkv, CBufferFloat *score, CBufferFloat *out)
{
if(!OpenCL || !qkv || !score || !out)
return false;
//---
uint global_work_offset[3] = {0, 0, 0};
uint global_work_size[3] = {iWindowKey, iUnits, iHeads};
uint local_work_size[3] = {iWindowKey, iUnits, 1};
if(!OpenCL.SetArgumentBuffer(def_k_XCiTFeedForward, def_k_XCiTff_qkv, qkv.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_XCiTFeedForward, def_k_XCiTff_score, score.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_XCiTFeedForward, def_k_XCiTff_out, out.GetIndex()))
return false;
ResetLastError();
if(!OpenCL.Execute(def_k_XCiTFeedForward, 3, global_work_offset, global_work_size, local_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
string error;
CLGetInfoString(OpenCL.GetContext(), CL_ERROR_DESCRIPTION, error);
Print(error);
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
//---
for(uint i = 0; (i < iLayers && !IsStopped()); i++)
{
//--- Calculate Queries, Keys, Values
CBufferFloat *inputs = (i == 0 ? NeuronOCL.getOutput() : FF_Tensors.At(4 * i - 2));
CBufferFloat *qkv = QKV_Tensors.At(i * 2);
if(IsStopped() || !ConvolutionForward(QKV_Weights.At(i * (optimization == SGD ? 2 : 3)), inputs, qkv, iWindow, 3 * iWindowKey * iHeads, None))
return false;
//--- Score calculation
CBufferFloat *temp = S_Tensors.At(i * 2);
CBufferFloat *out = AO_Tensors.At(i * 2);
if(IsStopped() || !XCiT(qkv, temp, out))
return false;
//--- Sum and normilize attention
if(IsStopped() || !SumAndNormilize(out, inputs, out, iWindow, true))
return false;
//--- LPI
inputs = out;
temp = cLPI.At(i * 6);
if(IsStopped() || !ConvolutionForward(cLPI_Weights.At(i * (optimization == SGD ? 5 : 7)), inputs, temp, iLPIWindow, iHeads, LReLU, iLPIStep))
return false;
out = cLPI.At(i * 6 + 1);
if(IsStopped() || !BatchNorm(temp, cLPI_Weights.At(i * (optimization == SGD ? 5 : 7) + 1), out))
return false;
temp = out;
out = cLPI.At(i * 6 + 2);
if(IsStopped() || !ConvolutionForward(cLPI_Weights.At(i * (optimization == SGD ? 5 : 7) + 2), temp, out, 2 * iHeads, 2, None, iHeads))
return false;
//--- Sum and normilize attention
if(IsStopped() || !SumAndNormilize(out, inputs, out, iWindow, true))
return false;
//--- Feed Forward
inputs = out;
temp = FF_Tensors.At(i * 4);
if(IsStopped() || !ConvolutionForward(FF_Weights.At(i * (optimization == SGD ? 4 : 6)), inputs, temp, iWindow, 4 * iWindow, LReLU))
return false;
out = FF_Tensors.At(i * 4 + 1);
if(IsStopped() || !ConvolutionForward(FF_Weights.At(i * (optimization == SGD ? 4 : 6) + 1), temp, out, 4 * iWindow, iWindow, activation))
return false;
//--- Sum and normilize out
if(IsStopped() || !SumAndNormilize(out, inputs, out, iWindow, true))
return false;
}
iBatchCount++;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::BatchNorm(CBufferFloat *inputs, CBufferFloat *options, CBufferFloat *out)
{
if(!OpenCL || !inputs || !options || !out)
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = inputs.Total();
iBatchCount = MathMin(iBatchCount, iBatch);
if(!OpenCL.SetArgumentBuffer(def_k_BatchFeedForward, def_k_bff_inputs, inputs.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_BatchFeedForward, def_k_bff_options, options.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_BatchFeedForward, def_k_bff_output, out.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_BatchFeedForward, def_k_bff_batch, (int)iBatchCount))
return false;
if(!OpenCL.SetArgument(def_k_BatchFeedForward, def_k_bff_optimization, (int)optimization))
return false;
if(!OpenCL.SetArgument(def_k_BatchFeedForward, def_k_bff_activation, (int)None))
return false;
ResetLastError();
if(!OpenCL.Execute(def_k_BatchFeedForward, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::BatchNormInsideGradient(CBufferFloat *inputs, CBufferFloat *inputs_g, CBufferFloat *options, CBufferFloat *out, CBufferFloat *out_g, ENUM_ACTIVATION activ)
{
if(!OpenCL || !inputs || !inputs_g || !options || !out || !out_g)
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = inputs.Total();
if(!OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientBatch, def_k_bchg_matrix_i, inputs.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientBatch, def_k_bchg_options, options.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientBatch, def_k_bchg_matrix_g, out_g.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_CalcHiddenGradientBatch, def_k_bchg_matrix_ig, inputs_g.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_CalcHiddenGradientBatch, def_k_bchg_activation, (int)activ))
return false;
if(!OpenCL.SetArgument(def_k_CalcHiddenGradientBatch, def_k_bchg_batch, (int)iBatchCount))
return false;
if(!OpenCL.SetArgument(def_k_CalcHiddenGradientBatch, def_k_bchg_optimization, (int)optimization))
return false;
ResetLastError();
if(!OpenCL.Execute(def_k_CalcHiddenGradientBatch, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::BatchNormUpdateWeights(CBufferFloat *options, CBufferFloat *out_g)
{
if(!OpenCL || !options || !out_g)
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1];
global_work_size[0] = out_g.Total();
//---
if(optimization == SGD)
{
if(!OpenCL.SetArgumentBuffer(def_k_UpdateBatchOptionsMomentum, def_k_buom_options, options.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateBatchOptionsMomentum, def_k_buom_matrix_g, out_g.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsMomentum, def_k_buom_learning_rates, lr))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsMomentum, def_k_buom_momentum, alpha))
return false;
ResetLastError();
if(!OpenCL.Execute(def_k_UpdateBatchOptionsMomentum, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateBatchOptionsMomentum %d", GetLastError());
return false;
}
}
else
{
if(!OpenCL.SetArgumentBuffer(def_k_UpdateBatchOptionsAdam, def_k_buoa_options, options.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_UpdateBatchOptionsAdam, def_k_buoa_matrix_g, out_g.GetIndex()))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsAdam, def_k_buoa_l, lr))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsAdam, def_k_buoa_b1, b1))
return false;
if(!OpenCL.SetArgument(def_k_UpdateBatchOptionsAdam, def_k_buoa_b2, b2))
return false;
ResetLastError();
if(!OpenCL.Execute(def_k_UpdateBatchOptionsAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel UpdateBatchOptionsAdam %d", GetLastError());
return false;
}
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::XCiTInsideGradients(CBufferFloat *qkv, CBufferFloat *qkvg, CBufferFloat *score, CBufferFloat *aog)
{
if(!OpenCL || !qkv || !qkvg || !score || !aog)
return false;
//---
uint global_work_offset[3] = {0, 0, 0};
uint global_work_size[3] = {iWindowKey, iUnits, iHeads};
if(!OpenCL.SetArgumentBuffer(def_k_XCiTInsideGradients, def_k_XCiTig_qkv, qkv.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_XCiTInsideGradients, def_k_XCiTig_qkv_g, qkvg.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_XCiTInsideGradients, def_k_XCiTig_scores, score.GetIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_XCiTInsideGradients, def_k_XCiTig_gradient, aog.GetIndex()))
return false;
ResetLastError();
if(!OpenCL.Execute(def_k_XCiTInsideGradients, 3, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::calcInputGradients(CNeuronBaseOCL *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
CBufferFloat *out_grad = Gradient;
//---
for(int i = int(iLayers - 1); (i >= 0 && !IsStopped()); i--)
{
//--- Passing gradient through feed forward layers
if(IsStopped() || !ConvolutionInputGradients(FF_Weights.At(i * (optimization == SGD ? 4 : 6) + 1), out_grad, FF_Tensors.At(i * 4), FF_Tensors.At(i * 4 + 2), 4 * iWindow, iWindow, None))
return false;
CBufferFloat *temp = cLPI.At(i * 6 + 5);
if(IsStopped() || !ConvolutionInputGradients(FF_Weights.At(i * (optimization == SGD ? 4 : 6)), FF_Tensors.At(i * 4 + 1), cLPI.At(i * 6 + 2), temp, iWindow, 4 * iWindow, LReLU))
return false;
//--- Sum and normilize gradients
if(IsStopped() || !SumAndNormilize(out_grad, temp, temp, iWindow, false))
return false;
out_grad = temp;
//--- Passing gradient through LPI
if(IsStopped() || !ConvolutionInputGradients(cLPI_Weights.At(i * (optimization == SGD ? 5 : 7) + 2), temp, cLPI.At(i * 6 + 1), cLPI.At(i * 6 + 4), 2 * iHeads, 2, None, 0, iHeads))
return false;
if(IsStopped() || !BatchNormInsideGradient(cLPI.At(i * 6), cLPI.At(i * 6 + 3), cLPI_Weights.At(i * (optimization == SGD ? 5 : 7) + 1), cLPI.At(i * 6 + 1), cLPI.At(i * 6 + 4), LReLU))
return false;
if(IsStopped() || !ConvolutionInputGradients(cLPI_Weights.At(i * (optimization == SGD ? 5 : 7)), cLPI.At(i * 6 + 3), AO_Tensors.At(i * 2), AO_Tensors.At(i * 2 + 1), iLPIWindow, iHeads, None, 0, iLPIStep))
return false;
temp = AO_Tensors.At(i * 2 + 1);
//--- Sum and normilize gradients
if(IsStopped() || !SumAndNormilize(out_grad, temp, temp, iWindow, false))
return false;
out_grad = temp;
//--- Passing gradient to query, key and value
if(IsStopped() || !XCiTInsideGradients(QKV_Tensors.At(i * 2), QKV_Tensors.At(i * 2 + 1), S_Tensors.At(i * 2), temp))
return false;
//---
CBufferFloat *inp = NULL;
if(i == 0)
{
inp = prevLayer.getOutput();
temp = prevLayer.getGradient();
}
else
{
temp = FF_Tensors.At(i * 4 - 1);
inp = FF_Tensors.At(i * 4 - 3);
}
if(IsStopped() || !ConvolutionInputGradients(QKV_Weights.At(i * (optimization == SGD ? 2 : 3)), QKV_Tensors.At(i * 2 + 1), inp, temp, iWindow, 3 * iWindowKey * iHeads, None))
return false;
//--- Sum and normilize gradients
if(IsStopped() || !SumAndNormilize(out_grad, temp, temp, iWindow))
return false;
if(i > 0)
out_grad = temp;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(CheckPointer(NeuronOCL) == POINTER_INVALID)
return false;
CBufferFloat *inputs = NeuronOCL.getOutput();
for(uint l = 0; l < iLayers; l++)
{
if(IsStopped() || !ConvolutuionUpdateWeights(QKV_Weights.At(l * (optimization == SGD ? 2 : 3)), QKV_Tensors.At(l * 2 + 1), inputs, (optimization == SGD ? QKV_Weights.At(l * 2 + 1) : QKV_Weights.At(l * 3 + 1)), (optimization == SGD ? NULL : QKV_Weights.At(l * 3 + 2)), iWindow, 3 * iWindowKey * iHeads))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(cLPI_Weights.At(l * (optimization == SGD ? 5 : 7)), cLPI.At(l * 6 + 3), AO_Tensors.At(l * 2), (optimization == SGD ? cLPI_Weights.At(l * 5 + 3) : cLPI_Weights.At(l * 7 + 3)), (optimization == SGD ? NULL : cLPI_Weights.At(l * 7 + 5)), iLPIWindow, iHeads, iLPIStep))
return false;
if(IsStopped() || !BatchNormUpdateWeights(cLPI_Weights.At(l * (optimization == SGD ? 5 : 7) + 1), cLPI.At(l * 6 + 4)))
return false;
if(IsStopped() || !ConvolutuionUpdateWeights(cLPI_Weights.At(l * (optimization == SGD ? 5 : 7) + 2), cLPI.At(l * 6 + 5), cLPI.At(l * 6 + 1), (optimization == SGD ? cLPI_Weights.At(l * 5 + 4) : cLPI_Weights.At(l * 7 + 4)), (optimization == SGD ? NULL : cLPI_Weights.At(l * 7 + 6)), 2 * iHeads, 2, iHeads))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 4 : 6)), FF_Tensors.At(l * 4 + 2), cLPI.At(l * 6 + 2), (optimization == SGD ? FF_Weights.At(l * 4 + 2) : FF_Weights.At(l * 6 + 2)), (optimization == SGD ? NULL : FF_Weights.At(l * 6 + 4)), iWindow, 4 * iWindow))
return false;
//---
if(IsStopped() || !ConvolutuionUpdateWeights(FF_Weights.At(l * (optimization == SGD ? 4 : 6) + 1), FF_Tensors.At(l * 4 + 3), FF_Tensors.At(l * 4), (optimization == SGD ? FF_Weights.At(l * 4 + 3) : FF_Weights.At(l * 6 + 3)), (optimization == SGD ? NULL : FF_Weights.At(l * 6 + 5)), 4 * iWindow, iWindow))
return false;
inputs = FF_Tensors.At(l * 4 + 1);
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::Save(const int file_handle)
{
if(!CNeuronMLMHAttentionOCL::Save(file_handle))
return false;
//--- Saving constants
if(!FileWriteInteger(file_handle, iLPIWindow, INT_VALUE) || !FileWriteInteger(file_handle, iLPIStep, INT_VALUE) ||
!FileWriteInteger(file_handle, iBatchCount, INT_VALUE))
return false;
//--- Saving objects
if(!cLPI.Save(file_handle) || !cLPI_Weights.Save(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronXCiTOCL::Load(const int file_handle)
{
if(!CNeuronMLMHAttentionOCL::Load(file_handle))
return false;
//--- Saving constants
iLPIWindow = FileReadInteger(file_handle, INT_VALUE);
iLPIStep = FileReadInteger(file_handle, INT_VALUE);
iBatchCount = FileReadInteger(file_handle, INT_VALUE);
//--- Loading objects
if(!cLPI.Load(file_handle) || !cLPI_Weights.Load(file_handle))
return false;
if(!cLPI.SetOpenCL(OpenCL) || !cLPI_Weights.SetOpenCL(OpenCL))
return false;
//---
Output = FF_Tensors.At(iLayers * 4 - 3);
Gradient = FF_Tensors.At(iLayers * 4 - 1);
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronXCiTOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronMLMHAttentionOCL::SetOpenCL(obj);
cLPI.SetOpenCL(OpenCL);
cLPI_Weights.SetOpenCL(OpenCL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronDOTOCL : public CNeuronBaseOCL
{
protected:
uint iWindowSize;
uint iPrevWindowSize;
uint iDimension;
uint iUnits;
uint iHeads;
//---
CNeuronConvOCL cProjInput;
CNeuronConvOCL cQKV;
int iScoreBuffer;
CNeuronBaseOCL cRelativePositionsBias;
CNeuronBaseOCL MHAttentionOut;
CNeuronConvOCL cProj;
CNeuronBaseOCL AttentionOut;
CNeuronConvOCL cFF1;
CNeuronConvOCL cFF2;
CNeuronBaseOCL SAttenOut;
CNeuronXCiTOCL cCAtten;
//---
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL);
virtual bool DOT(void);
//---
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL);
virtual bool updateRelativePositionsBias(void);
virtual bool DOTInsideGradients(void);
public:
CNeuronDOTOCL(void) {};
~CNeuronDOTOCL(void) {};
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
uint window, uint dimension, uint heads,
uint units_count, uint prev_window,
ENUM_OPTIMIZATION optimization_type,
uint batch);
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer);
//---
virtual int Type(void) const { return defNeuronDOTOCL; }
//--- methods for working with files
virtual bool Save(int const file_handle);
virtual bool Load(int const file_handle);
virtual CLayerDescription* GetLayerInfo(void);
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
virtual void SetOpenCL(COpenCLMy *obj);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDOTOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint window, uint dimension, uint heads, uint units_count, uint prev_window, ENUM_OPTIMIZATION optimization_type, uint batch)
{
//---
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, window * units_count, optimization_type, batch))
return false;
//---
if(prev_window != window)
{
if(!cProjInput.Init(0, 0, OpenCL, prev_window, prev_window, window, units_count, optimization_type, batch))
return false;
}
//---
iWindowSize = window;
iPrevWindowSize = prev_window;
iDimension = dimension;
iHeads = heads;
iUnits = units_count;
//---
if(!cQKV.Init(0, 1, OpenCL, window, window, dimension * heads, units_count, optimization_type, batch))
return false;
//---
iScoreBuffer = OpenCL.AddBuffer(sizeof(float) * iUnits * iHeads * 3, CL_MEM_READ_WRITE);
if(iScoreBuffer < 0)
return false;
//---
if(!cRelativePositionsBias.Init(1, 2, OpenCL, iUnits * iHeads * 3, optimization_type, batch))
return false;
if(!MHAttentionOut.Init(0, 3, OpenCL, iUnits * iHeads * iDimension, optimization_type, batch))
return false;
if(!cProj.Init(0, 4, OpenCL, iHeads * iDimension, iHeads * iDimension, window, iUnits, optimization_type, batch))
return false;
if(!AttentionOut.Init(0, 5, OpenCL, iUnits * window, optimization_type, batch))
return false;
if(!cFF1.Init(0, 6, OpenCL, window, window, 4 * window, units_count, optimization_type, batch))
return false;
if(!cFF2.Init(0, 7, OpenCL, window * 4, window * 4, window, units_count, optimization_type, batch))
return false;
if(!SAttenOut.Init(0, 8, OpenCL, iUnits * window, optimization_type, batch))
return false;
if(!cCAtten.Init(0, 9, OpenCL, window, MathMax(window / 2, 3), 8, iUnits, 1, optimization_type, batch))
return false;
//---
if(!!Output)
delete Output;
Output = cCAtten.getOutput();
if(!!Gradient)
delete Gradient;
Gradient = cCAtten.getGradient();
SAttenOut.SetGradientIndex(cFF2.getGradientIndex());
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDOTOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
CNeuronBaseOCL* inputs = NeuronOCL;
if(iPrevWindowSize != iWindowSize)
{
if(!cProjInput.FeedForward(inputs) ||
!cQKV.FeedForward(GetPointer(cProjInput)))
return false;
inputs = GetPointer(cProjInput);
}
else
if(!cQKV.FeedForward(inputs))
return false;
if(!DOT())
return false;
if(!cProj.FeedForward(GetPointer(MHAttentionOut)))
return false;
if(!SumAndNormilize(inputs.getOutput(), cProj.getOutput(), AttentionOut.getOutput(), iWindowSize, true))
return false;
if(!cFF1.FeedForward(GetPointer(AttentionOut)))
return false;
if(!cFF2.FeedForward(GetPointer(cFF1)))
return false;
if(!SumAndNormilize(AttentionOut.getOutput(), cFF2.getOutput(), SAttenOut.getOutput(), iWindowSize, true))
return false;
if(!cCAtten.FeedForward(GetPointer(SAttenOut)))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDOTOCL::DOT(void)
{
if(!OpenCL)
return false;
//---
uint global_work_offset[3] = {0, 0, 0};
uint global_work_size[3] = {iDimension, iUnits, iHeads};
uint local_work_size[3] = {iDimension, 1, 1};
if(!OpenCL.SetArgumentBuffer(def_k_DOTFeedForward, def_k_dot_qkv, cQKV.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_DOTFeedForward, def_k_dot_score, iScoreBuffer))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_DOTFeedForward, def_k_dot_rpb, cRelativePositionsBias.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_DOTFeedForward, def_k_dot_out, MHAttentionOut.getOutputIndex()))
return false;
ResetLastError();
if(!OpenCL.Execute(def_k_DOTFeedForward, 3, global_work_offset, global_work_size, local_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDOTOCL::DOTInsideGradients(void)
{
if(!OpenCL)
return false;
//---
uint global_work_offset[3] = {0, 0, 0};
uint global_work_size[3] = {iUnits, iDimension, iHeads};
if(!OpenCL.SetArgumentBuffer(def_k_DOTInsideGradients, def_k_dotg_qkv, cQKV.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_DOTInsideGradients, def_k_dotg_qkv_g, cQKV.getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_DOTInsideGradients, def_k_dotg_scores, iScoreBuffer))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_DOTInsideGradients, def_k_dotg_rpb, cRelativePositionsBias.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_DOTInsideGradients, def_k_dotg_rpb_g, cRelativePositionsBias.getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_DOTInsideGradients, def_k_dotg_gradient, MHAttentionOut.getGradientIndex()))
return false;
ResetLastError();
if(!OpenCL.Execute(def_k_DOTInsideGradients, 3, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDOTOCL::calcInputGradients(CNeuronBaseOCL *prevLayer)
{
if(!prevLayer)
return false;
//---
if(!cCAtten.calcInputGradients(GetPointer(SAttenOut)))
return false;
if(!cFF2.calcInputGradients(GetPointer(cFF1)))
return false;
if(!cFF1.calcInputGradients(GetPointer(AttentionOut)))
return false;
if(!SumAndNormilize(AttentionOut.getGradient(), SAttenOut.getGradient(), cProj.getGradient(), iWindowSize, false))
return false;
if(!cProj.calcInputGradients(GetPointer(MHAttentionOut)))
return false;
if(!DOTInsideGradients())
return false;
//---
if(iPrevWindowSize != iWindowSize)
{
if(!cQKV.calcInputGradients(GetPointer(cProjInput)))
return false;
if(!SumAndNormilize(cProjInput.getGradient(), cProj.getGradient(), cProjInput.getGradient(), iWindowSize, false))
return false;
if(!cProjInput.calcInputGradients(prevLayer))
return false;
}
else
{
if(!cQKV.calcInputGradients(prevLayer))
return false;
if(!SumAndNormilize(prevLayer.getGradient(), cProj.getGradient(), prevLayer.getGradient(), iWindowSize, false))
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronDOTOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
cProjInput.SetOpenCL(OpenCL);
cQKV.SetOpenCL(OpenCL);
iScoreBuffer = OpenCL.AddBuffer(sizeof(float) * iUnits * iHeads * 3, CL_MEM_READ_WRITE);
cRelativePositionsBias.SetOpenCL(OpenCL);
MHAttentionOut.SetOpenCL(OpenCL);
cProj.SetOpenCL(OpenCL);
AttentionOut.SetOpenCL(OpenCL);;
cFF1.SetOpenCL(OpenCL);
cFF2.SetOpenCL(OpenCL);
SAttenOut.SetOpenCL(OpenCL);
cCAtten.SetOpenCL(OpenCL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDOTOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
//---
if(FileWriteInteger(file_handle, (int)iWindowSize) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iPrevWindowSize) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iDimension) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iUnits) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iHeads) < INT_VALUE)
return false;
//---
ResetLastError();
if(iWindowSize != iPrevWindowSize)
if(!cProjInput.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
if(!cQKV.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
if(!cRelativePositionsBias.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
if(!MHAttentionOut.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
if(!cProj.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
if(!AttentionOut.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
if(!cFF1.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
if(!cFF2.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
if(!SAttenOut.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
if(!cCAtten.Save(file_handle))
{
PrintFormat("%s -> %d: %d", __FUNCTION__, __LINE__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDOTOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
//---
iWindowSize = (uint)FileReadInteger(file_handle);
iPrevWindowSize = (uint)FileReadInteger(file_handle);
iDimension = (uint)FileReadInteger(file_handle);
iUnits = (uint)FileReadInteger(file_handle);
iHeads = (uint)FileReadInteger(file_handle);
//---
if(iWindowSize != iPrevWindowSize)
if(!LoadInsideLayer(file_handle, GetPointer(cProjInput)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cQKV)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cRelativePositionsBias)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(MHAttentionOut)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cProj)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(AttentionOut)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cFF1)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cFF2)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(SAttenOut)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cCAtten)))
return false;
//---
iScoreBuffer = OpenCL.AddBuffer(sizeof(float) * iUnits * iHeads * 3, CL_MEM_READ_WRITE);
if(iScoreBuffer < 0)
return false;
//---
if(!!Output)
delete Output;
Output = cCAtten.getOutput();
if(!!Gradient)
delete Gradient;
Gradient = cCAtten.getGradient();
SAttenOut.SetGradientIndex(cFF2.getGradientIndex());
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDOTOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(iWindowSize != iPrevWindowSize)
{
if(!cProjInput.UpdateInputWeights(NeuronOCL))
return false;
if(!cQKV.UpdateInputWeights(GetPointer(cProjInput)))
return false;
}
else
{
if(!cQKV.UpdateInputWeights(NeuronOCL))
return false;
}
//---
if(!cProj.UpdateInputWeights(GetPointer(MHAttentionOut)))
return false;
if(!cFF1.UpdateInputWeights(GetPointer(AttentionOut)))
return false;
if(!cFF2.UpdateInputWeights(GetPointer(cFF1)))
return false;
if(!cCAtten.UpdateInputWeights(GetPointer(SAttenOut)))
return false;
if(!updateRelativePositionsBias())
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronDOTOCL::updateRelativePositionsBias(void)
{
if(!OpenCL)
return false;
//---
uint global_work_offset[1] = {0};
uint global_work_size[1] = {cRelativePositionsBias.Neurons()};
if(!OpenCL.SetArgumentBuffer(def_k_RPBUpdateAdam, def_k_rpbw_rpb, cRelativePositionsBias.getOutputIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_RPBUpdateAdam, def_k_rpbw_gradient, cRelativePositionsBias.getGradientIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_RPBUpdateAdam, def_k_rpbw_matrix_m, cRelativePositionsBias.getFirstMomentumIndex()))
return false;
if(!OpenCL.SetArgumentBuffer(def_k_RPBUpdateAdam, def_k_rpbw_matrix_v, cRelativePositionsBias.getSecondMomentumIndex()))
return false;
if(!OpenCL.SetArgument(def_k_RPBUpdateAdam, def_k_rpbw_b1, b1))
return false;
if(!OpenCL.SetArgument(def_k_RPBUpdateAdam, def_k_rpbw_b2, b2))
return false;
ResetLastError();
if(!OpenCL.Execute(def_k_RPBUpdateAdam, 1, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronBaseOCL::LoadInsideLayer(int file_handle, CNeuronBaseOCL *neuron)
{
if(!neuron)
return false;
if(FileReadInteger(file_handle) != neuron.Type())
return false;
if(neuron.OpenCL != OpenCL)
neuron.SetOpenCL(OpenCL);
//---
return neuron.Load(file_handle);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronFAQOCL : public CNeuronBaseOCL
{
protected:
//---
CNeuronConvOCL cF;
CNeuronBaseOCL cWv;
CNeuronBatchNormOCL cNormV;
CNeuronBaseOCL cQd;
CNeuronXCiTOCL cDQd;
//---
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL);
//---
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL);
public:
CNeuronFAQOCL(void) {};
~CNeuronFAQOCL(void) {};
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
uint window, uint window_out, uint heads,
uint units_count, uint input_units,
ENUM_OPTIMIZATION optimization_type,
uint batch);
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer);
//---
virtual int Type(void) const { return defNeuronFAQOCL; }
//--- methods for working with files
virtual bool Save(int const file_handle);
virtual bool Load(int const file_handle);
virtual CLayerDescription* GetLayerInfo(void);
virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau);
virtual void SetOpenCL(COpenCLMy *obj);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFAQOCL::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
uint window, uint window_out, uint heads,
uint units_count, uint input_units,
ENUM_OPTIMIZATION optimization_type, uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, window * units_count,
optimization_type, batch))
return false;
//---
activation = None;
//---
if(!cF.Init(0, 0, OpenCL, 3 * window, window, 8, fmax((int)input_units - 2, 1), optimization_type, batch))
return false;
cF.SetActivationFunction(None);
if(!cNormV.Init(8, 1, OpenCL, fmax((int)input_units - 2, 1) * 8, batch, optimization_type))
return false;
cNormV.SetActivationFunction(None);
if(!cWv.Init(units_count * window_out, 2, OpenCL, 8, optimization_type, batch))
return false;
cWv.SetActivationFunction(SIGMOID);
if(!cQd.Init(0, 4, OpenCL, units_count * window_out, optimization_type, batch))
return false;
cQd.SetActivationFunction(None);
if(!cDQd.Init(0, 5, OpenCL, window_out, 3, heads, units_count, 3, optimization_type, batch))
return false;
cDQd.SetActivationFunction(None);
//---
if(Output != cDQd.getOutput())
{
Output.BufferFree();
delete Output;
Output = cDQd.getOutput();
}
if(Gradient != cDQd.getGradient())
{
Gradient.BufferFree();
delete Gradient;
Gradient = cDQd.getGradient();
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFAQOCL::feedForward(CNeuronBaseOCL *NeuronOCL)
{
//---
if(!cF.FeedForward(NeuronOCL))
return false;
if(!cNormV.FeedForward(GetPointer(cF)))
return false;
if(!cWv.FeedForward(GetPointer(cNormV)))
return false;
if(!cQd.FeedForward(GetPointer(cWv)))
return false;
if(!cDQd.FeedForward(GetPointer(cQd)))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFAQOCL::calcInputGradients(CNeuronBaseOCL *prevLayer)
{
if(!cDQd.calcInputGradients(GetPointer(cQd)))
return false;
if(!cWv.calcHiddenGradients(GetPointer(cQd)))
return false;
if(!cNormV.calcHiddenGradients(GetPointer(cWv)))
return false;
if(!cNormV.calcInputGradients(GetPointer(cF)))
return false;
if(!cF.calcInputGradients(prevLayer))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFAQOCL::updateInputWeights(CNeuronBaseOCL *NeuronOCL)
{
if(!cDQd.UpdateInputWeights(GetPointer(cQd)))
return false;
if(!cQd.UpdateInputWeights(GetPointer(cWv)))
return false;
if(!cWv.UpdateInputWeights(GetPointer(cNormV)))
return false;
if(!cNormV.UpdateInputWeights(GetPointer(cF)))
return false;
if(!cF.UpdateInputWeights(NeuronOCL))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFAQOCL::Save(const int file_handle)
{
if(!CNeuronBaseOCL::Save(file_handle))
return false;
//---
if(!cF.Save(file_handle))
return false;
if(!cNormV.Save(file_handle))
return false;
if(!cWv.Save(file_handle))
return false;
if(!cQd.Save(file_handle))
return false;
if(!cDQd.Save(file_handle))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFAQOCL::Load(const int file_handle)
{
if(!CNeuronBaseOCL::Load(file_handle))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cF)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cNormV)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cWv)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cQd)))
return false;
if(!LoadInsideLayer(file_handle, GetPointer(cDQd)))
return false;
//---
if(Output != cDQd.getOutput())
{
if(!!Output)
{
Output.BufferFree();
delete Output;
}
Output = cDQd.getOutput();
}
if(Gradient != cDQd.getGradient())
{
if(!!Gradient)
{
Gradient.BufferFree();
delete Gradient;
}
Gradient = cDQd.getGradient();
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronFAQOCL::WeightsUpdate(CNeuronBaseOCL *source, float tau)
{
if(!CNeuronBaseOCL::WeightsUpdate(source, tau))
return false;
if(!cF.WeightsUpdate(source, tau))
return false;
if(!cNormV.WeightsUpdate(source, tau))
return false;
if(!cWv.WeightsUpdate(source, tau))
return false;
if(!cQd.WeightsUpdate(source, tau))
return false;
if(!cDQd.WeightsUpdate(source, tau))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CNeuronFAQOCL::SetOpenCL(COpenCLMy *obj)
{
CNeuronBaseOCL::SetOpenCL(obj);
cF.SetOpenCL(OpenCL);
cNormV.SetOpenCL(OpenCL);
cWv.SetOpenCL(OpenCL);
cQd.SetOpenCL(OpenCL);
cDQd.SetOpenCL(OpenCL);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CNeuronCrossAttention : public CNeuronMH2AttentionOCL
{
protected:
uint iWindow_K;
uint iUnits_K;
CNeuronBaseOCL *cContext;
//---
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL, CNeuronBaseOCL *Context);
virtual bool feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *Context);
virtual bool attentionOut(void);
//---
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL, CNeuronBaseOCL *Context);
virtual bool AttentionInsideGradients(void);
public:
CNeuronCrossAttention(void) {};
~CNeuronCrossAttention(void) { delete cContext; }
//---
virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
uint window, uint window_key, uint heads,
uint units_count, uint window_k, uint units_k,
ENUM_OPTIMIZATION optimization_type,
uint batch);
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer, CNeuronBaseOCL *Context);
virtual bool calcInputGradients(CNeuronBaseOCL *prevLayer, CBufferFloat *SecondInput, CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = None);
virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL, CBufferFloat *Context);
//---
virtual int Type(void) const { return defNeuronCrossAttenOCL; }
//--- methods for working with files
virtual bool Save(int const file_handle);
virtual bool Load(int const file_handle);
virtual CLayerDescription* GetLayerInfo(void);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
uint window, uint window_key, uint heads,
uint units_count, uint window_k, uint units_k,
ENUM_OPTIMIZATION optimization_type,
uint batch)
{
if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, window * units_count,
optimization_type, batch))
return false;
//---
iWindow = fmax(window, 1);
iWindowKey = fmax(window_key, 1);
iUnits = fmax(units_count, 1);
iWindow_K = fmax(window_k, 1);
iUnits_K = fmax(units_k, 1);
iHeads = fmax(heads, 1);
activation = None;
//---
if(!Q_Embedding.Init(0, 0, OpenCL, iWindow, iWindow, iWindowKey * iHeads, iUnits, optimization_type, batch))
return false;
Q_Embedding.SetActivationFunction(None);
if(!KV_Embedding.Init(0, 0, OpenCL, iWindow_K, iWindow_K, 2 * iWindowKey * iHeads, iUnits_K, optimization_type, batch))
return false;
KV_Embedding.SetActivationFunction(None);
//---
ScoreIndex = OpenCL.AddBuffer(sizeof(float) * iUnits * iUnits_K * iHeads, CL_MEM_READ_WRITE);
if(ScoreIndex == INVALID_HANDLE)
return false;
//---
if(!MHAttentionOut.Init(0, 0, OpenCL, iWindowKey * iUnits * iHeads, optimization_type, batch))
return false;
MHAttentionOut.SetActivationFunction(None);
if(!W0.Init(0, 0, OpenCL, iWindowKey * iHeads, iWindowKey * iHeads, iWindow, iUnits, optimization_type, batch))
return false;
W0.SetActivationFunction(None);
if(!AttentionOut.Init(0, 0, OpenCL, iWindow * iUnits, optimization_type, batch))
return false;
AttentionOut.SetActivationFunction(None);
if(!FF[0].Init(0, 0, OpenCL, iWindow, iWindow, 4 * iWindow, iUnits, optimization_type, batch))
return false;
if(!FF[1].Init(0, 0, OpenCL, 4 * iWindow, 4 * iWindow, iWindow, iUnits, optimization_type, batch))
return false;
for(int i = 0; i < 2; i++)
FF[i].SetActivationFunction(None);
//---
Gradient.BufferFree();
delete Gradient;
Gradient = FF[1].getGradient();
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::attentionOut(void)
{
if(!OpenCL)
return false;
//---
uint global_work_offset[3] = {0};
uint global_work_size[3] = {iUnits/*Q units*/, iUnits_K/*K units*/, iHeads};
uint local_work_size[3] = {1, iUnits_K, 1};
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_q, Q_Embedding.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_kv, KV_Embedding.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_score, ScoreIndex))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionOut, def_k_mh2ao_out, MHAttentionOut.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_MH2AttentionOut, def_k_mh2ao_dimension, (int)iWindowKey))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_MH2AttentionOut, 3, global_work_offset, global_work_size, local_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *Context)
{
if(!Context)
return false;
if(!cContext)
{
cContext = new CNeuronBaseOCL();
if(!cContext)
return false;
if(!cContext.Init(0, 0, OpenCL, Context.Total(), optimization, iBatch))
return false;
}
//---
if(Context.GetIndex() >= 0)
{
CBufferFloat *inside = cContext.getOutput();
if(inside.GetIndex() != Context.GetIndex())
inside.BufferSet(Context.GetIndex());
}
else
{
CBufferFloat *inside = cContext.getOutput();
inside.AssignArray(Context);
if(!inside.BufferWrite())
return false;
delete Context;
Context = inside;
}
//---
return feedForward(NeuronOCL, cContext);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::feedForward(CNeuronBaseOCL *NeuronOCL, CNeuronBaseOCL *Context)
{
//---
if(!Q_Embedding.FeedForward(NeuronOCL))
return false;
//---
if(!KV_Embedding.FeedForward(Context))
return false;
//---
if(!attentionOut())
return false;
//---
if(!W0.FeedForward(GetPointer(MHAttentionOut)))
return false;
//---
if(!SumAndNormilize(W0.getOutput(), NeuronOCL.getOutput(), AttentionOut.getOutput(), iWindow))
return false;
//---
if(!FF[0].FeedForward(GetPointer(AttentionOut)))
return false;
if(!FF[1].FeedForward(GetPointer(FF[0])))
return false;
//---
if(!SumAndNormilize(FF[1].getOutput(), AttentionOut.getOutput(), Output, iWindow))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::AttentionInsideGradients(void)
{
if(!OpenCL)
return false;
//---
uint global_work_offset[3] = {0};
uint global_work_size[3] = {iUnits, iWindowKey, iHeads};
ResetLastError();
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_q, Q_Embedding.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_qg, Q_Embedding.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_kv, KV_Embedding.getOutputIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_kvg, KV_Embedding.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_score, ScoreIndex))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgumentBuffer(def_k_MH2AttentionInsideGradients, def_k_mh2aig_outg, MHAttentionOut.getGradientIndex()))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.SetArgument(def_k_MH2AttentionInsideGradients, def_k_mh2aig_kunits, (int)iUnits_K))
{
printf("Error of set parameter kernel %s: %d; line %d", __FUNCTION__, GetLastError(), __LINE__);
return false;
}
if(!OpenCL.Execute(def_k_MH2AttentionInsideGradients, 3, global_work_offset, global_work_size))
{
printf("Error of execution kernel %s: %d", __FUNCTION__, GetLastError());
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::calcInputGradients(CNeuronBaseOCL *prevLayer, CBufferFloat *SecondInput, CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = None)
{
if(!SecondInput)
return false;
if(!cContext)
{
cContext = new CNeuronBaseOCL();
if(!cContext)
return false;
if(!cContext.Init(0, 0, OpenCL, SecondInput.Total(), optimization, iBatch))
return false;
}
cContext.SetActivationFunction(SecondActivation);
//---
if(SecondInput.GetIndex() >= 0)
{
CBufferFloat *inside = cContext.getOutput();
if(inside.GetIndex() != SecondInput.GetIndex())
inside.BufferSet(SecondInput.GetIndex());
}
else
{
CBufferFloat *inside = cContext.getOutput();
inside.AssignArray(SecondInput);
if(!inside.BufferWrite())
return false;
delete SecondInput;
SecondInput = inside;
}
//---
if(SecondGradient.GetIndex() >= 0)
{
CBufferFloat *inside = cContext.getGradient();
if(inside.GetIndex() != SecondGradient.GetIndex())
inside.BufferSet(SecondGradient.GetIndex());
}
else
{
CBufferFloat *inside = cContext.getGradient();
delete SecondGradient;
SecondGradient = inside;
}
//---
return calcInputGradients(prevLayer, cContext);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::calcInputGradients(CNeuronBaseOCL *prevLayer, CNeuronBaseOCL *Context)
{
if(!FF[1].calcInputGradients(GetPointer(FF[0])))
return false;
if(!FF[0].calcInputGradients(GetPointer(AttentionOut)))
return false;
if(!SumAndNormilize(FF[1].getGradient(), AttentionOut.getGradient(), W0.getGradient(), iWindow, false))
return false;
if(!W0.calcInputGradients(GetPointer(MHAttentionOut)))
return false;
if(!AttentionInsideGradients())
return false;
if(!KV_Embedding.calcInputGradients(Context))
return false;
if(!Q_Embedding.calcInputGradients(prevLayer))
return false;
if(!SumAndNormilize(prevLayer.getGradient(), W0.getGradient(), prevLayer.getGradient(), iWindow, false))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::updateInputWeights(CNeuronBaseOCL *NeuronOCL, CBufferFloat *Context)
{
if(!Context)
return false;
if(!cContext)
{
cContext = new CNeuronBaseOCL();
if(!cContext)
return false;
if(!cContext.Init(0, 0, OpenCL, Context.Total(), optimization, iBatch))
return false;
}
//---
if(Context.GetIndex() >= 0)
{
CBufferFloat *inside = cContext.getOutput();
if(inside.GetIndex() != Context.GetIndex())
inside.BufferSet(Context.GetIndex());
}
else
{
CBufferFloat *inside = cContext.getOutput();
inside.AssignArray(Context);
if(!inside.BufferWrite())
return false;
delete Context;
Context = inside;
}
//---
return updateInputWeights(NeuronOCL, cContext);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::updateInputWeights(CNeuronBaseOCL *NeuronOCL, CNeuronBaseOCL *Context)
{
if(!Q_Embedding.UpdateInputWeights(NeuronOCL))
return false;
if(!KV_Embedding.UpdateInputWeights(Context))
return false;
if(!W0.UpdateInputWeights(GetPointer(MHAttentionOut)))
return false;
if(!FF[0].UpdateInputWeights(GetPointer(AttentionOut)))
return false;
if(!FF[1].UpdateInputWeights(GetPointer(FF[0])))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::Save(const int file_handle)
{
if(!CNeuronMH2AttentionOCL::Save(file_handle))
return false;
if(FileWriteInteger(file_handle, (int)iWindow_K) < INT_VALUE)
return false;
if(FileWriteInteger(file_handle, (int)iUnits_K) < INT_VALUE)
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuronCrossAttention::Load(const int file_handle)
{
if(!CNeuronMH2AttentionOCL::Load(file_handle))
return false;
iWindow_K = (uint)FileReadInteger(file_handle);
iUnits_K = (uint)FileReadInteger(file_handle);
//---
if(!!OpenCL)
{
if(ScoreIndex >= 0)
OpenCL.BufferFree(ScoreIndex);
ScoreIndex = OpenCL.AddBuffer(sizeof(float) * iUnits * iUnits_K * iHeads, CL_MEM_READ_WRITE);
if(ScoreIndex == INVALID_HANDLE)
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+