English Русский Español Deutsch 日本語 Português
preview
种群优化算法:进化策略,(μ,λ)-ES 和 (μ+λ)-ES

种群优化算法:进化策略,(μ,λ)-ES 和 (μ+λ)-ES

MetaTrader 5示例 | 12 八月 2024, 13:31
18 0
Andrey Dik
Andrey Dik

内容

1. 概述
2. 算法
3. 替换测试函数
4. 测试结果
5. 结束语


1. 概述

进化策略算法中的优化方法,基于从自然界中观察到的原理。它们模拟自然选择,其中最优解得以生存,并将其特性传递给下一代。这些算法广泛用于解决优化问题,尤其是在机器学习和人工智能领域。它们是由德国的 Ingo Rechenberg 教授及其同事在 1960 年代开发的,用于解决工业和工程中的优化问题。

进化策略的基本思想是创建一个解集,然后使用类似于自然进化中所用的突变和选择运算符来改进它们。进化策略使用真实向量来表示解。这令我们能够更灵活、更准确地描述解空间,并搜索最优值,这与二元运算的经典遗传算法形成鲜明对比。

进化策略有若干种不同的变体,它们在种群的生成和处理方式,以及所用的突变和选择运算符上有所不同。一些最常见的选项包括:

  1. (1+1)-ES:在该变体中,仅为每个亲本创建一个子代,两者的最优解将成为下一代的亲本。这种简单快速的方法对于某些问题可能有效,但对于优化复杂问题时效果较差。(1+1)-ES 算法创建于 1960 年代,是优化所有进化策略的最简单方法之一。它包括生成一个随机向量,然后将其按随机步骤变更。如果修改后的向量更好,则替换原始向量,否则原始向量保持不变。重复此过程,直到达成最优态。
  1. (μ,λ)-ES:在该算法中,创建了一个 μ 大小的亲本群落,并产生 λ 个子代,且最佳子代会取代亲本。它可以有效地解决各种优化问题。(μ,λ)-ES 算法由 Reinhard Speigelmann 创建于 1965 年。在对子代进行评估后,只保留最佳的 μ 解,并成为下一代的亲本,因此亲本在每个世代都完全被子代替换。
  1. (μ+λ)-ES:在该选项中,将创建 λ 个后代。他们中的佼佼者,与亲本一起参与下一代的创造。在这种方法中,亲本和子代相互竞争,这与 (μ,λ)-ES 是一个重要的区别。(μ+λ)-ES 算法由 Johannes Reichenbacher 和 Hans-Paul Schwefel 于 1970 年代创建,是优化所有进化策略的一种方法。这种方法允许对解空间进行更完整的探索,并且可以更有效地解决复杂问题。

进化策略还有其它变体,但在本文中,我们仅研究 (μ,λ)-ES 和 (μ+λ)-ES。(1+1)-ES 选项太简单,不适合求解多维问题。由于在代码、文件名、以及变量名中使用希腊字母和特殊字符的困难,我们将分别使用 PO 和 P_O,其中 P 代表亲本,O 意即幼崽(后代)。

计算机科学中的进化策略令我们能够对进化和自然选择进行建模,从而解决复杂的优化问题。它们使用类似于自然选择的原理在参数空间中寻找最优解。

在没有明显的分析解、或搜索空间非常大的问题中,这些算法特别实用。它们可以采用受进化启发的操作(如杂交、突变、和选择)有效地搜索最优解。

“进化策略”这个名字可能具有误导性,因为研究人员也许认为它是一类进化算法的通用名称。然而,事实并非如此。事实上,它是一套特定的算法,它们利用进化的思想来解决优化问题。


2. 算法

(μ,λ)-ES 表示在算法的每次迭代中,选择 μ 个亲本,并生成 λ 个子代。然后,从 λ 个子代中选择最佳 μ 子代,成为下一次迭代的亲本。因此,在 (μ,λ)-ES 中,新的幼崽完全取代了他们的亲本,并参与下一代的创造。

(μ+λ)-ES 按类似的方式工作,但不是从 λ 中选择最佳幼崽,而是将它们与亲本结合形成 μ+λ 大小的新群落。然后从这个组合群落中选择 μ 个最佳个体成为下一次迭代的亲本。因此,在 (μ+λ)-ES 中,新的幼崽与他们的亲本一起形成下一个群落,并相互竞争。

(μ,λ)-ES 和 (μ+λ)-ES 之间的主要区别在于新生幼崽如何与亲本竞争在下一个群落中的位置。在 (μ,λ)-ES 中,新生子代与亲本争夺有限数量的名额,这可能导致过早地收敛到局部最优值。在 (μ+λ)-ES 中,新生子代与亲本一起工作,从而对解空间进行了更广泛的探索。

