【问题标题】:Genetic algorithm initial seed diversity using value encoding C#使用值编码 C# 的遗传算法初始种子多样性
【发布时间】:2012-09-14 09:48:23
【问题描述】:

我想知道以下内容: 如何使用值编码有效地生成具有高多样性的染色体? 一种方法是网格初始化,但是太慢了。

到目前为止,我一直在使用 .NET 中的 Random 类在值编码中选择随机值,但是,尽管值是均匀分布的,但从这些染色体计算出的适应度函数值却不是。这是染色体初始化的代码:

 public Chromosome(Random rand) 
        {
            Alele = new List<double>();
            for (int i = 0; i < ChromosomeLength; i++)
            {
                Alele.Add(rand.NextDouble() * 2000 - 1000);
            }
        }

所以,我开发了一个函数,可以从新的、随机生成的染色体(上面的代码)计算适应度,如果适应度与染色体列表中已经存在的任何其他染色体相似,则随机生成一个新染色体并计算他的适应度,然后这个重复该过程,直到他的适应度与列表中的适应度相差不大。

这是这部分的代码:

private bool CheckSimilarFitnes(List<Chromosome> chromosome, Chromosome newCandidate) 
    {
     Boolean flag=false;
     double fitFromList, fitFromCandidate;
     double fitBigger,fitSmaller;

     foreach (var listElement in chromosome)
      {  
      fitFromList = listElement.CalculateChromosomeFitness(listElement.Alele);
      fitFromCandidate = newCandidate.CalculateChromosomeFitness(newCandidate.Alele);
      fitBigger = fitFromList >= fitFromCandidate ? fitFromList : fitFromCandidate;
      fitSmaller =  fitFromList < fitFromCandidate ? fitFromList : fitFromCandidate;

            if ((fitFromList / fitFromCandidate) < 1.5) 
                return false
      }

     else return true;

    }

但是,我在列表中拥有的染色体越多,添加一个新染色体的时间就越长,其适应度与已有的其他染色体有足够的不同。

那么,有没有办法让这个网格初始化更快,制造这样的 80 条染色体需要几天时间?

【问题讨论】:

  • 问:我不明白。标准.Net“Random()”到底有什么问题?只是默认种子(滴答声)?问:这个链接有帮助吗:matthewlynch.net/dotnet/good-seed-for-random
  • 不是种子,问题是我必须制造染色体,然后检查它们的适应度。如果它与列表中已经存在的染色体(适应度)过于相似,则重复创建新染色体的过程,直到它的适应度 id 足够不同。但这需要很长时间,所以我的问题是有没有更快的方法来使初始种子多样化?
  • 问:这会给你带来更好的东西吗:Random random = new Random(Guid.NewGuid().GetHashCode());

标签: c# algorithm grid initialization genetic


【解决方案1】:

这里有一些可能有帮助的代码(我刚刚写的):GA for ordering 10 values spaced by 1.0。它从 100 个完全随机的等位基因群开始,这正是您的代码开始的方式。

我给 GA 解决的目标是以 1.0 的间隔按升序排列值。它在适应度函数Eval_OrderedDistance 中通过计算每对样本与 1.0 的标准差来实现这一点。随着适应度趋于 0.0,等位基因应该开始按顺序出现。

第 0 代最适合的染色体是完全随机的,其他染色体也是如此。您可以看到适应度值非常高(即差):

GEN: fitness   (allele, ...)
  0: 375.47460 (583.640, -4.215, -78.418, 164.228, -243.982, -250.237, 354.559, 374.306, 709.859, 115.323) 

随着世代的继续,适应度(从 1.0 的标准差)下降,直到在第 100,000 代时几乎完美:

  100: 68.11683 (-154.818, -173.378, -170.846, -193.750, -198.722, -396.502, -464.710, -450.014, -422.194, -407.162)
  ...
10000:  6.01724 (-269.681, -267.947, -273.282, -281.582, -287.407, -293.622, -302.050, -307.582, -308.198, -308.648)
  ...
