English Русский 中文 Español Deutsch Português
preview
ニューラルネットワークが簡単に(第26部):強化学習

ニューラルネットワークが簡単に(第26部):強化学習

MetaTrader 5トレーディング | 29 11月 2022, 09:54
423 1
Dmitriy Gizlyk
Dmitriy Gizlyk

内容


はじめに

連載ではこれまで、教師あり学習と教師なし学習のアルゴリズムについて見てきました。この記事で、もう1つの機械学習の章が開かれます。強化学習です。これらのアルゴリズムは、試行錯誤による学習の実現に基づいており、生物の学習システムに例えることができます。この性質により、このようなアルゴリズムをある種の戦略の開発が必要な問題の解決に利用することができます。すべてのトレーダーは、取引を成功させるために特定の戦略に従っているので、明らかに、取引はこのような問題に起因することができます。そのため、このような技術の利用は、私たちの特定の分野にも役立つと思います。


1.強化学習の基礎

具体的なアルゴリズムについて学ぶ前に、強化学習の基本的な概念や考え方について学んでみましょう。まず、強化学習では、モデルを別物として扱わないことに注意してください。過程主体間の相互作用を扱います。過程全体の理解を深めるためには、過程参加者の1人として人物を紹介することが有効でしょう。私たちは、自分たちの行動をよく理解しています。この場合、モデルの挙動を理解することが容易になります。

つまり、私たちは常に変化する世界に生きているのです。その変化は、ある程度、私たちや私たちの行動にかかっていますが、もっと大きな意味で、私たちに依存するものではありません。なぜなら、他の何百万人もの人々がこの世界で生活し、ある行動をとっているからです。さらに、人に依存しない要素も多くあります。

同様に、強化学習では、環境エージェントが存在します。 これは私たちの世界を擬人化したものです。 エージェントの中には環境と相互作用するものもあります。エージェントは、この環境の中で生活する人に例えることができます。環境は常に変化しています。

私たちは常に周りを見渡し、触って物を評価し、音を聞いています。私たちは感覚を通して、刻々と世界を評価しているのです。心の中ではその状態を固定してしまいます。

同様に、環境はそのエージェントによって評価される状態を生成します。

私たちが世界観に則って行動するのと同様に、エージェントはその政策(戦略)に従って行動を取ります。

その衝撃によって、環境はある確率で変化します。各行動に対してエージェント環境からいくつかの報酬を受け取ります。報酬はプラスの場合もマイナスの場合もあります。報酬をもとに、エージェントは取った行動の有用性を評価することができます。

強化学習

なお、報酬政策は異なる場合があります。環境が各行動の後に報酬を返す場合、ワンステップのオプションがある場合がありますが、それ以外にも、一つひとつの行動を評価することが難しいあるいは不可能な仕事はたくさんあります。報酬はセッションの終了時にのみ付与されます。例えば、将棋を考えてみると、一手一手、局面が良くなったか悪くなったかで専門的な評価をしてみることができるのです。でも、一番の目標は対局に勝つことです。これは、過去の可能な限りの報告を網羅した報酬です。そうでなければ、このモデルは「対局するためだけに対局する」ことになり、決勝に進むことよりも最大限の報酬を得ることに執着してループする方法を見出すことになるでしょう。

同様に、マーケットで開いたポジションはプラスの場合もマイナスの場合もあります。しかし、取引の結果は、それが終了した後にしか評価できません。

このようなケースを見ると、報酬が1つの行動に依存しないことが多いことがわかりますが、それらは多くの連続した 行動.に依存します。

これにより、モデルの訓練目標が決定されます。私たちが取引で最大の利益を得るように努力するのと同じように、モデルもある有限の区間で最大の報酬を得るように訓練されます。試合でもセッションでも、あるいは期間だけでもです。

ここで、強化学習法を利用するための関連する2つの要件に注目してほしいと思います。

まず、対象となる過程は、いわゆるマルコフ決定過程の要件を満たしている必要があります。簡単に言えば、すべてのエージェントが取る行動は、現在の状態のみに依存します。過去に取られた行動または観察された 状態エージェント行動環境の変更に影響を与えなくなります。その影響はすべて、すでに現在の状態で考慮されています。