两种进化策略算法都基于遗传算子的组合:突变和选择。在算法的每次迭代中,从当前群落中选择一位个体,并对其应用突变算子,然后计算所得个体的适应度,并将最适者放入下一个群落之中。为了生成初始群落,为变化参数向量里的每个分量指定一个区间,并假设分量的初始值在指定的区间内均匀分布。该算法可以使用各种停止条件,例如达到指定的世代数量、指定的群落状态、或指定的收敛水平。在 (μ+λ) 算法中,所有个体都包含在群落中,而在 (μ,λ) 算法中,仅包含后代。对于 (μ+λ) 算法,概率收敛性已经得到证明,但对于 (μ,λ) 算法,收敛性问题仍然悬而未决。

(μ+λ) 和 (μ,λ) 算法的比较表明,(μ+λ) 算法在使用高度适应的个体方面更节省,保留他们与后代竞争。这增加了搜索的强度,但可能导致过早收敛到局部极值。传统进化策略算法中的突变算子是唯一的进化算子,使用高斯突变算法。

经典的 (μ,λ)-ES 算法可以用以下伪代码来描述:

1. 以随机个体初始化初始群落。
2. 重复直到达到停止标准:
2.1. μ 个亲本中的每一个都使用突变算子生成 λ 个幼崽,并入当前群落。
2.2. 选择最佳的 μ 个后代组成下一个群落。
3. 从最后一个群落中返回最佳个体。

传统的 (μ+λ)-ES 算法可以用以下伪代码来描述:

1. 以随机个体初始化初始群落。
2. 重复直到达到停止标准:
2.1. μ 个亲本中的每一个都使用突变算子生成 λ 个幼崽,并入当前群落。
2.2. 将亲本和幼崽合并,得到 μ+λ 大小的组合群落。
2.3. 从组合群落中选择最佳的 μ 位个体组成下一个群落。
3. 从最后一个群落中返回最佳个体。

我们查看了两种主要“进化策略”算法的经典版本。在这两种情况下,亲本仅使用他们的遗传信息产生 λ 个幼崽。该结局呈星形分支,其中每个后代都彼此独立发育。亲本之间也没有信息交流,这排除了结合他们的遗传特性的可能性。如此这般,组合品质彻底缺失。

测试结果表明,这两种 ES 选项的效率都较低。我尝试使用重组来提升它。

重组允许将来自不同个体的遗传物质组合在一起,从而创建可能具有更好属性或性状的新组合。这一过程促进了群落的多样性。

重组(或杂交)是将亲本的遗传物质结合,从而产生幼崽的过程。这个过程模拟了生物进化中的自然交叉。在重组期间,亲本的基因结合,为幼崽创造新的遗传物质。重组通常发生在基因或遗传性状的级别上。基因是生物体基因组中特定属性或特征的编码信息片段。

重组后,后代的基因将使用突变算子进行更改,可对基因进行随机更改。这有助于将新的研究变体引入群落,并促进遗传物质的多样性。

因此,对于每个后代基因,我们将使用随机选择的亲本基因,其中基因是相应的亲本坐标。因此,幼崽将继承群落中所有亲本的特征。


(μ,λ)-ES 算法。

我们继续回顾代码,从更简单的算法 (μ,λ)-ES 开始,通过添加重组(来自多个亲本的基因遗传)进行修改。

对于充当个体的亲本和子代,S_Agent 是一个好的结构,其中包含一个坐标 “c” 的数组,和一个变量 “f” — 适应度值。Init 函数初始化个体时,会调整数组 “c” 的大小,并将 “f” 的值设置为 “-DBL_MAX”(可能的最差适应度值)。

//——————————————————————————————————————————————————————————————————————————————
struct S_Agent
{
  void Init (int coords)
  {
    ArrayResize (c, coords);
    f = -DBL_MAX;
  }

  double c []; //coordinates
  double f;    //fitness
};
//——————————————————————————————————————————————————————————————————————————————

声明 C_AO_POES 类来描述 (μ,λ)-ES 算法。

该类包含以下元素:
  • “cB”、“fB”、“a”、“rangeMax”、“rangeMin”、“rangeStep” 公开变量:这些变量分别用于存储最佳坐标、对应的适应度函数值、个体、最大和最小搜索值、以及搜索步骤。
  • Public Init():该函数初始化优化算法。它需要几个参数,例如坐标数量、群落大小、亲本个体数量、突变强度、和西格玛值。在函数内部,算法所用的变量和数组被初始化。
  • “Moving()” 和 “Revision()” 公开函数:这些函数分别用于执行个体移动和群落修订。
  • “coords”、“popSize”、“parentsNumb”、“mutationPower”、“sigmaM”、和 “revision” 私密变量:这些变量分别用于存储坐标数量、群落大小、亲本个体数量、突变强度、西格玛值、和修订标志。
  • “parents”、“ind”、“val” 和 “pTemp” 私密数组:这些数组分别用于存储有关亲本个体、索引、值、和临时变量的信息。
  • GaussDistribution()、SeInDiSp()、RNDfromCI()、Scale()、Sorting() 私密函数:这些函数用于执行随机数生成、值缩放、和数组排序。
