【问题标题】:Gradually increase the probability of mutation逐渐增加变异的概率
【发布时间】:2013-12-03 06:01:08
【问题描述】:

我正在实现与遗传算法非常相似的东西。所以你经历了多代种群——在一代结束时,你以三种不同的方式“随机”、“突变”和“交叉”创建一个新种群。

目前概率是静态的,但我需要做到这一点,以便突变的概率逐渐增加。我很感激任何方向,因为我有点卡住了..

这就是我所拥有的:

int random = generator.nextInt(10);
if (random < 1)  
    randomlyCreate() 
else if (random > 1 && random < 9 )
    crossover(); 
else  
    mutate();

谢谢。

【问题讨论】:

  • 您在这种情况下使用的 1 和 9 可以设置为每次调用操作时都会更改的变量。分配初始值 random = 1,crossover = 9,也许每 10 次迭代,将 crossover 减 1,直到达到您的首选值。

标签: java genetic-algorithm probability-theory mutation


【解决方案1】:

在你的 if 语句中,用变量替换硬编码的数字,并在每一代开始时更新它们。

您的 if 语句有效地将区间 0 到 10 分成三个箱。调用 mutate() vs crossover() vs randomlyCreate() 的概率取决于每个 bin 的大小。您可以通过逐渐移动 bin 的边界来调整突变率。

在您的代码中,mutate() 在 20% 的时间被调用(当 random = 9 或 1 时),randomlyCreate() 在 10% 的时间被调用(当 random = 0 时)并且crossover() 被调用其他 70% 的时间。

下面的代码在第 0 代开始时具有相同的比率,但突变率每代增加 1%。所以第 1 代的突变率为 21%,第 2 代的突变率为 22%,以此类推。无论突变率如何,randomlyCreate() 被称为 crossover() 的频率是 1 / 7。

您可以通过更改 getMutationBoundary() 来使突变率的增加呈二次方、指数或您选择的任何形式。

我在下面的代码中使用了浮点数。双打也可以。

如果您最感兴趣的是突变率,则移动突变箱使其最初位于 [0, 2] 可能更直观,然后从那里增加其上边界 (2.1, 2.2,等等)。然后您可以轻松读取突变率(21%、22% 等)。

void mainLoop() {
    // make lots of generations
    for (int generation = 0; generation < MAX_GEN; generation++) {
        float mutationBoundary = getMutationBoundary(generation);   
        float creationBoundary = getCreationBoundary(mutationBoundary);
        createNewGeneration(mutationBoundary, creationBoundary);
        // Do some stuff with this generation, e.g. measure fitness
    }
}

void createNewGeneration(float mutationBoundary, float creationBoundary) {
    // create each member of this generation
    for (int i = 0; i < MAX_POP; i++) {
        createNewMember(mutationBoundary, creationBoundary);
    }
}

void createNewMember(float mutationBoundary, float creationBoundary) {
    float random = 10 * generator.nextFloat();

    if (random > mutationBoundary) {
        mutate();
    }
    else {
        if (random < creationBoundary) {
            randomlyCreate();
        }
        else {
            crossover();
        }
    }
}

float getMutationBoundary(int generation) {
    // Mutation bin is is initially between [8, 10].
    // Lower bound slides down linearly, so it becomes [7.9, 10], [7.8, 10], etc.
    // Subtracting 0.1 each generation makes the bin grow in size.
    // Initially the bin is 10 - 8 = 2.0 units wide, then 10 - 7.9 = 2.1 units wide,
    // and so on. So the probability of mutation grows from 2 / 10 = 20%
    // to 2.1 / 10 = 21% and so on.
    float boundary = 8 - 0.1f * generation;

    if (boundary < 0) {
        boundary = 0;
    }
    return boundary;    
}

float getCreationBoundary(float creationBoundary) {
    return creationBoundary / 8; // fixed ratio
}

【讨论】:

  • 抱歉,这是一个愚蠢的问题。为什么在 getMutationBoundary 方法中减去 0.1?另外,你为什么选择使用浮动?我可以用 double 代替吗?
  • 请参阅getMutationBoundary() 中的新 cmets,了解我为什么要减去 0.1。如果您愿意,可以使用双打。更新答案以提及这一点。
【解决方案2】:

在您当前使用9 的地方使用一个变量,并且(例如)将其乘以0.9 每次迭代,除非mutate() 发生,在这种情况下您将它乘以3。这样,突变的机会会缓慢但呈指数增长(是的,这是可能的),直到它们真正发生突变,此时另一个突变的机会像砖头一样下降,整个过程重新开始。

这些值是完全随机的,并且不基于任何关于突变的知识,但我只是向您展示如何操纵它以使每次都具有可变值。另外:如果你使用我刚刚使用的,请确保变量的值设置为 10,如果它超过 10。

【讨论】:

    【解决方案3】:

    对算子的遗传概率的任何选择都是任意的(如果您使用某些函数来增加或减少概率,这也是有效的)。最好在染色体内编码运算符。例如,您可以添加一些位来编码您使用的所有运算符。生成子代时,您会查看总体中所有元素的这些位,并以与全局考虑的整个总体中运算符的当前情况相等的概率应用运算符。

    例如:

    void adaptive_probabilities(GA *ga, long chromosome_length) {
        register int i, mut = 1, xover = 1, uxover = 1, ixover = 1, pop;
        char bit1, bit2;
    
        for (i = 0; i < ga->npop; i++) {
            bit1 = ga->pop[i]->chromosome[chromosome_length - 2];
            bit2 = ga->pop[i]->chromosome[chromosome_length - 1];
    
            if (bit1 == '0' && bit2 == '0') {
                mut++;
            } else if (bit1 == '0' && bit2 == '1') {
                xover++;
            } else if (bit1 == '1' && bit2 == '0') {
                uxover++;
            } else if (bit1 == '1' && bit2 == '1') {
                ixover++;
            }
        }
    
        pop = ga->npop + 4;
    
        ga->prob[0] = mut / (float)pop;
        ga->prob[1] = xover / (float)pop;
        ga->prob[2] = uxover / (float)pop;
        ga->prob[3] = ixover / (float)pop;
    }
    

    在我的例子中,我使用两个位,因为我的染色体编码为四个运算符(三种类型的交叉 + 突变)。运算符位位于染色体末端。所有概率都 > 0(运算符的计数器从 1 开始),然后我必须正确规范化所有概率

    pop = ga->npop + 4;
    

    然后,我根据保存在数组 ga->prob 中的计算概率生成一个随机数,用于选择运算符。新子元素的最后一位被更改以反映所使用的运算符。

    这种机制确保了 GA 的双重搜索:在错误空间(像往常一样)和运算符空间。概率会自动变化并得到优化,因为在计算的任何时刻使用最佳运算符以更高的概率生成子​​节点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-11
      • 2016-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多