English Русский Español Deutsch Português
preview
競争学習アルゴリズム(CLA)

競争学習アルゴリズム(CLA)

MetaTrader 5トレーディング |
17 0
Andrey Dik
Andrey Dik

内容

  1. はじめに
  2. アルゴリズムの実装
  3. テスト結果


はじめに

過去数十年にわたり、アリのコロニーや粒子群から、ハイイロオオカミやクジラに至るまで、多くの生物着想型アルゴリズムが提案されてきました。しかし、複雑な社会的相互作用を持つ人間社会もまた、効果的な最適化手法のための豊かな着想源となり得ます。この考え方が、競争学習アルゴリズム(CLA)の基盤となっています。

CLAでは、教育プロセスをメタファーとして利用し、解の集団をクラスに編成された生徒として表現します。このアルゴリズムは、3種類の学習を巧みにモデル化します。それは、クラス内で最も優れた生徒から学ぶこと、個人的な経験から学ぶこと、そしてクラス間の相互作用を通じて学ぶことです。このアプローチにより、探索空間を広く調べることと、発見された優れた解を活用することとのバランスが取られます。これは、効果的な最適化において極めて重要な要素です。

本記事では、CLAの基本原理、数学的基礎、実装上の特徴について詳しく検討します。また、標準的なテスト関数を用いて、他の代表的なメタヒューリスティック手法との性能比較もおこないます。


アルゴリズムの実装

競争学習アルゴリズムは、学校における教育プロセスをメタファーとして構築されています。このメタファーでは、生徒が最適化問題における可能な解を表し、クラスは生徒のグループ、教師は各クラスで最も優れた生徒、知識は探索空間における座標に対応し、成績は適応度関数の値によって決定されます。

アルゴリズムは初期化から始まります。これは、学校の新学期の始まりに相当します。たとえば198人の生徒からなる集団を作成し、それを22人ずつ9クラスに分割します。各生徒には、探索空間内の座標として表される初期の「知識」がランダムに割り当てられます。

学習プロセスは反復的におこなわれ、各反復において生徒は3つの異なる方法で学習します。1つ目は教師主導の学習です。各生徒はクラスの教師役(そのクラスで最良の生徒)から学びます。クラスの成績が悪いほど学習プロセスは活発になりますが、時間の経過とともに全員の学習強度は低下します。2つ目は個人学習です。これは4回目の反復以降にのみ開始されます。このモードでは、生徒は過去4回の「授業」における自身の最良の結果を思い出し、自分自身の最良の位置へ戻ろうとします。3つ目は他のクラスからの学習で、これも4回目の反復以降に開始されます。50%の確率で、生徒はすべてのクラスから計算された平均教師から学習します。これにより、局所最適解に陥ることを回避できます。

各学習サイクルの後には、進捗が評価されます。各クラスで最も優れた生徒が特定され、教師となります。また、すべての生徒の成績を考慮してクラス全体の評価が計算され、これまでに見つかった全体最良の解が更新されます。

アルゴリズムでは、5つの主要なパラメータを使用します。

  • popSize:生徒の総数
  • numClasses:クラス数
  • beta:クラス全体の評価に対する、クラス内の全生徒の影響度
  • gamma:他のクラスから学習する確率
  • deltaIter:個人的な経験とクラス間の相互作用を利用した拡張学習を開始する反復回数

アルゴリズムには、いくつかのスマートなメカニズムが実装されています。適応型の学習係数によって、成績の低いクラスほど集中的に学習し、時間の経過とともに学習速度が徐々に低下します。これは現実の教育プロセスと同様です。探索と活用のバランスは、初期段階で積極的に探索し、その後、発見された最良の解に焦点を移すことで実現されます。また、記憶メカニズムによって各生徒の履歴を記憶し、必要に応じて過去の良好な解へ戻ることができます。

数学的には、生徒の知識の更新は、現在の知識に3つの要素を加えたものとして表すことができます。それは、クラスの教師からの指導、個人的な過去の経験、そしてすべてのクラスの平均教師から得られる知識です。この式によって、リーダーに従うこと、個人的な経験を利用すること、新しい領域を探索することのバランスが取られます。

最終的に、アルゴリズムの有効性はいくつかの要因によって決まります。複数のクラスが探索空間内の異なる方向を探索することで、多様性が確保されます。教師の座をめぐる生徒間の競争が、より優れた解の発見を促します。クラス間で知識を共有する協調によって、早期収束を防ぎます。適応性によって成績の低いクラスに追加の支援が与えられ、記憶メカニズムによって良好な解に関する情報が保存されます。

CLA_L

図1:アルゴリズムの動作

アルゴリズムの動作を示した図では、初期化、学習フェーズ、評価と更新という3つの主要なステップが説明されています。それでは、CLA_Lアルゴリズムの疑似コードを書き始めましょう。

事前に必要なもの
- 198名の生徒(私たちの解)
- 9クラス(生徒グループ)
- パラメータβ = 0.9(クラス内の全生徒がどの程度重要か)
- パラメータγ = 0.5(他のクラスから学習する確率)
- 4回目の反復以降に追加の学習方式を導入
- 解の品質を評価する関数

開始

