【问题标题】:Java and Increasing the Efficiency of Genetic AlgorithmsJava 和提高遗传算法的效率
【发布时间】:2011-06-08 04:55:53
【问题描述】:

我想知道是否可以就提高实现遗传算法的程序的整体效率获得一些建议。是的,这是一个作业问题,但我已经自己完成了作业,我只是在寻找一种让它表现更好的方法 Problem Description

目前我的程序读取由成分类型 h 或 p 组成的给定链。 (例如:hphpphhphpphphhpphph)对于每个 H 和 P,它生成一个随机移动(上、下、左、右)并将该移动添加到包含在“染色体”对象中的 arrayList 中。开始时,程序为 10,000 条染色体生成 19 次移动

   SecureRandom sec = new SecureRandom();
    byte[] sbuf = sec.generateSeed(8);
    ByteBuffer bb = ByteBuffer.wrap(sbuf);
    Random numberGen = new Random(bb.getLong());
    int numberMoves = chromosoneData.length();
    moveList = new ArrayList(numberMoves);
    for (int a = 0; a < numberMoves; a++) {
        int randomMove = numberGen.nextInt(4);
        char typeChro = chromosoneData.charAt(a);
        if (randomMove == 0) {
            moveList.add(Move.Down);
        } else if (randomMove == 1) {
            moveList.add(Move.Up);
        } else if (randomMove == 2) {
            moveList.add(Move.Left);
        } else if (randomMove == 3) {
            moveList.add(Move.Right);
        }

    }

之后是从种群中选择要交叉的染色体。我的交叉函数从最适合的 20% 的人群中随机选择第一个染色体,从前 20% 之外的人群中随机选择另一个。然后将选择的染色体交叉并调用突变函数。我相信我受到最大打击的领域是计算每个染色体的适应度。目前我的适应度函数创建一个二维数组作为网格,从上面显示的函数生成的移动列表中按顺序放置移动,然后循环遍历数组以进行适应度计算。 (IE 找到并且位置 [2,1] 的 H 是 Cord [1,1] [3,1] [2,0] 或 [2,2] 也是一个 H,如果找到一个 H,它只会增加找到债券)

计算完成后,从我的种群中删除最不适合的染色体并添加新的染色体,然后对染色体的数组列表进行排序。冲洗并重复,直到找到目标溶液

如果你们想看更多我的代码来证明我在寻求帮助之前确实做了这项工作,请告诉我(不想发太多帖子,所以其他学生不能只是复制我的东西)

正如 cmets 中所建议的那样,我已经在我的应用程序上运行了分析器(以前从未使用过,只有一年级的 CS 学生),我最初对我遇到问题的地方的猜测有些不正确。从探查器告诉我的情况看来,大热点是:

  1. 在将新染色体与群体中的其他染色体进行比较以确定其位置时。我通过实现 Comparable 来做到这一点:
    public int compareTo(Chromosome other) {
        if(this.fitness >= other.fitness)
                        return 1;
             if(this.fitness ==other.fitness )
                       return 0;
                else
                        return -1;
    }
  1. 所描述的另一个问题领域是我的实际进化函数,它消耗了大约 40% 的 CPU 时间。下面所述方法的代码示例

     double topPercentile = highestValue;
     topPercentile = topPercentile * .20;
     topPercentile = Math.ceil(topPercentile);
     randomOne = numberGen.nextInt((int) topPercentile);
     //Lower Bount for random two so it comes from outside of top 20%
     int randomTwo = numberGen.nextInt(highestValue - (int) topPercentile);
     randomTwo = randomTwo + 25;
     //System.out.println("Selecting First: " + randomOne + " Selecting Second: " + randomTwo);
     Chromosome firstChrom = (Chromosome) populationList.get(randomOne);
     Chromosome secondChrom = (Chromosome) populationList.get(randomTwo);
     //System.out.println("Selected 2 Chromosones Crossing Over");
     Chromosome resultantChromosome = firstChrom.crossOver(secondChrom);
     populationList.add(resultantChromosome);
     Collections.sort(populationList);
     populationList.remove(highestValue);
     Chromosome bestResult = (Chromosome) populationList.get(0);
    
  2. 另一个主要的性能命中是由帖子中的第一个代码示例执行的初始种群播种

【问题讨论】:

  • 你的 compareTo 函数永远不会返回 0

标签: java performance genetic-algorithm


【解决方案1】:

我相信我受到最大打击的领域是计算每个染色体的适应度

如果您不确定,那么我假设您尚未在程序上运行分析器。
如果你想提高性能,分析是你应该做的第一件事。

【讨论】:

    【解决方案2】:

    如果您的适应度测量值在几代人之间是一致的(即不依赖于人口中的其他成员),那么我希望至少您将其存储在 Chromosome 对象中,这样您只需为每个人口成员计算一次。有了它,您每次迭代只需计算新生成/组装的染色体的适应度。如果没有更多关于如何计算适应度的信息,就很难在该区域提供任何优化。

    【讨论】:

    • 更正适应度计算函数仅在生成移动时或在创建新染色体时交叉的情况下被调用。适应度函数将计算出的适应度存储在对象内部。所以每个染色体只调用一次适应度函数
    【解决方案3】:

    不要重复对人口进行排序,而是使用一个保持其内容已排序的集合。 (例如树集)

    【讨论】:

    • 像 PriorityQueue 这样的解决方案会是类似的解决方案吗?
    • 是的,类似,但是 TreeSet 可以为您提供最好的和最差的,并按顺序迭代。 PriorityQueue 只能给出一个结束。它们都使 get(index) 变得棘手。
    • 使用 TreeSet 时 get(index) 的最佳替代方案是什么?它会使用迭代器和计数器类型的交易还是?
    • 要么,要么将人口存储在多个集合中。该作业似乎具有小的适应度变化,因此您可以为每个适应度值设置一个数组。
    【解决方案4】:

    您的随机数生成器种子不需要具有很强的加密能力。

    Random numberGen = new Random();
    

    【讨论】:

    • 我发现使用 System.nanoTime() 随机播种并不能真正在初始种群中提供足够的变化,仅使用 new Random() 会产生足够随机的结果。仅使用正态随机数进行测试,它大大减少了种群播种功能的运行时间。感谢您的提示
    • new Random() ++seedUniquifier + System.nanoTime() 上的种子(在 Oracle 的 JVM 中)
    【解决方案5】:

    播种人口时的小幅加速是删除所有测试和分支:

        static Move[] moves = {Move.Down, Move.Up, Move.Left, Move.Right};
    
        ...
    
        moveList.add(moves[randomMove]);
    

    【讨论】:

    • 谢谢!总体而言,随着这个建议和随机生成的变化,总体 CPU 时间从 30% 减少到大约 1.2%
    猜你喜欢
    • 1970-01-01
    • 2011-10-11
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    • 2015-03-21
    • 2011-02-22
    • 2016-09-05
    • 2015-09-12
    相关资源
    最近更新 更多