99999:  0.67262 (-294.746, -293.906, -293.114, -292.632, -292.596, -292.911, -292.808, -292.039, -291.112, -290.928)

代码中有趣的部分是适应度函数:

// try to pack the aleles together spaced apart by 1.0
// returns the standard deviation of the samples from 1.0
static float Eval_OrderedDistance(Chromosome c) {
    float sum = 0;
    int n = c.alele.Length;
    for(int i=1; i<n; i++) {
        float diff = (c.alele[i] - c.alele[i-1]) - 1.0f; 
        sum += diff*diff; // variance from 1.0
    }

    return (float)Math.Sqrt(sum/n);
}

还有突变。我使用了一个简单的交叉和“完全突变一个等位基因”:

Chromosome ChangeOne(Chromosome c) {
    Chromosome d = c.Clone();
    int i = rand.Next() % d.alele.Length;
    d.alele[i] = (float)(rand.NextDouble()*2000-1000);
    return d;
}

我使用精英主义来始终保留一份最佳染色体的精确副本。然后使用突变和交叉生成 100 条新染色体。

听起来您确实在计算适应度的方差,这当然会告诉您总体中的适应度几乎相同。我发现如何定义适应度函数非常很重要。适应度函数越精细,您就越能区分染色体。显然,您的适应度函数为完全不同的染色体返回相似的值,因为您的第 0 代返回的适应度方差为 68e-19。

你能分享你的健身计算吗?或者您要求 GA 解决什么问题?我认为这可能会对我们有所帮助。

[编辑:添加明确的健身分享/Niching]

我重新考虑了一下,updated my code。如果你想保持独特的染色体,你必须比较它们的内容(正如其他人提到的那样)。一种方法是计算它们之间的标准偏差。如果它小于某个阈值,则可以将它们视为相同。来自染色体类:

// compute the population standard deviation
public float StdDev(Chromosome other) {
    float sum = 0.0f;
    for(int i=0; i<alele.Length; i++) {
        float diff = other.alele[i] - alele[i];
        sum += diff*diff;
    }
    return (float)Math.Sqrt(sum);
}

我认为 Niching 会给你你想要的。它比较群体中的所有染色体以确定它们的相似性,并为每个染色体分配一个“利基”值。然后使用一种称为“显式健身共享”的技术对染色体进行“惩罚”,因为它们属于某个生态位。适应度值除以每个生态位中的染色体数量。因此,如果您在利基组 A (A,A,A) 中有三个而不是该利基被选择的可能性是其 3 倍,则它被视为单个实体。

我比较了我的样本与 Explicit Fitness Sharing 的开启和关闭。最大 STDDEV 为 500 且 Niching 关闭时,大约有 18-20 个壁龛(所以基本上 100 人口中每个项目有 5 个重复)。启用 Niching 后,大约有 85 个壁龛。那是人口中 85% 的独特染色体。在我的测试输出中,您可以看到diversity after 17000 generations

这是利基代码:

// returns: total number of niches in this population
// max_stddev -- any two chromosomes with population stddev less than this max
//               will be grouped together
int ComputeNiches(float max_stddev) {
    List<int> niches = new List<int>();

    // clear niches
    foreach(var c in population) {
        c.niche = -1;
    }

    // calculate niches
    for(int i=0; i<population.Count; i++) {
        var c = population[i];
        if( c.niche != -1) continue; // niche already set

        // compute the niche by finding the stddev between the two chromosomes 
        c.niche = niches.Count;
        int count_in_niche = 1; // includes the curent Chromosome
        for(int j=i+1; j<population.Count; j++) {
            var d = population[j];
            float stddev = c.StdDev(d);
            if(stddev < max_stddev) {
                d.niche = c.niche; // same niche
                ++count_in_niche;
            }
        }
        niches.Add(count_in_niche);
    }

    // penalize Chromosomes by their niche size
    foreach(var c in population) {
        c.niche_scaled_fitness = c.scaled_fitness / niches[c.niche];
    }

    return niches.Count;
}