1. 学校を作る
   - 198人の生徒を9クラスに分配する(各クラス22人)。
   - 各生徒に探索空間内のランダムな初期位置を与える。
   - 各クラスで最も優れた生徒を選び、その生徒を教師とする。
- 各生徒の履歴を記録するログを作成する。

2. 学習プロセス(反復プロセス)
   
   ステップ1:学習強度を決定する
- 各クラスについて、生徒がどの程度積極的に学習する必要があるかを計算する。
- 成績の低いクラスほど、より集中的に学習する。
- 時間の経過とともに、全員の学習強度を低下させる(現実の教育と同様)。
   
   ステップ2:「平均教師」を見つける
- すべての教師の位置を取得する。
- その平均値を計算する。
   - これを学校全体の知識水準の目安とする。
   
   ステップ3:各生徒が学習する
   
   各生徒について:
   
   a) 常に自分の教師から学ぶ
      - クラスの教師がどこにいるかを確認する。
      - その方向へ移動する。
      - 移動速度はクラスの学習係数によって決まる。
   
   b) 4回目の反復以降は、経験を思い出す
      - ログを確認する。過去4回の授業で、自分が最も良かった位置はどこだったかを確認する。
      - ある程度のランダムな力を加えて、その位置へ戻る。
      - これによって、良好な解を保持することができる。
   
   c) 4回目の反復以降は、他のクラスから学ぶ
      - コインを投げる(50%の確率)。
- 裏が出た場合は、「平均教師」を参照する。
      - その方向へ少し移動する。
      - これによって、クラス間で経験を共有する。
   
   ステップ4:すべての生徒を評価する
   - 各生徒に適応度を与える。
   - 位置が優れているほど、高い評価を与える。
   
   ステップ5:学校の階層を更新する
   
   各クラスについて:
   - 新たに最も優れた生徒を見つけ、その生徒を教師とする。
   - クラス全体のレベルを計算する。
     * 教師の適応度を取得する。
     * すべての生徒の平均成績を加える(βを乗算)。
   - クラスの順位を決定する
     * 最も優れたクラスには低い順位(1、2、3……)を与える。
     * 最も成績の悪いクラスには高い順位を与える。
   
   ステップ6:最良の解を記憶する
   - いずれかの教師が現在の記録値より優れている場合、
   - それを新しい記録として保存する
   
   ステップ7:履歴を保存する
   - すべての生徒の現在位置を保存する。
   - これは個人学習に必要となる。

3.終了
   - 発見された最良の解を返す。
   - その適応度も返す。

それでは、アルゴリズムのコードを書き始めましょう。C_AO_CLA_lクラスは親クラスC_AOを継承し、競争学習の概念に基づくアルゴリズムを実装しています。このクラスには、ユーザーが設定可能ないくつかのパラメータが含まれています。

  • popSize:集団サイズ(「エージェント」または「生徒」の数)
  • numClasses:エージェントを分割するクラスの数
  • beta:学習速度または適応速度に影響を与えるパラメータ
  • gamma:学習プロセスに関連するもう1つのパラメータ
  • deltaIter:アルゴリズムの特定の段階を開始する反復回数

コンストラクタでは主要なパラメータを初期化し、アルゴリズムの名前と説明を設定し、変数のデフォルト値を指定します。また、アルゴリズムのパラメータに関する情報を格納するために使用されるparams配列のサイズも設定します。

メソッド

  • SetParams():params配列の値を使用して、クラス内部の変数(アルゴリズムのパラメータ)を更新します。これにより、外部から設定したパラメータを変更できます。
  • Init ():アルゴリズムを初期化します。パラメータの境界と変更ステップを定義するための値を受け取ります。
  • Moving ():エージェントを「移動」させるための主要なメソッドです。アルゴリズムの反復処理と各ステップを実行します。
  • Revision ():解の修正または改善に関連するメソッドです。
  • Injection ():新しい知識やデータをエージェントに挿入するためのメソッドです。
クラスフィールド
  • numClasses、beta、gamma、deltaIter:アルゴリズムのパラメータ。
  • currentIter、studentsPerClass、totalIters:アルゴリズムの処理フローを制御する内部変数。
  • teachers []:各クラスの「教師」を表すS_AO_Agent構造体の配列です。各教師はアンカーポイントとして機能します。
  • classRanks []:クラスの成績を表すクラス順位。
  • classTotalCosts [] :各クラスの合計コスト、つまり「成績」。
  • CL []:教師の平均知識を計算するための一時配列。
  • UpdateTeachersAndCosts ():教師とそのコストに関する情報を更新する内部メソッド。
  • UpdateClassRanks():クラスの順位を更新する内部メソッド。
  • UpdateStudentsKnowledge():生徒の知識、つまりエージェントのパラメータを更新する内部メソッド。
//————————————————————————————————————————————————————————————————————
class C_AO_CLA_l : public C_AO
{
  public: //----------------------------------------------------------
  ~C_AO_CLA_l () { }
  C_AO_CLA_l ()
  {
    ao_name = "CLA_L";
    ao_desc = "Competitive Learning Algorithm";
    ao_link = "https://www.mql5.com/ja/articles/18857";

    popSize        = 198;
    numClasses     = 3;
    beta           = 0.3;
    gamma          = 0.8;
    deltaIter      = 2;

    ArrayResize (params, 5);

    params [0].name = "popSize";     params [0].val = popSize;
    params [1].name = "numClasses";  params [1].val = numClasses;
    params [2].name = "beta";        params [2].val = beta;
    params [3].name = "gamma";       params [3].val = gamma;
    params [4].name = "deltaIter";   params [4].val = deltaIter;
  }