もちろん、現実にはそのような要件を満たす過程を見つけることは困難です。そして、それは間違いなく取引ではありません。トレーダーは取引をおこなう前に、ある時間間隔のデータを様々な角度から慎重に分析します。しかし、すべての事象の影響力は徐々に低下し、新たな事象によって補われます。したがって、現在の状態は、常にある時間間隔の事象を含んでいると言えます。また、何年前に発生した事象かを示すタイムスタンプを追加することも可能です。

第二の要件は、過程の有限性です。前述したように、モデルを訓練する目的は報酬を最大化することです。そして、等しい期間でのみ戦略の収益性を評価することができます。ある戦略が持続的にうまく機能すれば、より多くの時間をかけてより多くの利益を生み出すことができます。無限大の過程では、合計報酬は無限大になる可能性があるということです。

したがって、無限過程(取引もこれにあたる)の場合、この要件を満たすためには、訓練用サンプルのサイズをある時間枠に限定する必要があるのです。一方、訓練用サンプルは代表的なものでなければありません。少なくとも訓練期間終了後しばらくは通用する戦略が必要だからです。十分なモデル運用期間が長いほど良いです。

教師あり学習アルゴリズムの研究を始めたときにも、同じような話をしたことを思い出してください。教え方による違いについては、もう少し後でお話します。

ここで、実行された行動に適したモデル報酬政策を作成することの重要性について言及したいと思います。人事管理における報酬制度の適切な編成が重要であることは、皆さんもよくご存じでしょう。適切な報酬制度は、会社の従業員を刺激し、生産性と仕事の質を向上させます。同様に、適切な報酬制度は、モデルを訓練し、望ましい結果を得るための鍵となり得ます。これは、報酬が遅延するタスクでは特に重要です。

最終的な目標を達成するために取ったすべての行動に対して最終的な報酬を正しく配分することは難しいかもしれません。例えば、取引による損益をポジションの開始操作と終了操作にどのように分けるかです。まず思いつくのは、両方の操作を均等に割り振ることですが、残念ながら、必ずしもそうとは限りません。適切なタイミングでポジションを建てることで、価格が自分の方向へ動くようになります。エグジットの瞬間はどのように決めるのでしょうか。早めにポジションを決済すれば、潜在的な利益の一部を逃すことがあります。あるいは、ポジションを長く持ちすぎて、価格が自分に不利な方向に転がり始めたら決済することもあります。そのため、得られるはずの利益の一部を取りこぼすことになります。最悪の場合、損失で決済することもあります。この場合、一見良いポジションを建てる操作が、悪いポジション決済操作により、負の報酬を受けることになります。これは不公平だと思いませんか。さらに、この負の報酬のために、次回はこのエントリは適切でないと判断されて、さらに利益を逃すことになります。

もちろん、逆の状況もあり得ます。利益のないポジションを建てたとします。ここではその理由は議論していません。幸運なことに、しばらくすると価格が反転し、自分の方向に動き始めます。それで、なんとか利益でポジションを決済することができます。モデルは正の報酬を受け取り、そのようなエントリが成功したとみなし、そのようなパターンが発生した場合、再び取引を開始します。しかし、今回は運が悪かったのか、価格が逆転することはありません。

確かに、モデルは複数の案件から学習し、取引統計情報を収集・平均化します。しかし、報酬体系を誤ると、すべてが台無しになり、モデルの訓練を間違った方向に導いてしまいます。

したがって、教師あり学習モデルを構築する際には、報酬システムの開発に十分な注意を払う必要があります。


2.以前考察した手法との違い

強化学習法と、先に述べた教師あり・教師なし学習アルゴリズムの違いについて見てみましょう。すべての手法には、訓練するためのモデルと訓練用サンプルがあります。教師あり学習法を用いる場合、訓練サンプルには、「教師」が与えた初期状態と正解の組が含まれます。教師なし学習では、訓練用サンプルがあるだけで、アルゴリズムは個々の状態の内部の類似性と構造を調べて分離します。いずれの場合も訓練用サンプルは静的です。モデル操作では、モデルを変更することはありません。

強化学習の場合、通常の意味での訓練用サンプルがありません。あるのは現在の状態を生成する状態.です。訓練用サンプルとして、異なる環境状態をサンプリングすることができますが、環境とエージェントの関係はもう1つあります。システムの状態を評価した後、エージェントは何らかの行動を取ります。この行動は環境に影響を与え、環境を変化させる可能性があります。また、その行動に対して、環境は報酬として反応を返す必要があります。