[编辑:Anton 代码的后期分析和更新]

我知道这可能不是解决家庭作业问题的正确论坛,但由于我在知道这一点之前就做了努力,而且我从中获得了很多乐趣,我认为它只会对 Anton 有所帮助。

Genotip.csKromosom.csKromoMain.cs

此代码保持良好的多样性,我能够在一次运行中将“原始适应度”降至 47,在您的情况下,这是平均平方误差。那是相当接近!

正如我在评论中提到的,我想尝试帮助您进行编程,而不仅仅是帮助您完成作业。请阅读这些对您工作的分析。

  1. 正如我们所料,没有必要从一开始就制造“更加多样化”的人口。只需生成一些完全随机的 Kromosomes。

  2. 你的突变和交叉具有很强的破坏性,而你只有其中的几个。我添加了几个似乎更适合解决此问题的新运算符。

  3. 您放弃了最佳解决方案。当我让您的代码仅使用 Tournament Selection 运行时,将会有一个 Kromo 比其他所有的要好 99%。通过锦标赛选择,这个最佳价值很可能被遗忘。我添加了一些“精英主义”,为下一代保留了该价值的副本。

  4. 考虑面向对象的技术。将我发送给您的重写代码与我的原始代码进行比较。

  5. 不要重复代码。您有两个不同类别的采样参数。

  6. 保持代码干净。有几个未使用的代码部分。尤其是在向 SO 提交问题时,尽量缩小范围,删除未使用的代码,并进行一些清理。

  7. 评论您的代码!我对重做的工作发表了重要的评论。我知道这是塞尔维亚语,但即使是几个 cmets 也会帮助其他人了解您在做什么以及您打算做什么。

  8. 总体而言,很好地实现了一些更复杂的功能,例如锦标赛选择

  9. 更喜欢 double[] 数组而不是 List。开销更少。此外,甚至不需要您的几个 List 临时变量。你的结构

    列表温度 = 新列表(); 为了(...) { temp.add(值); } for(temp 中的每个值) { 总和 += 值 } 平均值 = sum / temp.Count

可以很容易地写成:

sum = 0
for(...) {
    sum += value;
}
average = sum / count;
  1. 在几个地方,您忘记初始化循环变量,这很容易添加到您的问题中。这样的事情会导致严重的问题,并且它在您的 fitness 代码以及其他一两个地方

    双重拟合 = 0; 对于(每条染色体){ // 你应该初始化适合这里 inside 循环 对于(每个等位基因){ 适合 += ...; } 适合/=计数; }

祝你编程好运!

【讨论】:

  • 更新了利基,这听起来像是您正在尝试做的事情。干杯。
  • 这里有很多好东西。我认为 OP 仍在努力解决初始种群中应该解决的问题与算法本身的问题。
  • @cod3monk3y - 非常感谢,你有什么建议,你能看看我的源代码吗? pastebin.com/D4RvKMHq
  • 我会将我的适应度函数放在你的代码中的什么位置,看看这是否有效?你能看看吗,拜托。谢谢
  • 你能告诉我逆最小二乘法是一个很好的多项式系数计算的拟合函数吗?你在我的源代码中以 RacunajFunkcijuFitnesa() 为名。
【解决方案2】:

这里的基本问题是大多数随机生成的染色体具有相似的适应度,对吧?没关系;这个想法并不是让您的初始染色体具有截然不同的适应度;这是因为染色体本身不同,而且可能它们是不同的。事实上,您应该期望大多数第一代的初始适应度接近于零,因为您还没有运行算法。

这就是您的代码如此缓慢的原因。假设第一个候选人很糟糕,基本上是零适应度。如果第二个必须有 1.5 倍的不同,那真的只是意味着它必须要好 1.5 倍,因为它不会变得更糟。然后下一个必须比那个好 1.5 倍,以此类推到 80 倍。所以你真正要做的是通过生成完全随机的染色体并将它们与你的染色体进行比较来寻找越来越好的染色体有。我敢打赌,如果您记录进度,您会发现找到后续候选者需要越来越多的时间,因为很难找到真正好的染色体。但是寻找更好的染色体是 GA 的目的!基本上你之前所做的就是手动优化一些染色体,嗯,实际上是优化它们。

如果您想确保您的染色体是多样化的,请比较它们的内容,而不是比较它们的适合度。比较适应度是算法的工作。

【讨论】:

  • +1。与我的“鸽子洞”相比,我更喜欢你的解释 - 与算法更相关。
  • +1。这个问题实际上非常广泛,我想知道它是否有答案。本质上,OP 是在询问如何编写适当的遗传算法。我建议AI Techniques for Game Programmers by Mat Buckland。这是一个非常容易理解的文本,包含大量关于健身缩放、变异和压力的信息。 (注意:我与这本书没有任何关系。几年前我只是发现它作为介绍性文本非常有用)
  • 你说得对,我的代码正在“手动”优化初始人口或初始人口。但是在一件事上你错了,随机创建的染色体,确实具有相似的适应度,不能在下一代中创造任何新的东西(使用蒙面的统一交叉)。所以我需要一种方法来制作更具多样性的初始种子。正如所有 GA 文献中所说,如果初始种子没有足够的多样性,算法就会过早收敛。
  • 顺便说一下,我使用的是 5% 的突变率、均匀交叉和概率二元锦标赛。
  • @artun 多样性很重要,否则你最终会达到局部最大值。但不是 fitness 的多样性。适合度是对染色体“好”程度的衡量,而不是关于它的任何定性。拥有多样化的健身对 GA 根本没有帮助,因为它的主要工作是促进更高的健身。如果您的初始染色体范围从不适合到适合,您认为哪个会被 GA 提升?它打败了整个观点。
【解决方案3】:

我要快速解决这个问题,但 Isaac 说的很对。您需要让 GA 完成其工作。你有一代人(染色体,等等),而且他们的健康水平都在范围内(或者也许他们都是相同的)。

你选择一些好的来变异(自己)和交叉(彼此)。您可能会使用前 10% 来生成另一个完整的人口,并丢弃底部的 90%。也许你总是把头号人物留在身边(精英主义)。

您在此重复一段时间,直到您的 GA 停止改进,因为每个人都非常相似。最终你的人口中几乎没有多样性。

可能对您有所帮助的是 1) 使您的突变更有效,2) 找到更好的方法来选择个体进行突变。在我的评论中,我推荐了AI Techniques for Game Programmers。这是一本很棒的书。非常容易阅读。

要列出书中的几个标题,您要查找的内容是:

选择技术,如Roulette Selection (on stackoveflow)(在wikipedia)和Stochastic Universal Sampling,它们控制如何选择你的个人。我一直很喜欢轮盘赌选择。您设置个人被选中的概率。这不仅仅是简单的白噪声随机采样。

我在 GA 之外使用它从罗马字母中随机选择 4 个字母。我为每个字母分配了一个从 0.0 到 1.0 的值。每次用户(孩子)正确选择字母时,我都会将该值降低,例如 0.1。这将增加选择其他字母的可能性。如果 10 次后,用户选择了正确的字母,则该值为 0.0,并且(几乎)没有机会再次显示该字母。

Fitness Scaling 技术,如 Rank Scaling、Sigma Scaling 和 Boltzmann Scaling (pdf on ftp!!!),可让您修改原始健身值以得出调整后的健身值。其中一些是动态的,例如玻尔兹曼缩放,它允许您设置随时间变化的“压力”或“温度”。增加的“压力”意味着选择了更健康的个体。压力降低意味着可以选择人群中的任何个体。