  void SetParams ()
  {
    popSize    = (int)params [0].val;
    numClasses = (int)params [1].val;
    beta       = params      [2].val;
    gamma      = params      [3].val;
    deltaIter  = (int)params [4].val;
  }

  bool Init (const double &rangeMinP  [],
             const double &rangeMaxP  [],
             const double &rangeStepP [],
             const int     epochsP = 0);

  void Moving   ();
  void Revision ();
  void Injection (const int popPos, const int coordPos, const double value) { }

  //------------------------------------------------------------------
  int    numClasses;
  double beta;
  double gamma;
  int    deltaIter;

  private: //---------------------------------------------------------
  int    currentIter;
  int    studentsPerClass;
  int    totalIters;

  // Structures for classes
  S_AO_Agent teachers        [];
  double     classRanks      [];
  double     classTotalCosts [];

  // Temporary array
  double     CL [];             // Average knowledge of teachers

  // Auxiliary methods
  void   UpdateTeachersAndCosts  ();
  void   UpdateClassRanks        ();
  void   UpdateStudentsKnowledge ();
};
//————————————————————————————————————————————————————————————————————

C_AO_CLA_lクラスのInit()メソッドは、アルゴリズムの動作開始前に初期化をおこないます。処理は複数の段階に分かれています。 標準初期化:StandardInit()メソッドを呼び出し、最適化アルゴリズムの標準的な初期化を実行します。このメソッドには、rangeMinP、rangeMaxP、rangeStepPの各ステップパラメータが渡されます。標準初期化に失敗した場合、Init()メソッドはfalseを返します。

アルゴリズムパラメータの初期化:現在の反復回数カウンタを「0」にリセットし、epochsP引数で渡された値を使用して、アルゴリズムが実行する総反復回数を設定します。次に、クラス数に対する個体数の除算によって、各クラスに所属する「生徒」(エージェント)の人数を計算します。その後、各クラスに少なくとも1人の生徒が存在することを確認します。続いて、forループによって母集団内の各エージェントを初期化します。各エージェントに対して、Init()メソッドが呼び出され、その座標配列が初期化されます。

次に、forループによって各クラスの「教師」を初期化し、各クラスのランクを1.0に設定するとともに、各クラスの初期「コスト」を負の最大値に設定します。これにより、その後、より優れた解が見つかるようになります。すべての初期化処理が正常に完了すると、メソッドはtrueを返します。

//————————————————————————————————————————————————————————————————————
bool C_AO_CLA_l::Init (const double &rangeMinP  [],
                       const double &rangeMaxP  [],
                       const double &rangeStepP [],
                       const int epochsP = 0)
{
  if (!StandardInit (rangeMinP, rangeMaxP, rangeStepP)) return false;

  //------------------------------------------------------------------
  currentIter = 0;
  totalIters = epochsP;
  studentsPerClass = popSize / numClasses;

  if (studentsPerClass < 1)
  {
    Print ("Error: Too few students per class");
    return false;
  }

  // Adjust the population size
  //spopSize = studentsPerClass * numClasses;
  ArrayResize (a, popSize);
  for (int i = 0; i < popSize; i++) a [i].Init (coords);

  // Initialize class structures
  ArrayResize (teachers, numClasses);
  ArrayResize (classRanks, numClasses);
  ArrayResize (classTotalCosts, numClasses);

  for (int i = 0; i < numClasses; i++)
  {
    teachers        [i].Init (coords);
    classRanks      [i] = 1.0;
    classTotalCosts [i] = -DBL_MAX;
  }

  // Temporary array
  ArrayResize (CL, coords);

  return true;
}
//————————————————————————————————————————————————————————————————————

C_AO_CLA_lクラスのMoving()メソッドは、最適化アルゴリズムのメインループにおける1回の反復を実行します。まず、初回の反復であるかどうかを確認します。初回の反復(revisionがfalse)の場合、指定された範囲内で母集団内のすべてのエージェントの位置をランダムな値で初期化します。集団内のすべてのエージェントを順番に処理し、各エージェントについて、そのすべての座標を順番に処理します。

各座標について、u.RNDfromCI()メソッドを使用して、rangeMin[c]からrangeMax[c]までの範囲でランダム値valを生成します。このメソッドは乱数を生成するために使用されます。生成したvalを、i番目のエージェントのa[i].c[c]座標に設定します。ただし、その前に値が許容範囲内に収まり、指定されたrangeStep[c]の刻みに一致するよう調整します。この処理には、値のチェックと調整をおこなうu.SeInDiSp()メソッドを使用します。