//——————————————————————————————————————————————————————————————————————————————
class C_AO_POES
{
  //----------------------------------------------------------------------------
  public: double  cB [];  //best coordinates
  public: double  fB;     //FF of the best coordinates
  public: S_Agent a  [];  //agent

  public: double rangeMax  []; //maximum search range
  public: double rangeMin  []; //manimum search range
  public: double rangeStep []; //step search

  public: void Init (const int    coordsP,          //coordinates number
                     const int    popSizeP,         //population size
                     const int    parentsP,         //number of parents, < Population size
                     const double mutationPowerP,   //mutation power
                     const double sigmaP);          //sigma

  public: void Moving   ();
  public: void Revision ();

  //----------------------------------------------------------------------------
  private: int    coords;        //coordinates number
  private: int    popSize;       //population size
  private: int    parentsNumb;   //number of parents
  private: double mutationPower; //mutation power
  private: double sigmaM;
  private: bool   revision;

  private: S_Agent parents [];  //parents
  private: int     ind     [];
  private: double  val     [];
  private: S_Agent pTemp   [];

  private: double GaussDistribution   (const double In, const double outMin, const double outMax, const double sigma);
  private: double SeInDiSp  (double In, double InMin, double InMax, double Step);
  private: double RNDfromCI (double min, double max);
  private: double Scale     (double In, double InMIN, double InMAX, double OutMIN, double OutMAX,  bool revers);
  private: void   Sorting   (S_Agent &p [], int size);
};
//——————————————————————————————————————————————————————————————————————————————

为了初始化优化算法,调用 C_AO_POES 类的 Init 函数。该函数接受几个参数:坐标数量、群落大小、亲本个体数量、突变强度、和西格玛值。

在函数内部,算法所用的变量和数组被初始化。该函数执行以下操作:

  • 重置随机数生成器,并将 “fB” 变量设置为 “-DBL_MAX”。 
  • 设置 “coords”、“popSize”、“parentsNumb”、“mutationPower” 和 “sigmaM” 变量值。 
  • 调用 ArrayResize 函数更改 “ind”、“val”、“pTemp”、“a”、“parents”、“rangeMax”、“rangeMin”、“rangeStep” 和 “cB” 数组大小。 
  • “a” 和 “parents” 数组是调用 “S_Agent” 类的 Init 函数初始化的,该函数初始化个体的坐标,并将 “f” 变量值设置为 “-DBL_MAX”。
//——————————————————————————————————————————————————————————————————————————————
void C_AO_POES::Init (const int    coordsP,          //coordinates number
                      const int    popSizeP,         //population size
                      const int    parentsP,         //number of parents, < Population size
                      const double mutationPowerP,   //mutation power
                      const double sigmaP)           //sigma
{
  MathSrand ((int)GetMicrosecondCount ()); // reset of the generator
  fB       = -DBL_MAX;
  revision = false;

  coords        = coordsP;
  popSize       = popSizeP;
  parentsNumb   = parentsP;
  mutationPower = mutationPowerP;
  sigmaM        = sigmaP;

  ArrayResize (ind,   popSize);
  ArrayResize (val,   popSize);
  ArrayResize (pTemp, popSize);
  ArrayResize (a,     popSize);
  for (int i = 0; i < popSize; i++) a [i].Init (coords);

  ArrayResize (parents, parentsNumb);
  for (int i = 0; i < parentsNumb; i++) parents [i].Init (coords);

  ArrayResize (rangeMax,  coords);
  ArrayResize (rangeMin,  coords);
  ArrayResize (rangeStep, coords);
  ArrayResize (cB,        coords);
}
//——————————————————————————————————————————————————————————————————————————————

Moving 方法在搜索空间中移动个体。