我是这样想的:您正在多维空间中寻找解决方案。你达到了一个“高峰”并努力进入它。适合的压力非常大。你紧贴当地的最大值。现在你的体能不能改变。你的突变不会让你走出高峰。所以你开始减少压力,哦,随机选择项目。你的健康水平开始下降,这在一段时间内是可以的。然后你又开始增加压力,惊喜!您已经跳过了局部最大值,并找到了一个可爱的新局部最大值。再次加大压力!

Niching(我从未使用过,但似乎是一种将相似个体组合在一起的方式)。假设你有两个非常好的人,但他们完全不同。他们不断被选中。他们不断地发生轻微的变异,并没有变得更好。现在你有一半的人口是 A 的次要变体,一半的人口是 B 的次要变体。这似乎是一种说法,嘿,整个 A 组的平均适应度是多少? B呢?以及您拥有的所有其他利基市场。然后根据每个利基的平均适应度进行选择。选择您的利基市场,然后从该利基市场中随机选择一个人。也许我会开始使用它。我喜欢!

希望对您有所帮助!

【讨论】:

  • 谢谢你的链接,我一定会看看,但这不是我的问题。我必须找出如何制作具有更多多样性的初始种子。我现在这样做的方式在第一篇文章中显示并且太慢了,还有其他方法吗?
  • 您所指的文献中的多样性可能意味着个体之间相关性的多样性。我认为您将健身与多样性混为一谈。在您发布的照片​​中,前两个 Alele 之间的相关性为 0.1,非常低(即高度多样性)。可以发一下你的健身码吗?你有多少条染色体?几代?这张图是哪一代的? 100代后能发截图吗?
  • 在此处,您可以进行:80染色体 - 1.生成方差= 68.405597402411193E-19 2.生成方差= 3.3390292462201335E-19之后100代= 0.000000000000000000013084417866801596在100 000世代Fitness之后= 0.7569107832092211e-19之后000 = 6.6447231810762E-19
  • 这就是适应度的方差?我需要查看您的体能计算,以便进一步帮助您。我已经发布了一些示例代码(第二个答案)可能对您有所帮助,它使用您的设置解决了一个问题,而无需付出任何额外的努力来确保新染色体是唯一的。
  • 这是我的完整源代码:pastebin.com/D4RvKMHq 我要感谢您的努力,如果我们解决了这个问题,我会给您我的绿色粗标记 :-) 调用 fitnes 的函数: RacunajFunkcijuFitnesa();
【解决方案4】:

如果您的应用程序需要 true 随机数,我建议您查看Random.org。他们有一个免费的 HTTP API 和clients for just about every language

随机性来自大气噪声,在许多方面它比计算机程序中通常使用的伪随机数算法要好。

(我与 Random.org 无关,尽管我确实贡献了 PHP 客户端)。

【讨论】:

  • 我不认为 OP 抱怨他的数字不够随机。
  • 是的,Isaac,你是莱特,我的数字确实需要价值的多样性,而不是适合度。但是感谢您的贡献
【解决方案5】:

我认为您的问题在于您的适应度函数和选择候选人的方式,而不是随机值的方式。您的过滤感觉过于严格,甚至可能不允许接受足够的元素。

样本

  • 值:随机浮点数 0-10000。
  • 适应度函数平方根(n)
  • 所需的适应度分布 - 与距离至少为 1 的线性关系。

使用此健身功能,您将很快获得大部分 1 宽“点”(因为您最多有 100 个位置),因此每个下一个都需要更长的时间。在某些时候,会留下几个很小的范围,并且大多数结果都会被拒绝,更糟糕的是,在您获得大约 50 个数字位置之后,下一个数字很可能根本无法拟合。

【讨论】:

  • 是的,你是莱特,那么你有什么建议,如何计算不同的多样性?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-04
  • 1970-01-01
  • 2015-07-26
  • 1970-01-01
  • 1970-01-01
  • 2020-07-11
  • 2019-02-15
相关资源
最近更新 更多