机器学习

这些方法用于机器学习。

神经网络激活函数根据输入的加权累加和来判定神经元的输出值。 激活函数的选择对神经网络性能有很大影响。 模型部件(层)不同可选用不同的激活函数。

除了所有已知的激活函数外,MQL5 还提供其衍生函数。 函数导数能够根据学习中接到的误差有效地更新模型参数。

神经网络旨在找到一种算法,将学习误差最小化,为此选用了损失函数。 损失函数的值表示模型预测值与实际值的偏差度。 根据问题采用不同的损失函数。 例如,均方误差(MSE) 用于回归问题;二元交叉熵(BCE)用于二元分类目的。

函数

动作

Activation

计算激活函数值,并将其写入传递的向量/矩阵

Derivative

计算激活函数导数值,并将其写入所传递的向量/矩阵

Loss

计算损失函数值,并将其写入所传递的向量/矩阵

LossGradient

计算亏损函数梯度的向量或矩阵

RegressionMetric

在指定数据数组上构建回归线,并计算回归量程作为偏差误差

ConfusionMatrix

计算混淆矩阵。该方法应用于预测值向量

ConfusionMatrixMultilabel

计算每个标签的混淆矩阵。该方法应用于预测值向量

ClassificationMetric

计算分类指标来评估预测数据相对于真实数据的质量。该方法适用于预测值的向量

ClassificationScore

计算分类指标来评估预测数据相对于真实数据的质量

PrecisionRecall

计算值以构建精确调用曲线。与ClassificationScore类似,此方法应用于真值向量

ReceiverOperatingCharacteristic

计算值以构建接收器工作特性(ROC)曲线。与ClassificationScore类似,此方法应用于真值向量

举例

此示例演示如何选用矩阵运算训练模型。 训练的模型针对函数 (a + b + c)^2 / (a^2 + b^2 + c^2)。 我们输入初始数据矩阵,其中 a、b 和 c 包含在不同的列中。 函数结果在模型输出端获得。

matrix weights1weights2weights3;               // 权重矩阵
matrix output1output2result;                   // 神经层输出矩阵
input int layer1 = 200;                            // 第一个隐藏层的大小
input int layer2 = 200;                            // 第二个隐藏层的大小
input int Epochs = 20000;                          // 训练世代的数量
input double lr = 3e-6;                            // 学习率
input ENUM_ACTIVATION_FUNCTION ac_func = AF_SWISH// 激活函数
//+------------------------------------------------------------------+
//| 脚本程序 start 函数                                                |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   int train = 1000;    // 训练样本大小
   int test = 10;       // 测试样本大小
   matrix m_datam_target;
//--- 生成训练样本
   if(!CreateData(m_datam_targettrain))  
      return;
//--- 训练模型
   if(!Train(m_datam_targetEpochs))      
      return;
//--- 生成测试样本
   if(!CreateData(m_datam_targettest))   
      return;
//--- 测试模型
   Test(m_datam_target);                   
  }
//+------------------------------------------------------------------+
//| 样本生成方法                                                       |
//+------------------------------------------------------------------+
bool CreateData(matrix &datamatrix &targetconst int count)
  {
//--- 初始化初始数据和结果矩阵
   if(!data.Init(count3) || !target.Init(count1))
      return false;
//--- 用随机值填充初始数据矩阵
   data.Random(-1010);                     
//--- 计算训练样本的目标值
   vector X1 = MathPow(data.Col(0) + data.Col(1) + data.Col(1), 2);
   vector X2 = MathPow(data.Col(0), 2) + MathPow(data.Col(1), 2) + MathPow(data.Col(2), 2);
   if(!target.Col(X1 / X20))
      return false;
//--- 返回结果
   return true;
  }
//+------------------------------------------------------------------+
//| 模型训练方法                                                       |
//+------------------------------------------------------------------+
bool Train(matrix &datamatrix &targetconst int epochs = 10000)
  {
//--- 创建模型
   if(!CreateNet())
      return false;
//--- 训练模型
   for(int ep = 0ep < epochsep++)
     {
      //--- 前向验算
      if(!FeedForward(data))
         return false;
      PrintFormat("Epoch %d, loss %.5f"epresult.Loss(targetLOSS_MSE));
      //--- 权重矩阵的反向传播与更新
      if(!Backprop(datatarget))
         return false;
     }
//--- 返回结果
   return true;
  }