集団の初期化が完了すると、初期化が実行済みであることを示すフラグを設定します。初回の反復でない場合は、現在の反復回数カウンタをインクリメントします。続いて、UpdateStudentsKnowledge()メソッドを呼び出します。このメソッドは、CLA_Lアルゴリズムで採用されている競争学習の原理に従って、エージェントの学習・適応をおこなう主要なメカニズムを実装しています。このメソッドのロジックによって、エージェント同士の相互作用や情報共有がおこなわれ、解の探索空間における各エージェントの位置が改善されます。

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::Moving ()
{
  // Initial population setup
  if (!revision)
  {
    for (int i = 0; i < popSize; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        double val = u.RNDfromCI (rangeMin [c], rangeMax [c]);
        a [i].c [c] = u.SeInDiSp (val, rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }
    revision = true;
    return;
  }

  currentIter++;

  // Update students' knowledge
  UpdateStudentsKnowledge ();
}
//————————————————————————————————————————————————————————————————————

UpdateStudentsKnowledge()メソッドは、最適化処理中に各生徒(エージェント)の位置を更新します。まず、現在の最適化の進捗状況を計算します。次に、2つの重要な学習係数を計算します。

  • TF (Teaching Factor):生徒が教師からどの程度学習するかを示します。
  • CF (Confirmatory Factor):生徒が教師たちの平均的な知識をどの程度考慮するかを示します。これらの係数は、生徒の進捗状況とクラスのランクに応じて決まります。

次に、すべての「有効な」教師(結果が有効な教師)の座標について平均値を計算します。この平均的な知識は、一時配列に格納されます。各生徒(エージェント)について、その生徒が所属するクラスを特定し、さらに各座標について新しい生徒の位置を計算します。新しい位置は、現在の座標に「知識源」から得られる変化量を加えることで求められます。生徒は、自分の教師から学習します。具体的には、教師の座標と自分自身の座標との差にTFを掛けた値だけ位置を調整します。十分な反復回数(currentIter > deltaIter)に達しており、かつ生徒が「最良解」を持っている場合、生徒は過去の成功経験からも学習します。この場合、ランダム係数を掛けた値だけ、最良座標の方向へ位置を調整します。

さらに、十分な反復回数に達しており、教師の数が有効である場合、生徒はすべての教師の平均的な知識から学習します。一定の確率(1-gamma)で、CFを掛けた平均座標の方向へ位置を調整します。最後に、各生徒の座標に境界条件(制約)を適用し、値が許容範囲内に収まることを保証します。また、探索時に使用するステップ幅に応じて、値が許容される値に一致するよう調整します。

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::UpdateStudentsKnowledge ()
{
  // Calculate learning factors for the current iteration
  double progress = (double)currentIter / (double)MathMax (totalIters, 100);

  // Calculate the average knowledge of all teachers (CL)
  ArrayInitialize (CL, 0.0);
  int validTeachers = 0;

  for (int k = 0; k < numClasses; k++)
  {
    // Make sure the teacher is initialized
    if (teachers [k].f > -DBL_MAX)
    {
      for (int c = 0; c < coords; c++)
      {
        CL [c] += teachers [k].c [c];
      }
      validTeachers++;
    }
  }

  if (validTeachers > 0)
  {
    for (int c = 0; c < coords; c++)
    {
      CL [c] /= validTeachers;
    }
  }

  // Update each student
  for (int i = 0; i < popSize; i++)
  {
    int classIdx = i / studentsPerClass;

    // Teaching Factor - decreases with progress
    double TF = MathExp (-0.6 * progress * classRanks [classIdx]);
    TF = MathMax (0.1, MathMin (1.0, TF));

    // Confirmatory Factor
    double CF = MathExp (-0.5 * progress * classRanks [classIdx]);
    CF = MathMax (0.1, MathMin (1.0, CF));

    // Update the student position
    for (int c = 0; c < coords; c++)
    {
      double newPos = a [i].c [c];

      // a) Teacher Learning - learn from the class teacher
      if (teachers [classIdx].f > -DBL_MAX)
      {
        newPos += TF * (teachers [classIdx].c [c] - a [i].c [c]);
      }

      // b) Personal Learning - learn from your best solution
      if (currentIter > deltaIter && a [i].fB > -DBL_MAX)
      {
        double PF = u.RNDprobab ();
        newPos += PF * (a [i].cB [c] - a [i].c [c]);
      }

      // c) Confirmatory Learning - learn from the average of all teachers
      if (currentIter > deltaIter && validTeachers > 0)
      {
        double rnd = u.RNDprobab ();
        if (rnd >= gamma) // Participate with probability (1-gamma)
        {
          newPos += CF * (CL [c] - a [i].c [c]);
        }
      }

      // Apply borders
      a [i].c [c] = u.SeInDiSp (newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//————————————————————————————————————————————————————————————————————

C_AO_CLA_lクラスのRevision()メソッドは、各エージェントの最良解に関する情報を更新するとともに、全体の最良解とそれに対応するパラメータを更新するために使用されます。

各エージェントについて、現在の目的関数値(a[i].f)が、記録されている最良値(a[i].fB)より改善されているかを確認します。改善されている場合は、その最良値を保存し、対応する座標をコピーします。すべてのエージェントの確認が完了した後、いずれかのエージェントが現在の全体の最良値(fB)よりも優れた関数値を得ていた場合、全体のパラメータを更新します。fBには全体の最良の関数値を、cBにはこの最良解の座標を設定します。

次に、UpdateTeachersAndCosts()メソッドを呼び出し、最良の教師に関する情報を更新します。最後にUpdateClassRanks()を呼び出してクラスのランクを再計算します。このランクは、その後の反復において、どの解を優先的に選択するかに影響します。

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::Revision ()
{
  for (int i = 0; i < popSize; i++)
  {
    // Update personal best positions
    if (a [i].f > a [i].fB)
    {
      a [i].fB = a [i].f;
      ArrayCopy (a [i].cB, a [i].c);
    }
    // Update the global best one
    if (a [i].f > fB)
    {
      fB = a [i].f;
      ArrayCopy (cB, a [i].c);
    }
  }

  // Update teachers 
  UpdateTeachersAndCosts ();

  // Update class ranks
  UpdateClassRanks ();
}
//————————————————————————————————————————————————————————————————————

UpdateTeachersAndCosts()メソッドは、各クラスの教師に関する情報を更新し、クラス全体の「コスト」を計算するために使用されます。メソッドでは、システムに定義されているすべてのクラスを順番に処理します。各クラスについて、そのクラスに所属する生徒(エージェント)の開始インデックスと終了インデックスを決定します。

クラス内で最も優れた生徒を見つけるために、最良の関数値、最良の生徒のインデックス、クラス内の全生徒の関数値の合計、および有効な生徒数を格納する変数を初期化します。続いて、現在のクラスに所属するすべての生徒を順番に処理します。各生徒について、その解が有効かどうかを確認し、有効であれば、生徒の適応度をsumFitnessに加算し、有効な生徒数のカウンタをインクリメントします。また、現在の生徒の適応度が現在の最良値bestFitnessより優れている場合は、bestFitnessを更新し、bestIdxをその生徒のインデックスに更新します。

クラス内の最良の生徒が見つかった後、そのクラスに少なくとも1人の有効な生徒が存在するか(validStudents > 0)を確認します。条件を満たしている場合、最良の生徒の座標を対応するクラスの教師の座標にコピーし、その生徒の関数値を教師の関数値として設定します。

次に、クラス内の全生徒の関数値の平均値avgFitnessを計算します。クラスの合計「コスト」は、最良の生徒の関数値と、係数betaにクラス内の全生徒の関数値の平均値を掛けた値の合計として計算されます。これは、教師の成果とクラス全体の平均的な水準を組み合わせた指標です。

//————————————————————————————————————————————————————————————————————
void C_AO_CLA::UpdateTeachersAndCosts ()
{
  for (int k = 0; k < numClasses; k++)
  {
    int startIdx = k * studentsPerClass;
    int endIdx = startIdx + studentsPerClass;

    double bestFitness = -DBL_MAX;
    int bestIdx = startIdx;
    double sumFitness = 0.0;
    int validStudents = 0;

    // Find the best student (teacher) in the class
    for (int i = startIdx; i < endIdx; i++)
    {
      if (a[i].f > -DBL_MAX) // Validity check
      {
        sumFitness += a[i].f;
        validStudents++;
        
        if (a[i].f > bestFitness)
        {
          bestFitness = a[i].f;
          bestIdx = i;
        }
      }
    }

    // Update the teacher
    if (validStudents > 0)
    {
      ArrayCopy (teachers[k].c, a[bestIdx].c);
      teachers[k].f = bestFitness;
      
      // Calculate the class total cost
      double avgFitness = sumFitness / validStudents;
      classTotalCosts[k] = bestFitness + beta * avgFitness;
    }
  }
}
//————————————————————————————————————————————————————————————————————

UpdateClassRanks()メソッドは、各クラスの全体的な「コスト」に基づいてクラスのランクを決定するために使用されます。このコストは、クラスがどの程度効果的であるかを示します。処理は、すべての有効なクラスの中から最小コストと最大コストを見つけることから始まります。すべてのクラスが同じ値である場合、または有効なクラスが存在しない場合は、すべてのクラスに同じランク1を設定します。

コストに差がある場合は、これらの値を正規化し、各コストを0から1の範囲に変換します。その後、値を反転させます。コストが高いクラスには1に近い低いランクが与えられ、コストが低いクラスにはクラス数に等しい最大ランクが与えられます。

その後、各ランクの値を最小値と最大値の範囲内に制限し、範囲外の値が発生しないようにします。最終的に、このメソッドの結果に基づいて、各クラスにその成績に応じたランクが与えられます。

//————————————————————————————————————————————————————————————————————
void C_AO_CLA_l::UpdateClassRanks ()
{
  // Find the min and max costs among valid classes
  double minCost   = DBL_MAX;
  double maxCost   = -DBL_MAX;
  int validClasses = 0;

  for (int k = 0; k < numClasses; k++)
  {
    if (classTotalCosts [k] > -DBL_MAX)
    {
      if (classTotalCosts [k] < minCost) minCost = classTotalCosts [k];
      if (classTotalCosts [k] > maxCost) maxCost = classTotalCosts [k];
      validClasses++;
    }
  }

  if (validClasses == 0 || maxCost - minCost < 1e-10)
  {
    // All classes have the same score
    for (int k = 0; k < numClasses; k++) classRanks [k] = 1.0;
  }
  else
  {
    // Ranking: best classes (high cost) get low rank
    for (int k = 0; k < numClasses; k++)
    {
      if (classTotalCosts [k] > -DBL_MAX)
      {
        // Normalize from 0 to 1
        double normalized = (classTotalCosts [k] - minCost) / (maxCost - minCost);

        // Inversion: the best get a rank close to 1
        classRanks [k] = 1.0 + (1.0 - normalized) * (numClasses - 1.0);

        // Limitation
        classRanks [k] = MathMax (1.0, MathMin ((double)numClasses, classRanks [k]));
      }
      else
      {
        classRanks [k] = numClasses; // Worst rank for uninitialized
      }
    }
  }
}
//————————————————————————————————————————————————————————————————————


テスト結果

テスト結果によると、CLA_Lアルゴリズムは比較的良好な結果を示しています。

CLA_L|Competitive Learning Algorithm|198.0|3.0|0.3|0.8|2.0|
=============================
5 Hilly's; Func runs:10000; result:0.6482993681242128
25 Hilly's; Func runs:10000; result:0.5535249826770444
500 Hilly's; Func runs:10000; result:0.2584959913710746
=============================
5 Forest's; Func runs:10000; result:0.8027208362980616
25 Forest's; Func runs:10000; result:0.49540442971179494
500 Forest's; Func runs:10000; result:0.20048686632188017
=============================
5 Megacity's; Func runs:10000; result:0.6353846153846153
25 Megacity's; Func runs:10000; result:0.2716923076923076
500 Megacity's; Func runs:10000; result:0.10086153846153936
=============================
All score:3.96687 (44.08%)

可視化結果から、アルゴリズムは初期段階では優れた探索能力を示しているものの、局所解に陥ることでその能力が低下し、アルゴリズムの動作後半では停滞が生じていることが分かります。

Hilly

Hillyテスト関数のCLA_L

Forest

Forestテスト関数のCLA_L

Megacity

Megacityテスト関数のCLA_L

アルゴリズムの動作結果に基づき、参考情報としてCLA_Lのランキング表を以下に示します。

# AO 説明 Hilly Hilly
ファイナル
Forest Forest
ファイナル
Megacity(離散) Megacity
ファイナル
ファイナル
結果

MAX
10p(5F)50p(25F)1000p(500F)10p(5F)50p(25F)1000p(500F)10p(5F)50p(25F)1000p(500F)
1ANSacross neighbourhood search0.949480.847760.438572.235811.000000.923340.399882.323230.709230.634770.230911.574916.13468.15
2CLAコードロックアルゴリズム(joo)0.953450.871070.375902.200420.989420.917090.316422.222940.796920.693850.193031.683806.10767.86
3AMOm動物移動最適化m0.903580.843170.462842.209590.990010.924360.465982.380340.567690.591320.237731.396755.98766.52
4(P+O)ES(P+O)進化戦略0.922560.881010.400212.203790.977500.874900.319452.171850.673850.629850.186341.490035.86665.17
5CTA彗星の尾アルゴリズム(joo)0.953460.863190.277702.094350.997940.857400.339492.194840.887690.564310.105121.557125.84664.96
6TETA時間進化移動アルゴリズム(joo)0.913620.823490.319902.057010.970960.895320.293242.159520.734620.685690.160211.580525.79764.41
7SDSm確率的拡散探索M0.930660.854450.394762.179880.999830.892440.196192.088460.723330.611000.106701.441035.70963.44
8BOAmビリヤード最適化アルゴリズムM0.957570.825990.252352.035901.000000.900360.305022.205380.735380.525230.095631.356255.59862.19
9AAmアーチェリーアルゴリズムM0.917440.708760.421602.047800.925270.758020.353282.036570.673850.552000.237381.463235.54861.64
10ESG社会集団の進化(joo)0.999060.796540.350562.146161.000000.828630.131021.959650.823330.553000.047251.423585.52961.44
11SIA等方的焼きなまし(joo)0.957840.842640.414652.215130.982390.795860.205071.983320.686670.493000.090531.270205.46960.76
12EOm極値最適化M0.761660.772420.317471.851550.999990.767510.235272.002770.747690.539690.142491.429875.28458.71
13BBO生物地理学に基づく最適化0.949120.694560.350311.993990.938200.673650.256821.868670.746150.482770.173691.402615.26558.50
14ACS人工協調探索0.755470.747440.304071.806981.000000.888610.224132.112740.690770.481850.133221.305835.22658.06
15DA弁証法的アルゴリズム0.861830.700330.337241.899400.981630.727720.287181.996530.703080.452920.163671.319675.21657.95
16BHAmブラックホールアルゴリズムM0.752360.766750.345831.864930.935930.801520.271772.009230.650770.516460.154721.321955.19657.73
17ASO無政府社会最適化0.848720.746460.314651.909830.961480.791500.238031.991010.570770.540620.166141.277525.17857.54
18RFOロイヤルフラッシュ最適化(joo)0.833610.737420.346291.917330.894240.738240.240981.873460.631540.502920.164211.298675.08956.55
19AOSm原子軌道探索M0.802320.704490.310211.817020.856600.694510.219961.771070.746150.528620.143581.418355.00655.63
20TSEA亀甲進化アルゴリズム(joo)0.967980.644800.296721.909490.994490.619810.227081.841390.690770.426460.135981.253225.00455.60
21BSAバックトラッキング探索アルゴリズム0.973090.545340.290981.809410.999990.585430.217471.802890.847690.369530.129781.347004.95955.10
22DE差分進化0.950440.616740.303081.870260.953170.788960.166521.908650.786670.360330.029531.176534.95555.06
23SRAレストラン経営達人アルゴリズム(joo)0.968830.634550.292171.895550.946370.555060.191241.692670.749230.440310.125261.314804.90354.48
24CRO化学反応の最適化0.946290.661120.298531.905930.879060.584220.211461.674730.758460.426460.126861.311784.89254.36
25BIO血液型遺伝最適化(joo)0.815680.653360.308771.777810.899370.653190.217601.770160.678460.476310.139021.293784.84253.80
26BSA鳥群アルゴリズム0.893060.649000.262501.804550.924200.711210.249391.884790.693850.326150.100121.120124.80953.44
27DEAイルカのエコーロケーションアルゴリズム0.759950.675720.341711.777380.895820.642230.239411.777460.615380.440310.151151.206844.76252.91
28HSハーモニー検索0.865090.687820.325271.878180.999990.680020.095901.775920.620000.422670.054581.097254.75152.79
29SSG苗木の播種と育成0.778390.649250.395431.823080.859730.624670.174291.658690.646670.441330.105981.193984.67651.95
30BCOm細菌走化性最適化M0.759530.622680.314831.697040.893780.613390.225421.732590.653850.420920.144351.219124.64951.65
31ABOアフリカ水牛の最適化0.833370.622470.299641.755480.921700.586180.197231.705110.610000.431540.132251.173784.63451.49
32(PO)ES(PO)進化戦略0.790250.626470.429351.846060.876160.609430.195911.681510.590000.379330.113221.082554.61051.22
33FBAフラクタルベースのアルゴリズム0.790000.651340.289651.730990.871580.568230.188771.628580.610770.460620.123981.195374.55550.61
34TSmタブーサーチM0.877950.614310.291041.783300.928850.518440.190541.637830.610770.382150.121571.114494.53650.40
35BSOブレインストーム最適化0.937360.576160.296881.810410.931310.558660.235371.725340.552310.290770.119140.962224.49849.98
36WOAm鯨最適化アルゴリズムM0.845210.562980.262631.670810.931000.522780.163651.617430.663080.411380.113571.188034.47649.74
37AEFA人工電界アルゴリズム0.877000.617530.252351.746880.927290.726980.180641.834900.666150.116310.095080.877544.45949.55
38AEO人工生態系ベースの最適化アルゴリズム0.913800.467130.264701.645630.902230.437050.214001.553270.661540.308000.285631.255174.45449.49
39CAmラクダアルゴリズムM0.786840.560420.351331.698590.827720.560410.243361.631490.648460.330920.134181.113564.44449.37
40ACOm蟻コロニー最適化M0.881900.661270.303771.846930.858730.586800.150511.596040.596670.373330.024720.994724.43849.31
41CMAES共分散行列適応進化戦略0.762580.720890.000001.483470.820560.796160.000001.616720.758460.490770.000001.249234.34948.33
42BFO-GA細菌採食の最適化:Ga0.891500.551110.315291.757900.969820.396120.063051.428990.726670.275000.035251.036924.22446.93
43SOAシンプル最適化アルゴリズム0.915200.469760.270891.655850.896750.374010.169841.440600.695380.280310.108521.084224.18146.45
44ABHA人工蜂の巣アルゴリズム0.841310.542270.263041.646630.878580.477790.171811.528180.509230.338770.103970.951974.12745.85
45ACMO大気雲モデルの最適化0.903210.485460.304031.692700.802680.378570.191781.373030.623080.244000.107950.975034.04144.90
CLA_L競争学習アルゴリズム0.648290.553520.258491.460300.802720.495400.200481.498600.635380.271690.100861.007933.96744.08
RWランダムウォーク0.487540.321590.257811.066940.375540.219440.158770.753750.279690.149170.098470.527342.34826.09


まとめ

競争学習アルゴリズム(CLA_L)は、標準的な最適化問題の求解において平均的な性能を示します。アルゴリズムの動作を分析した結果、特徴的な2段階の動的挙動が確認されました。初期の反復では活発な探索段階が見られる一方、最適化プロセスの後半では早期停滞が発生します。

集団をクラスに分割することで、初期段階における探索空間の良好なカバレッジが確保されます。各クラスがそれぞれ異なる領域を探索するため、全体的な探索に寄与します。また、教育モデルによって、アルゴリズムの仕組みが分かりやすく、解釈しやすくなっています。教師、生徒、そして異なる学習方式という概念は自然に理解できます。クラスのランクに応じて変化する学習係数は、理論上、探索と活用のバランスを取る役割を果たします。教師からの学習、個人的な学習、確認学習という3種類の学習を組み合わせることで、局所最適解を回避できる可能性も生まれます。しかし、こうした多様化のメカニズムを備えているにもかかわらず、アルゴリズムは局所最適解に陥りやすい傾向があります。 

CLAアルゴリズムは、教育というメタファーを最適化問題に適用する興味深いコンセプトを提示しています。革新的なアプローチと良好な初期性能を備えている一方で、現代のメタヒューリスティクスと競争できる性能を実現するには、大幅な改良が必要です。最大の課題は、最適化プロセス全体を通じて探索と活用のバランスを維持することにあります。

タブ

図2:テストによるアルゴリズムの色分け

チャート

図3:アルゴリズムテスト結果のヒストグラム(0から100のスケール、高いほど良い)100は理論上の最大値であり、アーカイブには評価表を計算するためのスクリプトがあります。

CLA_Lの長所と短所

長所

  1. 高速

短所

  1. 多数の外部パラメータ
  2. 局所最適解に陥りやすい。

この記事には、最新版のアルゴリズムコードを含むアーカイブが添付されています。記事の著者は、正統的なアルゴリズム定義の説明の絶対的な正確さについて責任を負いません。探索性能を向上させるために、それらの多くに変更が加えられています。記事に示された結論と判断は、実験結果に基づいています。


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

#名前種類説明
1#C_AO.mqh
インクルード
集団最適化アルゴリズムの親クラス
2#C_AO_enum.mqh
インクルード
集団最適化アルゴリズムの列挙
3TestFunctions.mqh
インクルード
テスト関数のライブラリ
4
TestStandFunctions.mqh
インクルード
テストスタンド関数ライブラリ
5
Utilities.mqh
インクルード
補助関数のライブラリ
6
CalculationTestResults.mqh
インクルード
比較表の結果を計算するスクリプト
7
Testing AOs.mq5
スクリプトすべての集団最適化アルゴリズムの統一テストスタンド
8
Simple use of population optimization algorithms.mq5
スクリプト
可視化せずに集団最適化アルゴリズムを使用する簡単な例
9
Test_AO_CLA_L.mq5
スクリプトCLA_Lテストスタンド

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

添付されたファイル |
CLA_I.zip (250.43 KB)
初級から中級まで:MetaTrader 5のサンドボックスにおけるファイル操作 初級から中級まで:MetaTrader 5のサンドボックスにおけるファイル操作
サンドボックスとは何かご存じでしょうか。また、サンドボックスをどのように扱うのかご存じでしょうか。もし、これらの質問のいずれかに「いいえ」と答えるのであれば、サンドボックスの基本的な動作原理を理解するために、この記事を読んでください。また、MetaTrader 5が内部データの整合性を保護するためにサンドボックスを使用している理由についても理解できるでしょう。ここで紹介する内容は、純粋に教育目的です。いかなる場合においても、本稿で扱うアプリケーションを、ここで説明する概念を学習すること以外の目的を持つ完成品として扱わないでください。
取引におけるニューラルネットワーク:高精度分類のための効果的な特徴量抽出(Mantis) 取引におけるニューラルネットワーク:高精度分類のための効果的な特徴量抽出(Mantis)
Transformerアーキテクチャを基盤とし、対照学習による事前学習とハイブリッドアテンションを備えた、軽量な時系列分類向け基盤モデル、Mantisを紹介します。最高水準の精度とスケーラビリティを実現します。
最強のML搭載取引プラットフォームが生まれるまで:アーカイブ、フォーラム、リリースからたどるMQLとMetaTraderの進化 最強のML搭載取引プラットフォームが生まれるまで:アーカイブ、フォーラム、リリースからたどるMQLとMetaTraderの進化
MQLの技術史を振り返り、機能が限定されていた初期のMQLおよびMQL II言語から、手続き型のMQL4、そしてオブジェクト指向のMQL5へと至る進化をたどります。MQL5では、ネイティブコンパイル、豊富なAPI、本格的な開発環境が実現しました。本記事では、MQLの主要な機能に加え、Python、OpenCL、ONNX、OpenBLAS、データベース、DirectX、エージェント型AIアシスタント(Agentic AI Assistant)、そしてModel Context Protocol (MCP)との統合について紹介します。MCPは、AIシステムとターミナル、MetaEditor、市場データ、取引操作、開発ツールを接続します。さらに、MetaQuotesとMetaTraderの起源に関するアーカイブ資料、MQL4.COMおよびMQL5.COMの開設、各種選手権、Algo Forge、そしてこれらがエコシステムに与えた影響について考察します。
市場シミュレーション:ポジション表示(III) 市場シミュレーション:ポジション表示(III)
以前の記事では、ZOrderプロパティに値を設定する必要がある場合があることについて説明しました。しかし、なぜでしょうか。チャートにオブジェクトを追加する多くのコードが、このプロパティを使用していない、より正確に言えば、このプロパティに値を定義していないからです。すべてのプログラマーが何をすべきか、あるいはすべきでないか、また、どのようにコードを書くべきか、あるいは書くべきでないかを私が決めるために、ここにいるわけではありません。私は、読者の皆さん、そしてこれらの処理が内部でどのように動作しているのかを本当に理解したいすべての方々に対して、実際に舞台裏で何が起こっているのかを示すために、ここにいます。