该函数包含两个代码模块,由 “if (!revision)” 条件分隔。

  1. 在第一个模块中,如果 “revision” 标志为 “false”,则为每位个体生成随机坐标。对于每个坐标,生成一个随机数,在 “rangeMin” 和 “rangeMax” 之间均匀分布,然后调用 SeInDiSp 函数对该数字进行常规化,该函数将坐标值设置为 “rangeStep” 的最接近的倍数。
  2. 在第二个模块中,如果 “revision” 标志等于 “true”,则会发生个体的移动。对于每个个体,从 “parents” 数组中随机选择一个亲本个体。然后,计算每位个体坐标的突变值 “dist”。该值取决于 “mutationPower” 突变强度,以及 “rangeMin” 和 “rangeMax” 搜索范围。调用 GaussDistribution 函数更改个体的坐标值,该函数使用 “sigmaM” 西格玛值,在父坐标值周围生成一个正态分布的随机数。然后,调用 SeInDiSp 函数对坐标值进行常规化。
//——————————————————————————————————————————————————————————————————————————————
void C_AO_POES::Moving ()
{
  //----------------------------------------------------------------------------
  if (!revision)
  {
    for (int i = 0; i < popSize; i++)
    {
      for (int c = 0; c < coords; c++)
      {
        a [i].c [c] = RNDfromCI (rangeMin [c], rangeMax [c]);
        a [i].c [c] = SeInDiSp (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
      }
    }

    revision = true;
    return;
  }

  //----------------------------------------------------------------------------
  int    indx = 0;
  double min  = 0.0;
  double max  = 0.0;
  double dist = 0.0;

  for (int i = 0; i < popSize; i++)
  {
    for (int c = 0; c < coords; c++)
    {
      indx = (int)RNDfromCI (0, parentsNumb);
      if (indx >= parentsNumb) indx = parentsNumb - 1;

      a [i].c [c] = parents [indx].c [c];

      dist = (rangeMax [c] - rangeMin [c]) * mutationPower;

      min = a [i].c [c] - dist; if (min < rangeMin [c]) min = rangeMin [c];
      max = a [i].c [c] + dist; if (max > rangeMax [c]) max = rangeMax [c];

      a [i].c [c] = GaussDistribution (a [i].c [c], min, max, sigmaM);
      a [i].c [c] = SeInDiSp  (a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }
  }
}
//——————————————————————————————————————————————————————————————————————————————

群落修订是通过 “Revision” 方法执行的,其修改优化算法中个体的当前状态。

该函数包含两个代码模块。

  1. 在第一个模块中,在 “for” 循环中遍历 “a” 数组中的最优个体。如果发现某个个体的适应度值高于当前最佳个体的 “fB”,则该个体的索引将存储在 “indx” 变量之中。然后,根据新的最佳个体更新当前最佳个体的 “fB” 值,和 “cB” 坐标。
  2. 在第二个模块中,调用 Sorting 函数对 “a” 数组按适应度降序排序,然后将 “a” 数组中的最佳个体的 “parentsNumb” 复制到 “parents” 数组当中。


因此,“Revision” 函数允许更新个体的当前状态,并将最佳个体保存在 “parents” 数组之中,其中最好的子代彻底替换所有亲本个体。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_POES::Revision ()
{
  //----------------------------------------------------------------------------
  int indx = -1;

  for (int i = 0; i < popSize; i++)
  {
    if (a [i].f > fB) indx = i;
  }

  if (indx != -1)
  {
    fB = a [indx].f;
    ArrayCopy (cB, a [indx].c, 0, 0, WHOLE_ARRAY);
  }

  //----------------------------------------------------------------------------
  Sorting (a, popSize);
  for (int i = 0; i < parentsNumb; i++)
  {
    parents [i] = a [i];
  }
}
//——————————————————————————————————————————————————————————————————————————————


(μ+λ)-ES 算法。

更改始自以 “yearsNumber” 参数的形式添加个体的预期生存期开始。这令控制群落的最高年龄成为可能,并避免其与非常老化的个体“堵塞”,从而阻止对无限生活空间新视野的探索,及新的发现。我希望,在该算法中这样做会很实用。

为什么 “(μ,λ)-ES” 算法中不包含此计数器?因为这就是它的意图。亲本完全被后代取代。这也是有道理的,就像动物王国中的传宗接代一样,有些物种一生中只繁殖一次。这类物种的例子包括鲑鱼、龙舌兰、竹子、椰子蟹、和苏铁。然而,在我们的算法中,我们将为个体提供多次繁殖的机会,无限期地活着或像竹子一样骄傲地死去。预期生存期可以是一个可调节的外部参数,作为我们测试的一部分,实验发现最优持续时间为 10 年。

此外,当人们开始“记住”并积累特定解,而不是在搜索空间的其它地方找到新的成功解时,生存期计数器可以帮助避免模型“过拟合”。限制个体的生存期令我们能够保持群落的多样性,并继续寻找更优解。

//——————————————————————————————————————————————————————————————————————————————
struct S_Agent
{
  void Init (int coords)
  {
    ArrayResize (c, coords);
    f = -DBL_MAX;
    yearsNumber = 0;
  }

  double c []; //coordinates
  double f;    //fitness
  int yearsNumber;
};
//——————————————————————————————————————————————————————————————————————————————

在 “Init” 方法中,我们将通过子代数量来增加亲本群落的大小。这允许将亲本和子代一起排序,尽管就像在 (μ,λ)-ES 算法中一样,将来只有联合群落的 μ 部分将用于生成新的子代。虽然在以前的算法中,亲本的数量必须小于或等于后代的群落,但在该算法中,这无关紧要,亲本群落可以设置为任何大小,甚至非常大。这不会影响世代的数量。实验发现,在有 100 个后代的情况下,亲本群落 150 是最优值(随着世代数量的减少,不可能有更大的值)。亲本群落的进一步增加导致基因库的多样性过多,算法开始收敛得更糟(这本身就很有趣)。

ArrayResize (ind,   popSize + parentsNumb);
ArrayResize (val,   popSize + parentsNumb);
ArrayResize (pTemp, popSize + parentsNumb);
ArrayResize (a,     popSize);
for (int i = 0; i < popSize; i++) a [i].Init (coords);

ArrayResize (parents, popSize + parentsNumb);
for (int i = 0; i < popSize + parentsNumb; i++) parents [i].Init (coords);

在 Moving 方法中,在创建新后代时将个体的年份计数器设置为 1。

a [i].yearsNumber = 1;

这些更改还影响了 Revision 方法,在该方法中,代码在考虑更改的情况下执行以下操作:

  • 将每个亲本的 “yearsNumber” 值加 1。
  • 如果 “yearsNumber” 的值超过规定的限制(寿命),则将对应亲本的适应度值 “f” 设置为 “-DBL_MAX”,这意味着将个体从群落中删除。
  • 将新的子代数组从 “a” 数组复制到 “parents” 数组。
  • 按 “f” 适应度值对 “parents” 数组进行排序。
//----------------------------------------------------------------------------
for (int i = 0; i < parentsNumb; i++)
{
  parents [i].yearsNumber++;

  if (parents [i].yearsNumber > lifespan)
  {
    parents [i].f = - DBL_MAX;
  }
}

for (int i = parentsNumb; i < parentsNumb + popSize; i++)
{
  parents [i] = a [i - parentsNumb];
}

Sorting (parents, parentsNumb + popSize);



3. 替代测试函数

以前,我们调用 Rastrigin 函数作为测试函数来评估优化算法。然而,Rastrigin 函数并非此意图的完美选择。它具有严格的周期性,和平衡的最小值和最大值,某些算法可以相对容易地检测到。因此,Rastrigin 函数表现出的形态也许会影响算法判定函数极值的能力。

为了对优化算法进行更可靠和客观的测试,建议调用具有多样化和不可预测属性的函数。此类函数通常没有明显的形态,也没有最小值和最大值之间的平衡。此类函数的示例包括噪声函数、具有非线性依赖性的函数、或具有大量局部极值的函数。选择这种函数,令我们能够更准确地评估算法在各种条件下检测并收敛到全局最优的能力。

按照惯例,所有函数都可以分为“简单”和“复杂”。简单函数是指最大表面积位于 “max” 和 “min” 之间中线上方的函数,并且表面积越接近 “max”,优化算法就越简单。因此,如果我们简单地在函数域的整个表面上随机放置点,我们将得到“高”优化结果的错误印象,因为结果将接近绝对全局最大值。这种简单函数的一个例子是图例 1 中假设函数的示意图。

虚假成功

图例 1. 优化算法的“简单”函数示例

鉴于上述情况,Rastrigin 函数可以归类为一种简单函数,该函数可能会导致某些优化算法的结果夸大。这是由于这些算法的搜索策略的特殊性,它可以将其个体分散在整个函数表面。

对于具有大量变量(例如 1000)的 Rastrigin 函数,这种影响尤其明显。虽然一些算法“诚实地”试图找到全局极值,但其它算法也许只是简单地将个体均匀地放置在函数的整个表面。这种方法并不表示优化算法能够执行准确的搜索,而只是给人一种能够这样做的错觉。

Rastrigin 函数已进行了重大修改,为优化算法创建了更复杂、更具挑战性的环境。该函数的新版本增加了若干个“山丘”和“山谷”,同时保持了表面那部分的周期性,这无助于找到全球极值。这些变化会造成额外的障碍,分散注意力,并充当陷阱。

现在,我们不能只是跳到具有周期性的步骤,以求达到全局极值,就像在传统版本的 Rastrigin 中一样。此外,全局最优值已从边缘移开,因此在通常关注函数定义边界的算法中,如果出现伪影,则很难找到。

新函数称为 “Hilly”(图例 2)。与 “Forest” 和 “Megacity” 一样,它指的是复杂的测试函数。对于这三个函数,位于最大高度的 50% 以上的表面积大致相同,约占函数总面积的 20%。

Hilly、Forest 和 Megacity 函数提供了复杂且真实的优化场景,可以帮助评估算法在复杂和多样化条件下的性能。通过调用这些函数作为优化算法的综合测试,我们可以更深入地了解它们找到全局最优和克服局部陷阱的能力。

此外,还对测试方法进行了更改。现在,执行 10 轮测试而不是 5 轮(优化过程的重复运行次数),以减少结果中的随机“尖峰”。


Hilly2

图例 2. Hilly 测试函数

4. 测试结果

(μ,λ)-ES 算法测试台结果:

C_AO_(PO)ES:100:10:0.025:8.0
=============================
5 Hilly's; Func runs: 10000; result: 0.7902459324049909
25 Hilly's; Func runs: 10000; result: 0.6264667539839893
500 Hilly's; Func runs: 10000; result: 0.42934981087827656
=============================
5 Forest's; Func runs: 10000; result: 0.8761631782479373
25 Forest's; Func runs: 10000; result: 0.6094343681829253
500 Forest's; Func runs: 10000; result: 0.19591138782930953
=============================
5 Megacity's; Func runs: 10000; result: 0.5900000000000001
25 Megacity's; Func runs: 10000; result: 0.37933333333333336
500 Megacity's; Func runs: 10000; result: 0.11321666666666666
=============================
All score: 4.61012

(μ+λ)-ES 算法测试台结果:

C_AO_(P_O)ES:100:150:0.02:8.0:10
=============================
5 Hilly's; Func runs: 10000; result: 0.9993447297882565
25 Hilly's; Func runs: 10000; result: 0.9189524317647721
500 Hilly's; Func runs: 10000; result: 0.562968579605404
=============================
5 Forest's; Func runs: 10000; result: 1.0
25 Forest's; Func runs: 10000; result: 0.9352215748931851
500 Forest's; Func runs: 10000; result: 0.3917923122543615
=============================
5 Megacity's; Func runs: 10000; result: 0.8316666666666664
25 Megacity's; Func runs: 10000; result: 0.6443333333333332
500 Megacity's; Func runs: 10000; result: 0.21155000000000007
=============================
All score: 6.49583

下面的可视化是针对 (μ+λ)-ES 算法的,该算法展示了针对搜索空间的出色探索,且不会遗漏可能有希望的区域。

Hilly

(μ+λ)-ES 基于 Hilly 测试函数

Forest

  (μ+λ)-ES 基于 Forest 测试函数

Megacity

  (μ+λ)-ES 基于 Megacity 测试函数


决定返回到测试结果的绝对值,并放弃相对值。为了达成这一点,对测试函数进行了修改,以便它们返回的值在 0.0 到 1.0 之间。现在,如果结果为 1.0,则表示 100% 收敛,而 0.32527 表示检验函数全局最大值的 32.5%。因此,由于测试总数为 9,因此从理论上讲,在算法 100% 收敛的情况下,在表格的“最终结果”列的每次测试上,算法可以显示所有测试的最大可能总结果不超过 9.0。此外,还添加了 “% of MAX” 列,显示最大可能结果的百分比。


现在,当把新算法添加到表格中时,结果数字不会改变,因为它们是以绝对值表示的。

如此,我们转到所研究算法的结果,首先是 (μ+λ)-ES。该算法的惊人结果真的令我感到惊讶:它总共获得了理论上可能结果的 72.18%。为了确保这些令人印象深刻的结果,专门针对该算法进行了 20 轮测试。20 轮运行中的每一次都显示出 100% 收敛于复杂的 Forest 函数 — 这简直太巨大了!此外,其它函数的结果也令人瞩目。

现在关于 (μ,λ)-ES 的一些溢美之词。该算法表现出稳定和良好的结果。在彩色图形中,它是均匀的“绿色”,没有颜色突变。

#

AO

说明

Hilly

Hilly 最终

Forest

Forest 最终

Megacity (离散)

Megacity 最终

最终结果

% of MAX

10 p (5 F)

50 p (25 F)

1000 p (500 F)

10 p (5 F)

50 p (25 F)

1000 p (500 F)

10 p (5 F)

50 p (25 F)

1000 p (500 F)

1

(P+O)ES

(P+O) 进化策略

0.99934

0.91895

0.56297

2.48127

1.00000

0.93522

0.39179

2.32701

0.83167

0.64433

0.21155

1.68755

6.496

72.18

2

SDSm

随机扩散搜索 M

0.93066

0.85445

0.39476

2.17988

0.99983

0.89244

0.19619

2.08846

0.72333

0.61100

0.10670

1.44103

5.709

63.44

3

SIA

模拟各向同性退火

0.95784

0.84264

0.41465

2.21513

0.98239

0.79586

0.20507

1.98332

0.68667

0.49300

0.09053

1.27020

5.469

60.76

4

DE

差分进化

0.95044

0.61674

0.30308

1.87026

0.95317

0.78896

0.16652

1.90865

0.78667

0.36033

0.02953

1.17653

4.955

55.06

5

HS

谐声搜索

0.86509

0.68782

0.32527

1.87818

0.99999

0.68002

0.09590

1.77592

0.62000

0.42267

0.05458

1.09725

4.751

52.79

6

SSG

树苗播种和生长

0.77839

0.64925

0.39543

1.82308

0.85973

0.62467

0.17429

1.65869

0.64667

0.44133

0.10598

1.19398

4.676

51.95

7

(PO)ES

(PO) 进化策略

0.79025

0.62647

0.42935

1.84606

0.87616

0.60943

0.19591

1.68151

0.59000

0.37933

0.11322

1.08255

4.610

51.22

8

ACOm

蚁群优化 M

0.88190

0.66127

0.30377

1.84693

0.85873

0.58680

0.15051

1.59604

0.59667

0.37333

0.02472

0.99472

4.438

49.31

9

MEC

心智进化计算

0.69533

0.53376

0.32661

1.55569

0.72464

0.33036

0.07198

1.12698

0.52500

0.22000

0.04198

0.78698

3.470

38.55

10

IWO

入侵性杂草优化

0.72679

0.52256

0.33123

1.58058

0.70756

0.33955

0.07484

1.12196

0.42333

0.23067

0.04617

0.70017

3.403

37.81

11

COAm

布谷鸟优化算法 M

0.75820

0.48652

0.31369

1.55841

0.74054

0.28051

0.05599

1.07704

0.50500

0.17467

0.03380

0.71347

3.349

37.21

12

SDOm

螺旋动力学优化 M

0.74601

0.44623

0.29687

1.48912

0.70204

0.34678

0.10944

1.15826

0.42833

0.16767

0.03663

0.63263

3.280

36.44

13

NMm

Nelder-Mead 方法 M

0.73807

0.50598

0.31342

1.55747

0.63674

0.28302

0.08221

1.00197

0.44667

0.18667

0.04028

0.67362

3.233

35.92

14

FAm

萤火虫算法 M

0.58634

0.47228

0.32276

1.38138

0.68467

0.37439

0.10908

1.16814

0.28667

0.16467

0.04722

0.49855

3.048

33.87

15

GSA

重力搜索算法

0.64757

0.49197

0.30062

1.44016

0.53962

0.36353

0.09945

1.00260

0.32667

0.12200

0.01917

0.46783

2.911

32.34

16

ABC

人工蜂群

0.63377

0.42402

0.30892

1.36671

0.55103

0.21874

0.05623

0.82600

0.34000

0.14200

0.03102

0.51302

2.706

30.06

17

BFO

细菌觅食优化

0.54626

0.43533

0.31907

1.30066

0.41626

0.23156

0.06266

0.71048

0.35500

0.15233

0.03627

0.54360

2.555

28.39

18

BA

蝙蝠算法

0.59761

0.45911

0.35242

1.40915

0.40321

0.19313

0.07175

0.66810

0.21000

0.10100

0.03517

0.34617

2.423

26.93

19

SA

模拟退火

0.55787

0.42177

0.31549

1.29513

0.34998

0.15259

0.05023

0.55280

0.31167

0.10033

0.02883

0.44083

2.289

25.43

20

IWDm

智能水滴 M

0.54501

0.37897

0.30124

1.22522

0.46104

0.14704

0.04369

0.65177

0.25833

0.09700

0.02308

0.37842

2.255

25.06

21

PSO

粒子群优化

0.59726

0.36923

0.29928

1.26577

0.37237

0.16324

0.07010

0.60572

0.25667

0.08000

0.02157

0.35823

2.230

24.77

22

MA

猴子算法

0.59107

0.42681

0.31816

1.33604

0.31138

0.14069

0.06612

0.51819

0.22833

0.08567

0.02790

0.34190

2.196

24.40

23

SFL

蛙跳

0.53925

0.35816

0.29809

1.19551

0.37141

0.11427

0.04051

0.52618

0.27167

0.08667

0.02402

0.38235

2.104

23.38

24

FSS

鱼群搜索

0.55669

0.39992

0.31172

1.26833

0.31009

0.11889

0.04569

0.47467

0.21167

0.07633

0.02488

0.31288

2.056

22.84

25

RND

随机

0.52033

0.36068

0.30133

1.18234

0.31335

0.11787

0.04354

0.47476

0.25333

0.07933

0.02382

0.35648

2.014

22.37

26

GWO

灰狼优化器

0.59169

0.36561

0.29595

1.25326

0.24499

0.09047

0.03612

0.37158

0.27667

0.08567

0.02170

0.38403

2.009

22.32

27

CSS

收费系统搜索

0.44252

0.35454

0.35201

1.14907

0.24140

0.11345

0.06814

0.42299

0.18333

0.06300

0.02322

0.26955

1.842

20.46

28

EM

类电磁算法

0.46250

0.34594

0.32285

1.13129

0.21245

0.09783

0.10057

0.41085

0.15667

0.06033

0.02712

0.24412

1.786

19.85


排位表格

图例 3. 算法的颜色渐变是根据相关测试

图表

图例 4. 算法测试结果的直方图(标尺从 0 到 100,越多越好,

其中 100 是最大可能的理论结果(存档提供了一个用于计算评级表格的脚本)。


5. 总结

进化策略的运用为各个领域开辟了新的可能性,包括机器学习中的参数优化、机器人设计和复杂系统的控制。它们令我们能够基于进化的生物学原理获得更好的解决方案。

目前,我们在积分榜上有一位无可争议的新领导者,领先于其最接近的竞争对手 SDSm 近 10%。


(μ,λ)-ES 算法的优点和缺点:

优势:
  1. 少量外部参数。
  2. 高效解决各种问题。
  3. 易于实现。
  4. 抗粘连性。
  5. 在平滑和复杂的离散函数上都有可喜的结果。
  6. 高收敛性。
缺点:
  1. 离散函数上的大量结果分散。

(μ+λ)-ES 算法的优点和缺点:

优势:
  1. 少量外部参数。
  2. 高效解决各种问题。
  3. 易于实现。
  4. 抗粘连性。
  5. 在平滑和复杂的离散函数上都有可喜的结果。
  6. 高收敛性。
缺点:
  1. 离散函数上的结果大量分散(尽管这些是目前最好的结果)。

本文附有一个存档,其中包含前几篇文章中讲述的算法代码的当前更新版本。文章作者不对规范算法讲述的绝对准确性负责。对其中进行了多处修改,从而提升搜索能力。文章中表述的结论和论断是基于实验的结果。

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/13923

附加的文件 |
为 Metatrader 5 开发 MQTT 客户端:TDD 方法 - 第 5 部分 为 Metatrader 5 开发 MQTT 客户端:TDD 方法 - 第 5 部分
本文是系列文章的第五部分,介绍了我们为 MQTT 5.0 协议开发本地 MQL5 客户端的步骤。在这一部分中,我们将介绍 PUBLISH 数据包的结构、如何设置其发布标志(Publish Flag)、如何对主题名称(Topic Name)字符串进行编码,以及在需要时如何设置数据包标识符(Packet Identifier)。
数据科学和机器学习(第 17 部分):摇钱树?外汇交易中随机森林的艺术与科学 数据科学和机器学习(第 17 部分):摇钱树?外汇交易中随机森林的艺术与科学
探索算法炼金术的秘密,我们将引导您融会贯通如何在解码金融领域时将艺术性和精确性相结合。揭示随机森林如何将数据转化为预测能力,为驾驭股票市场的复杂场景提供独特的视角。加入我们的旅程,进入金融魔法的心脏地带,此处我们会揭开随机森林在塑造市场命运、及解锁赚钱机会之门方面之角色的神秘面纱
新手在交易中的10个基本错误 新手在交易中的10个基本错误
新手在交易中会犯的10个基本错误: 在市场刚开始时交易, 获利时不适当地仓促, 在损失的时候追加投资, 从最好的仓位开始平仓, 翻本心理, 最优越的仓位, 用永远买进的规则进行交易, 在第一天就平掉获利的仓位,当发出建一个相反的仓位警示时平仓, 犹豫。
用于时间序列挖掘的数据标签(第 5 部分):使用 Socket 在 EA 中进行应用和测试 用于时间序列挖掘的数据标签(第 5 部分):使用 Socket 在 EA 中进行应用和测试
本系列文章介绍了几种时间序列标注方法,可以创建符合大多数人工智能模型的数据,根据需求有针对性地进行数据标注,可以使训练出来的人工智能模型更符合预期设计,提高我们模型的准确性,甚至帮助模型实现质的飞跃!