【问题标题】:What is the best way to perform vector crossover in genetic algorithm?在遗传算法中执行向量交叉的最佳方法是什么?
【发布时间】:2011-11-08 23:28:06
【问题描述】:

我正在使用遗传算法“学习”选秀/跳棋 AI 的最佳参数。这个参数存储在一个双精度向量中。

[x1 x2 x3 x4 x5 x6 x7 x8 x9]

实际上我使用两种简单的方法进行交叉:一点交叉和两点交叉。不幸的是,在我看来,这种方法还不够好。

例如,如果我有一个基因库:

[10 20 1]
[30 10 9]
[100 1 10]

如果 x1 值的理论最优值为 50,我永远无法通过交叉找到它。我唯一的希望是产生一个 x1=50 的突变,足以传给下一代。

那么,有没有更好的方法来执行与数字数组的交叉?

【问题讨论】:

    标签: artificial-intelligence machine-learning genetic-algorithm


    【解决方案1】:

    存在大量可能的交叉(和突变),关于它的文献几乎是无限的。如果您希望使用该表示(双精度向量),那么您可能需要查看模拟二元交叉混合交叉高斯突变运营商,他们很可能会帮助您找到与父母基因混合的孩子,而不是简单的交换。

    例如,带有eta = 0.5 的模拟二进制文件将给出(隐含的随机化)来自这两个父母

    [30 10 9]
    [100 1 10]
    

    两个孩子

    [52 8 9]
    [77 2 10]
    

    据我所知,几乎所有主要的 EC 框架都实现了这些运算符(Open Beagle、ECJ、DEAP、EO 等)

    【讨论】:

    • 谢谢。我从来没有听说过这些运营商。 :D 我要搜索更多关于他们的信息。
    【解决方案2】:

    我的 GA 中的交叉算法与您使用的不同——不是更好,只是不同。总之,我将 crossover 编码为数组拼接/连接操作,而不是替换,其中拼接点是随机的(并且也是“同步的”,因此当两个拼接点部分被组装成与每个父级相同长度的子向量。

    我觉得用代码解释起来要容易得多:

    DOMAIN_LENGTH = 14
    
    def crossover(v1, v2):
        crossover_point = random.randint(1, DOMAIN_LENGTH-2)
        return v1[:crossover_point] + v2[crossover_point:]
    
    # create a simple function to generate a couple of 'parent' vectors
    >>> fnx = lambda v : [random.choice(range(10)) for c in range(DOMAIN_LENGTH)]
    
    # now generate those parent vectors
    >>> v1 = fnx(DOMAIN_LENGTH)
    >>> v2 = fnx(DOMAIN_LENGTH)
    >>> v1
      [7, 9, 5, 6, 6, 7, 6, 9, 8, 6, 6, 4, 5, 8]
    >>> v2
      [2, 2, 9, 7, 1, 4, 6, 9, 0, 7, 1, 9, 3, 0]
    >>> len(v1); len(v2)
      14
      14
    
    # create the child vector via crossover
    >>> child_01 = crossover(v1, v2)
    >>> child_01
      [7, 9, 9, 7, 1, 4, 6, 9, 0, 7, 1, 9, 3, 0]
    >>> len(child_01)
      14
    

    所以:

    • 域大小(向量长度)为 5
    • *crossover_point* 为 2,而 t
    • 他的两个父向量是[4, 3, 2, 4, 8]和[1, 3, 1, 6, 3]

    然后:

    # fragment contributed from first parent:
    >>> f1 = p1[:2]
    >>> f1
      [4, 3]
    
    # fragment contributed from second parent:
    >>> f2 = p2[2:]
    >>> f2
      [1, 6, 3]
    
    # now just concatenate the two fragments to produce the child fragment
    >>> child = f1 + f2
    >>> child
      [4, 3, 1, 6, 3]
    >>> len(child) == len(p2)
      True
    

    【讨论】:

      【解决方案3】:

      您似乎遇到了编码问题,而不是交叉问题。如果您想要染色体的更多可变性 - 然后将数据编码为字节序列(甚至位)。 假设你有 3 个整数参数,那么你可以将它们表示为 3*4=12 字节向量:

      {114,2,0,214, // first 32-bit int
      14,184,220,7, // second 32-bit int
      145,2,32,12,  // etc...
      }
      

      那么在交叉之后,你的 int 将以很大的可变性进化。您也可以不使用 1/2 点交叉,而是 uniform crossover - 当在每个染色体点时,您将随机决定您将使用的基因版本。在这种情况下,您将获得更多的可变性。但请记住,交叉中的太多可变性也是灾难性的,因为会导致种群可能永远无法达到最优解,因为即使是次优解也会被交叉操作中的大随机波动撕裂。 稳定进化是这里的主要关键词。

      另一种方法 - 不是使用遗传算法,而是使用evolution strategy algorithms 改变染色体中的所有基因。但如果不同基因版本的数量不是很大,这种方法是可行的。所以这可能不适合你的浮点数/双精度问题。

      HTH!

      【讨论】:

      • 你的回答很有趣。非常感谢。我会尝试一些实验。 :)
      • "...将数据编码为字节序列(甚至位)..." 并强烈考虑使用格雷码 (en.wikipedia.org/wiki/Gray_code),以便突变不会导致大的表型变化。
      【解决方案4】:

      这真的取决于适应度函数如何。在交叉中,您还可以对这些值进行平均(同样,如果它对适应度函数有意义),但这可能会导致算法太容易收敛到具有非常相似个体的群体。

      我认为这是应该将单个值推向最佳值的突变,如果由于交叉而无法获得它,您应该因为突变而获得 50。

      考虑对单个个体进行某种局部搜索(模因算法)。

      【讨论】:

      • 你能解释一下适应度函数是如何参与交叉的吗?我没有看到连接——交叉创建(一些)候选解决方案,并且适应度函数评估它们。其次,我也看不出变异在这里有什么相关性——变异只是 GA 中用于创建候选解决方案的一种单独机制。
      • 我的适应度函数在这个问题上有点问题。没有办法获得选秀 AI 的绝对适应度值 :) 所以我使用池中 AI 之间选秀循环赛的获胜次数。这是一个相对适应度函数,但每篇关于此的论文都说它是可用于草稿学习任务的最佳适应度函数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-12
      • 2016-08-31
      • 2021-02-07
      • 1970-01-01
      • 2012-06-02
      • 2015-09-21
      相关资源
      最近更新 更多