環境から受け取った報酬は、教師あり学習法における「基準監督者の反応」と比較することができますが、ここには根本的な違いがあります。教師あり学習では、それぞれの状況に対して唯一の正解を用意し、そこから学習していきます。強化学習では、エージェントの行動に対する反応を得るだけです。報酬がどのように形成されるかはわかりません。しかも、それが最大なのか最小なのか、極値からどの程度離れているのかもわかりません。つまり、エージェントの行動とその推定値を知ることができるのです。しかし、その「参考」が何であったはずかはわかりません。これを知るには、ある状態から可能な限りの行動を取る必要があります。そして、この場合、1つの状態におけるすべての行動の評価を得ることになります。

ここで、次の期間に新しい環境状態になることを思い出してみましょう。この環境状態は、前のステップでエージェントが取った行動に依存します。

そして、分析対象期間全体の報酬総額が最大となるような努力もおこなっています。したがって、各状態の参照行動を得るためには、エージェントが実行するすべての可能な行動のために、環境のすべての可能な状態に対する多数のフルパスが必要です。

このような方法は、非常に長い時間と労力を必要とします。そこで、最適な戦略を見つけるために、後ほど少しお話するヒューリスティックを使うことにします。

まとめてみましょう。

教師あり学習 教師なし学習 強化学習
 基準値を近似するように訓練  データ構造を学習  最大報酬が得られるまで試行錯誤で訓練
 基準値が必要  基準値が不要  エージェントの行動に環境の応答が必要
 モデルが元データに影響を与えない  モデルが元データに影響を与えない  エージェントは環境に影響を与えることができる


3.クロスエントロピー法

強化学習アルゴリズムとの付き合いは、まずクロスエントロピーの手法から始めることをお勧めします。なお、本方式の使用には制限があります。これを正しく使うには、環境は有限の状態を持っていなければなりません。また、エージェントは有限の数の可能な行動に制限されています。もちろん、上記のマルコフ過程の要件や訓練期間の制限を遵守する必要があります。

この手法は、試行錯誤の思想と完全に一致しています。ご自分が、慣れない環境に身を置くと、新しい環境を探索するためにさまざまな行動を起こし始めることを思い出してください。これらの行動は、ランダムまたは類似の条件で得られた自分の経験に基づいています。

同様に、エージェントは、調査対象の環境において、最初から最後まで何度も通過します。それぞれの状態で、ある行動を取ります。行動は完全にランダムか、初期化時にエージェントに含まれる特定の政策によって指示されるかのいずれかです。このようなパスの数は、モデル構築者によって決定されるハイパーパラメータであり、異なることができます。

探索中の環境を通過するたびに、各状態、取った行動、各通過の総報酬を保存します。

すべてのパスのうち、総報酬で20%から50%のベストパスを選択し、その結果に基づいてエージェントの政策を更新します。政策の更新式は以下のとおりです。

政策更新

政策を更新した後、「環境」を通過することを繰り返します。最適なパッセージを選択します。エージェント政策を更新します。

希望する結果が得られるか、モデルの収益性の成長が止まるまで繰り返します。

3.1.MQL5を使用したPCAの実装

クロスエントロピー法のアルゴリズムは簡単そうに聞こえますが、MQL5ツールを使った実装はそれほど簡単ではありません。この手法では、環境の状態とエージェントの行動の可能性が有限であることを仮定しています。エージェントの行動は明確ですが、環境の状態の可能性の有限性には大きな疑問があります。

教師なし学習の問題に戻りましょう。特に、クラスタリング問題です。k平均法を検討する際、考えられるすべての状態を500クラスタに分けました。これは、可能な状態の数の有限性という問題に対する解として、納得のいくものだと思います。

これだけで、アルゴリズムのデモは十分です。ここで、エージェントの行動がシステムの状態に与える影響について、詳しくは触れないことにします。

クロスエントロピー法アルゴリズムを実装したMQL5コードは、EAファイル「crossenteopy.mq5」に添付しています。はじめに、必要なライブラリをインクルードします。今回は、クロスエントロピーの表形式版を実装するので、ニューラルネットワークライブラリは使用しません。本連載では次回以降、強化学習アルゴリズムでの利用を検討します。

#include "..\Unsupervised\K-means\kmeans.mqh"
#include <Trade\SymbolInfo.mqh>
#include <Indicators\Oscilators.mqh>