//+------------------------------------------------------------------+
//| 模型创建方法                                                       |
//+------------------------------------------------------------------+
bool CreateNet()
  {
//--- 初始化权重矩阵
   if(!weights1.Init(4layer1) || !weights2.Init(layer1 + 1layer2) || !weights3.Init(layer2 + 11))
      return false;
//--- 用随机值填充权重矩阵
   weights1.Random(-0.10.1);
   weights2.Random(-0.10.1);
   weights3.Random(-0.10.1);
//--- 返回结果
   return true;
  }
//+------------------------------------------------------------------+
//| 前向验算方法                                                       |
//+------------------------------------------------------------------+
bool FeedForward(matrix &data)
  {
//--- 检查初始数据大小
   if(data.Cols() != weights1.Rows() - 1)
      return false;
//--- 计算第一个神经层
   matrix temp = data;
   if(!temp.Resize(temp.Rows(), weights1.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights1.Rows() - 1))
      return false;
   output1 = temp.MatMul(weights1);
//--- 计算激活函数
   if(!output1.Activation(tempac_func))
      return false;
//--- 计算第二个神经层
   if(!temp.Resize(temp.Rows(), weights2.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights2.Rows() - 1))
      return false;
   output2 = temp.MatMul(weights2);
//--- 计算激活函数
   if(!output2.Activation(tempac_func))
      return false;
//--- 计算第三个神经层
   if(!temp.Resize(temp.Rows(), weights3.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights3.Rows() - 1))
      return false;
   result = temp.MatMul(weights3);
//--- 返回结果
   return true;
  }
//+------------------------------------------------------------------+
//| 反向传播法                                                         |
//+------------------------------------------------------------------+
bool Backprop(matrix &datamatrix &target)
  {
//--- 检查目标值矩阵的大小
   if(target.Rows() != result.Rows() ||
      target.Cols() != result.Cols())
      return false;
//--- 检测计算值与目标的偏差
   matrix loss = (target - result) * 2;
//--- 将梯度传播到上一层
   matrix gradient = loss.MatMul(weights3.Transpose());
//--- 更新最后一层的权重矩阵
   matrix temp;
   if(!output2.Activation(tempac_func))
      return false;
   if(!temp.Resize(temp.Rows(), weights3.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights3.Rows() - 1))
      return false;
   weights3 = weights3 + temp.Transpose().MatMul(loss) * lr;
//--- 依据激活函数的导数调整误差梯度
   if(!output2.Derivative(tempac_func))
      return false;
   if(!gradient.Resize(gradient.Rows(), gradient.Cols() - 1))
      return false;
   loss = gradient * temp;
//--- 将梯度传播到更低一层
   gradient = loss.MatMul(weights2.Transpose());
//--- 更新第二隐藏层的权重矩阵
   if(!output1.Activation(tempac_func))
      return false;
   if(!temp.Resize(temp.Rows(), weights2.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights2.Rows() - 1))
      return false;
   weights2 = weights2 + temp.Transpose().MatMul(loss) * lr;
//--- 依据激活函数的导数调整误差梯度
   if(!output1.Derivative(tempac_func))
      return false;
   if(!gradient.Resize(gradient.Rows(), gradient.Cols() - 1))
      return false;
   loss = gradient * temp;
//--- 更新第一隐藏层的权重矩阵
   temp = data;
   if(!temp.Resize(temp.Rows(), weights1.Rows()) ||
      !temp.Col(vector::Ones(temp.Rows()), weights1.Rows() - 1))
      return false;
   weights1 = weights1 + temp.Transpose().MatMul(loss) * lr;
//--- 返回结果
   return true;
  }
//+------------------------------------------------------------------+
//| 模型测试方法                                                       |
//+------------------------------------------------------------------+
bool Test(matrix &datamatrix &target)
  {
//--- 前向测试数据
   if(!FeedForward(data))
      return false;
//--- 记录模型计算结果和真实值
   PrintFormat("Test loss %.5f"result.Loss(targetLOSS_MSE));
   ulong total = data.Rows();
   for(ulong i = 0i < totali++)
      PrintFormat("(%.2f + %.2f + %.2f)^2 / (%.2f^2 + %.2f^2 + %.2f^2) =  Net %.2f, Target %.2f"data[i0], data[i1], data[i2],
                  data[i0], data[i1], data[i2], result[i0], target[i0]);
//--- 返回结果
   return true;
  }
//+------------------------------------------------------------------+