機械学習

これらの方法は、機械学習で使用されます。

ニューラルネットワーク活性化関数は、重み付けされた入力の合計に応じて、ニューロンの出力値を決定します。活性化関数の選択は、ニューラルネットワークのパフォーマンスに大きな影響を与えます。異なるモデルパーツ(レイヤー)は、異なるアクティベーション関数を使用できます。

すべての既知の活性化関数に加えて、MQL5はそれらの導関数も提供します。関数導関数により、学習で受け取ったエラーに基づいてモデルパラメータを効率的に更新できます。

ニューラルネットワークは、損失関数が使用される学習のエラーを最小化するアルゴリズムを見つけることを目的としています。損失関数の値は、モデルによって予測された値が実際の値からどれだけずれているかを示します。問題に応じて異なる損失関数が使用されます。たとえば、平均二乗誤差(MSE)は回帰問題に使用され、バイナリクロスエントロピー(BCE) は二項分類に使用されます。

関数

アクション

Activation

活性化関数の値を計算し、渡されたベクトル/行列に書き込みます

Derivative

活性化関数の導関数値を計算し、渡されたベクトル/行列に書き込みます

Loss

損失関数値を計算し、渡されたベクトル/行列に書き込みます

RegressionMetric

指定されたデータ配列で構築された回帰直線からの偏差エラーとして回帰指標を計算します

ConfusionMatrix

混同行列を計算します。このメソッドは、予測値のベクトルに適用されます

ConfusionMatrixMultilabel

各ラベルの混同行列を計算します。このメソッドは、予測値のベクトルに適用されます

ClassificationMetric

分類指標を計算して、実際のデータと比較して予測データの品質を評価します。このメソッドは、予測値のベクトルに適用されます

ClassificationScore

分類指標を計算して、実際のデータと比較して予測データの品質を評価します

PrecisionRecall

値を計算して適合率-再現率曲線を構築します。ClassificationScoreと同様、このメソッドは真の値のベクトルに適用されます

ReceiverOperatingCharacteristic

値を計算して受信者操作特性(ROC)曲線を構築します。ClassificationScoreと同様、このメソッドは真の値のベクトルに適用されます

この例は、行列演算を使用したモデルのトレーニングを示しています。モデルは、関数 (a + b + c)^2 / (a^2 + b^2 + c^2) についてトレーニングされます。a、b、c が異なる列に含まれる初期データ行列を入力します。関数の結果は、モデルの出力で取得されます。

matrix weights1, weights2, weights3;               // 重みの行列
matrix output1, output2, result;                   // ニューラル層出力の行列
input int layer1 = 200;                           // 最初の隠れ層のサイズ
input int layer2 = 200;                           // 2番目の隠れ層のサイズ
input int Epochs = 20000;                         // トレーニングエポック数
input double lr = 3e-6;                           // 学習率
input ENUM_ACTIVATION_FUNCTION ac_func = AF_SWISH; // 活性化関数
//+------------------------------------------------------------------+
//| スクリプトを開始する関数                                                |
//+------------------------------------------------------------------+
void OnStart()
 {
//---
  int train = 1000;   // トレーニングサンプルサイズ
  int test = 10;       // テストサンプルサイズ
  matrix m_data, m_target;
//--- トレーニングサンプルを生成する
  if(!CreateData(m_data, m_target, train))  
    return;
//--- モデルをトレーニングする
  if(!Train(m_data, m_target, Epochs))      
    return;
//--- テストサンプルを生成する
  if(!CreateData(m_data, m_target, test))  
    return;
//--- モデルをテストする
  Test(m_data, m_target);                  
 }
//+------------------------------------------------------------------+
//| サンプル生成メソッド                                                   |
//+------------------------------------------------------------------+
bool CreateData(matrix &data, matrix &target, const int count)
 {
//--- 初期データと結果行列を初期化する
  if(!data.Init(count, 3) || !target.Init(count, 1))
    return false;
//--- 初期データ行列をランダムな値で埋める
  data.Random(-10, 10);                    
//--- トレーニングサンプルの目標値を計算する
  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 / X2, 0))
    return false;
//--- 結果を返す
  return true;
 }
//+------------------------------------------------------------------+
//| モデルトレーニングメソッド                                                 |
//+------------------------------------------------------------------+
bool Train(matrix &data, matrix &target, const int epochs = 10000)
 {
//--- モデルを作成する
  if(!CreateNet())
    return false;
//--- モデルをトレーニングする
  for(int ep = 0; ep < epochs; ep++)
    {
    //--- フィードフォワードパス
    if(!FeedForward(data))
        return false;
    PrintFormat("Epoch %d, loss %.5f", ep, result.Loss(target, LOSS_MSE));
    //--- 重み行列の逆伝播と更新
    if(!Backprop(data, target))
        return false;
    }
//--- 結果を返す
  return true;
 }
//+------------------------------------------------------------------+
//| モデル作成メソッド                                                     |
//+------------------------------------------------------------------+
bool CreateNet()
 {
//--- 重み行列を初期化する
  if(!weights1.Init(4, layer1) || !weights2.Init(layer1 + 1, layer2) || !weights3.Init(layer2 + 1, 1))
    return false;
//--- 重み行列にランダムな値を書き込む
  weights1.Random(-0.1, 0.1);
  weights2.Random(-0.1, 0.1);
  weights3.Random(-0.1, 0.1);
//--- 結果を返す
  return true;
 }
//+------------------------------------------------------------------+
//| フィードフォワードメソッド                                                 |
//+------------------------------------------------------------------+
bool FeedForward(matrix &data)
 {
//--- 初期データサイズを確認する
  if(data.Cols() != weights1.Rows() - 1)
    return false;
//--- 1番目のニューラル層を計算する
  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(temp, ac_func))
    return false;
//--- 2番目のニューラル層を計算する
  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(temp, ac_func))
    return false;
//--- 3番目のニューラル層を計算する
  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 &data, matrix &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(temp, ac_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(temp, ac_func))
    return false;
  if(!gradient.Resize(gradient.Rows(), gradient.Cols() - 1))
    return false;
  loss = gradient * temp;
//--- 勾配をより低い層に伝播する
  gradient = loss.MatMul(weights2.Transpose());
//--- 2番目の隠れ層の重み行列を更新する
  if(!output1.Activation(temp, ac_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(temp, ac_func))
    return false;
  if(!gradient.Resize(gradient.Rows(), gradient.Cols() - 1))
    return false;
  loss = gradient * temp;
//--- 1番目の隠れ層の重み行列を更新する
  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 &data, matrix &target)
 {
//--- テストデータのフィードフォワード
  if(!FeedForward(data))
    return false;
//--- モデルの計算結果と真の値を記録する
  PrintFormat("Test loss %.5f", result.Loss(target, LOSS_MSE));
  ulong total = data.Rows();
  for(ulong i = 0; i < total; i++)
    PrintFormat("(%.2f + %.2f + %.2f)^2 / (%.2f^2 + %.2f^2 + %.2f^2) =  Net %.2f, Target %.2f", data[i, 0], data[i, 1], data[i, 2],
                data[i, 0], data[i, 1], data[i, 2], result[i, 0], target[i, 0]);
//--- 結果を返す
  return true;
 }
//+------------------------------------------------------------------+