次に、外部変数を宣言します。これは、k平均を実演するEAで使用したものとほぼ同じです。市場の状況をグラフ化したパターンをクラスタリングする手法なので、当然といえば当然です。

input int                  StudyPeriod =  15;            //Study period, years
input uint                 HistoryBars =  20;            //Depth of history
input int                  Clusters    =  500;           //Clusters
ENUM_TIMEFRAMES            TimeFrame   =  PERIOD_CURRENT;
//---
input int                  Samples     =  100;
input int                  Percentile  =  70;
      int                  Actions     =  3;
//---
input group                "---- RSI ----"
input int                  RSIPeriod   =  14;            //Period
input ENUM_APPLIED_PRICE   RSIPrice    =  PRICE_CLOSE;   //Applied price
//---
input group                "---- CCI ----"
input int                  CCIPeriod   =  14;            //Period
input ENUM_APPLIED_PRICE   CCIPrice    =  PRICE_TYPICAL; //Applied price
//---
input group                "---- ATR ----"
input int                  ATRPeriod   =  14;            //Period
//---
input group                "---- MACD ----"
input int                  FastPeriod  =  12;            //Fast
input int                  SlowPeriod  =  26;            //Slow
input int                  SignalPeriod =  9;            //Signal
input ENUM_APPLIED_PRICE   MACDPrice   =  PRICE_CLOSE;   //Applied price

クロスエントロピー法を実現するために、3つの変数が追加されました。

  • Samples - 各政策更新の反復のためのパスの数
  • Percentile - 政策更新のために参照パスを選択するパーセンタイル
  • Actions - エージェントの可能な行動の数

システムの可能な状態の数は、k平均法で作成されるクラスタの数によって決定されます。

EA初期化メソッドでは、指標を扱うオブジェクトと、グラフパターンをクラスタリングするオブジェクトを初期化します。

int OnInit()
  {
//---
   Symb = new CSymbolInfo();
   if(CheckPointer(Symb) == POINTER_INVALID || !Symb.Name(_Symbol))
      return INIT_FAILED;
   Symb.Refresh();
//---
   RSI = new CiRSI();
   if(CheckPointer(RSI) == POINTER_INVALID || !RSI.Create(Symb.Name(), TimeFrame, RSIPeriod, RSIPrice))
      return INIT_FAILED;
//---
   CCI = new CiCCI();
   if(CheckPointer(CCI) == POINTER_INVALID || !CCI.Create(Symb.Name(), TimeFrame, CCIPeriod, CCIPrice))
      return INIT_FAILED;
//---
   ATR = new CiATR();
   if(CheckPointer(ATR) == POINTER_INVALID || !ATR.Create(Symb.Name(), TimeFrame, ATRPeriod))
      return INIT_FAILED;
//---
   MACD = new CiMACD();
   if(CheckPointer(MACD) == POINTER_INVALID || !MACD.Create(Symb.Name(), TimeFrame, FastPeriod, SlowPeriod, SignalPeriod, MACDPrice))
      return INIT_FAILED;
//---
   Kmeans = new CKmeans();
   if(CheckPointer(Kmeans) == POINTER_INVALID)
      return INIT_FAILED;
//---
   bool    bEventStudy = EventChartCustom(ChartID(), 1, 0, 0, "Init");
//---
   return(INIT_SUCCEEDED);
  }

EA の非初期化メソッドで、上記で作成したオブジェクトをすべて削除します。ご存知のように、初期化解除メソッドは、プログラムを閉じるときに呼び出されます。そのため、メモリクリーンアップを実装するのはいいことです。

void OnDeinit(const int reason)
  {
//---
   if(CheckPointer(Symb) != POINTER_INVALID)
      delete Symb;
//---
   if(CheckPointer(RSI) != POINTER_INVALID)
      delete RSI;
//---
   if(CheckPointer(CCI) != POINTER_INVALID)
      delete CCI;
//---
   if(CheckPointer(ATR) != POINTER_INVALID)
      delete ATR;
//---
   if(CheckPointer(MACD) != POINTER_INVALID)
      delete MACD;
//---
   if(CheckPointer(Kmeans) != POINTER_INVALID)
      delete Kmeans;
//---
  }

アルゴリズムの実装とモデルの訓練はTrain関数で提供されます。関数開始時の準備作業を実施します。OpenCLデバイスを操作するためのオブジェクトを作成するところから始まります。この技術を使って、k平均アルゴリズムを実装する予定です。実装方法については、「ニューラルネットワークが簡単に(第15回):MQL5によるデータクラスタリング」稿をご覧ください。

void Train(void)
  {
   COpenCLMy *opencl = OpenCLCreate(cl_unsupervised);
   if(CheckPointer(opencl) == POINTER_INVALID)
     {
      ExpertRemove();
      return;
     }
   if(!Kmeans.SetOpenCL(opencl))
     {
      delete opencl;
      ExpertRemove();
      return;
     }

次に、履歴データの更新をおこないます。

   MqlDateTime start_time;
   TimeCurrent(start_time);
   start_time.year -= StudyPeriod;
   if(start_time.year <= 0)
      start_time.year = 1900;
   datetime st_time = StructToTime(start_time);
//---
   int bars = CopyRates(Symb.Name(), TimeFrame, st_time, TimeCurrent(), Rates);
   if(!RSI.BufferResize(bars) || !CCI.BufferResize(bars) || !ATR.BufferResize(bars) || !MACD.BufferResize(bars))
     {
      ExpertRemove();
      return;
     }
   if(!ArraySetAsSeries(Rates, true))
     {
      ExpertRemove();
      return;
     }
//---
   RSI.Refresh();
   CCI.Refresh();
   ATR.Refresh();
   MACD.Refresh();

次に、事前訓練したk平均法モデルを読み込みます。各ステップで結果を制御することを忘れないでください。

   int handl = FileOpen(StringFormat("kmeans_%d.net", Clusters), FILE_READ | FILE_BIN);
   if(handl == INVALID_HANDLE)
     {
      ExpertRemove();
      return;
     }
   if(FileReadInteger(handl) != Kmeans.Type())
     {
      ExpertRemove();
      return;
     }
   bool result = Kmeans.Load(handl);
   FileClose(handl);
   if(!result)
     {
      ExpertRemove();
      return;
     }

上記の操作が正常に終了したら、履歴データが十分にあるかどうかを確認します。

   int total = bars - (int)HistoryBars - 480;
   double data[], fractals[];
   if(ArrayResize(data, total * 8 * HistoryBars) <= 0 ||
      ArrayResize(fractals, total * 3) <= 0)
     {
      ExpertRemove();
      return;
     }

次に、クラスタリングする履歴サンプルを作成します。

   for(int i = 0; (i < total && !IsStopped()); i++)
     {
      Comment(StringFormat("Create data: %d of %d", i, total));
      for(int b = 0; b < (int)HistoryBars; b++)
        {
         int bar = i + b + 480;
         int shift = (i * (int)HistoryBars + b) * 8;
         double open = Rates[bar]
                       .open;
         data[shift] = open - Rates[bar].low;
         data[shift + 1] = Rates[bar].high - open;
         data[shift + 2] = Rates[bar].close - open;
         data[shift + 3] = RSI.GetData(MAIN_LINE, bar);
         data[shift + 4] = CCI.GetData(MAIN_LINE, bar);
         data[shift + 5] = ATR.GetData(MAIN_LINE, bar);
         data[shift + 6] = MACD.GetData(MAIN_LINE, bar);
         data[shift + 7] = MACD.GetData(SIGNAL_LINE, bar);
        }
      int shift = i * 3;
      int bar = i + 480;
      fractals[shift] = (int)(Rates[bar - 1].high <= Rates[bar].high && Rates[bar + 1].high < Rates[bar].high);
      fractals[shift + 1] = (int)(Rates[bar - 1].low >= Rates[bar].low && Rates[bar + 1].low > Rates[bar].low);
      fractals[shift + 2] = (int)((fractals[shift] + fractals[shift]) == 0);
     }
   if(IsStopped())
     {
      ExpertRemove();
      return;
     }
   CBufferFloat *Data = new CBufferFloat();
   if(CheckPointer(Data) == POINTER_INVALID ||
      !Data.AssignArray(data))
      return;
   CBufferFloat *Fractals = new CBufferFloat();
   if(CheckPointer(Fractals) == POINTER_INVALID ||
      !Fractals.AssignArray(fractals))
      return;

そして、クラスタリングを実行します。

//---
   ResetLastError();
   Data = Kmeans.SoftMax(Data);

次に、クロスエントロピーの手法を使った作業に進みます。まず、必要な変数を用意します。ここでは、システム状態行列statesと実行された行動の行列akushonnをゼロ値で埋めます。行列データの行がパスに対応することになります。その列は、対応するパスの各ステップを表しています。このように statesは適切なパスの各ステップでの状態を格納します。actions行列は、関連するステップで実行された行動を格納します。

CumRewardsベクトルは、各パスの報酬を累積するために使用されます。

エージェントのpolicyは、各行動に対して等しい確率で初期化されます。

   vector   env = vector::Zeros(Data.Total() / Clusters);
   vector   target = vector::Zeros(env.Size());
   matrix   states = matrix::Zeros(Samples, env.Size());
   matrix   actions = matrix::Zeros(Samples, env.Size());
   vector   CumRewards = vector::Zeros(Samples);
   double   average = 1.0 / Actions;
   matrix   policy = matrix::Full(Clusters, Actions, average);

なお、上記の例は、あくまでも技術のデモであり、かなり「非現実的」なものであることをご了承ください。そこで、考えられるシステムの状態数の増加を避けるため、エージェントの行動がその後の状態を変化させる影響を除外しました。これにより、解析期間中の全システム状態のシーケンスを envベクトルに変換することができました。教師あり学習問題で得られたターゲットデータを用いることで、ターゲット値のベクトルtarget.を作成できます。実用的な問題を解くときには、そのような機会はないでしょう。そのため、このデータを得るためには、毎回環境を参照する必要があります。

   for(ulong state = 0; state < env.Size(); state++)
     {
      ulong shift = state * Clusters;
      env[state] = (double)(Data.Maximum((int)shift, Clusters) - shift);
      shift = state * Actions;
      target[state] = Fractals.Maximum((int)shift, Actions) - shift;
     }

これで準備作業は終了です。それでは、クロスエントロピー法アルゴリズムの直接実装に進みましょう。以上のように、アルゴリズムはループ方式で実装されることになります。

外側のループは、エージェントの政策の更新に関連する反復処理の回数をカウントします。このループでは、まず累積報酬ベクトルをリセットします。

   for(int iter = 0; iter < 200; iter++)
     {
      CumRewards.Fill(0);

そして、解析した過程を通過するループを入れ子で作成します。

      for(int sampl = 0; sampl < Samples; sampl++)
        {

各パスには、過程のすべてのステップを通過するネストされたループも含まれています。各ステップで、現在の状態に対して最も可能性の高い行動を選択します。この状態が新しい場合、新しい行動をランダムに選択します。その後、選択した行動を環境に渡すと、報酬を受け取ることができます。

今回の実装では、正しい行動(基準に対応)には報酬を1、それ以外には-1を割り当てました。

現在の状態と行動を保存し、次のステップ(ループの新しい反復)に進みます。

         for(ulong state = 0; state < env.Size(); state++)
           {
            ulong a = policy.Row((int)env[state]).ArgMax();
            if(policy[(int)env[state], a] <= average)
               a = (int)(MathRand() / 32768.0 * Actions);
            if(a == target[state])
               CumRewards[sampl] += 1;
            else
               CumRewards[sampl] -= 1;
            actions[sampl, state] = (double)a;
            states[sampl,state]=env[state];
           }

すべてのパスを完了した後、参照パスのパス報酬レベルを決定します。

      double percentile = CumRewards.Percentile(Percentile);

その後エージェントの政策を更新します。そのためには、実行されたすべてのパスをループするシステムを実装し、その中から参照するものだけを選択します。

参照用パスでは、完了したすべてのステップをループし、訪問した各状態で、対応する完了した行動のカウンターを1ずつ増やします。参照用パスだけを確認するため、取られた行動は正しいと考えています。なぜなら、それが最高の報酬をもたらすからです。

      policy.Fill(0);
      for(int sampl = 0; sampl < Samples; sampl++)
        {
         if(CumRewards[sampl] < percentile)
            continue;
         for(int state = 0; state < env.Size(); state++)
            policy[(int)states[sampl, state], (int)actions[sampl, state]] += 1;
        }

基準戦略の行動をカウントした後,各状態の行動をとる確率の合計が1になるように,方針を正規化します。これをおこなうには、Policy行列政策.のすべての行をループします。この行列の各行がシステムのある状態に対応し、列が実行された行動に対応します。ある状態に対して行動が保存されていない場合、そのような状態に対してすべての行動が等しく可能であると考えます。

      for(int row = 0; row < Clusters; row++)
        {
         vector temp = policy.Row(row);
         double sum = temp.Sum();
         if(sum > 0)
            temp = temp / sum;
         else
            temp.Fill(average);
         if(!policy.Row(temp, row))
            break;
        }

ループの繰り返しの後、エージェントの更新された制作を得ます。

参考までに、受け取った最大報酬を出力し、解析中の環境を通じて新たな反復に進みます。

      PrintFormat("Iteration %d, Max reward %.0f", iter, CumRewards.Max());
     }

モデルの訓練が終了したら、訓練用サンプルのオブジェクトを削除し、プロシージャを呼び出してEA作業を終了させます。

   if(CheckPointer(Data) == POINTER_DYNAMIC)
      delete Data;
   if(CheckPointer(Fractals) == POINTER_DYNAMIC)
      delete Fractals;
   if(CheckPointer(opencl) == POINTER_DYNAMIC)
      delete opencl;
   Comment("");
//---
   ExpertRemove();
  }

EAの全コードと全ライブラリを添付ファイルでご確認ください。


結論

この記事によって、機械学習の勉強に新たな一歩を踏み出すことができました。強化学習です。この方法は、生物が学習する方法に最も近い精神を持っています。試行錯誤の原理で構成されています。この方法は、ラベルなしデータに基づいて、モデルの動作に対する論理的な戦略を構築することができるので、むしろ有望です。ただし、そのためにはモデルの報酬体系を徹底的に準備する必要があります。

今回は、強化学習アルゴリズムの一つであるクロスエントロピー法について考察しました。この手法はわかりやすいのですが、いくつかの制約があります。しかし、かなり簡略化した実装例で、この方法の大きな可能性を示しています。

次回は、強化学習の勉強を続けながら、他のアルゴリズムにも触れていく予定です。中には、ニューラルネットワークを使ってエージェントを訓練するものもあります。

参考文献リスト

  1. ニューラルネットワークが簡単に(第14部):データクラスタリング
  2. ニューラルネットワークが簡単に(第15部):MQL5によるデータクラスタリング
  3. ニューラルネットワークが簡単に(第16部):クラスタリングの実用化

記事で使用されているプログラム

# 名前 タイプ 詳細
1 クロスエンテオピー.mq5 EA モデルを訓練するEA 
2 kmeans.mqh  クラスライブラリ k平均法を実装するためのライブラリ 
3 unsupervised.cl コードベース
k平均法を実装するためのOpenCLプログラムコードライブラリ


MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/11344

添付されたファイル |
MQL5.zip (85.7 KB)
最後のコメント | ディスカッションに移動 (1)
WAN FX
WAN FX | 10 3月 2024 において 08:12
Thank you for the interesting article. I downloaded the ZIP file and compiled it, but it seems that CBufferFloat is not defined. In which file can I find this class? Thank you in advance.
VIDYAによる取引システムの設計方法を学ぶ VIDYAによる取引システムの設計方法を学ぶ
最も人気のあるテクニカル指標によって取引システムを設計する方法を学ぶ連載の新しい記事へようこそ。この新しい記事では、新しいテクニカルツールについて学び、VIDYA(Variable Index Dynamic Average、可変インデックス動的平均)テクニカル指標によって取引システムを設計する方法を学びます。
データサイエンスと機械学習—ニューラルネットワーク(第02回):フィードフォワードNNアーキテクチャの設計 データサイエンスと機械学習—ニューラルネットワーク(第02回):フィードフォワードNNアーキテクチャの設計
フィードフォワード(予測制御)ニューラルネットワークについて説明する前に、少し説明しておくことがあって、設計もその1つです。入力、隠れ層の数、および各ネットワークのノードに対する柔軟なニューラルネットワークを構築および設計する方法を見てみましょう。
DIYテクニカル指標 DIYテクニカル指標
この記事では、独自のテクニカル指標を作成できるアルゴリズムについて検討します。非常に単純な初期仮定で、非常に複雑で興味深い結果を得る方法を学びます。
市場の数学:利益、損失、コスト 市場の数学:利益、損失、コスト
この記事では、手数料やスワップなど、あらゆる取引の総損益を計算する方法を紹介します。最も正確な数学的モデルを提供し、それを使ってコードを書き、標準と比較するつもりです。そのほか、利益を計算するMQL5のメイン関数の内部にも入り込み、仕様から必要な値をすべて突き詰めてみます。