Javaで遺伝的アルゴリズムを設計する

Javaでの遺伝的アルゴリズムの設計

1. 前書き

このシリーズの目的は、explain the idea of genetic algorithmsです。

遺伝的アルゴリズムは、自然と同じプロセスを使用して問題を解決するように設計されています。選択、組換え、突然変異の組み合わせを使用して、問題の解決策を展開します。

最も単純なバイナリ遺伝的アルゴリズムの例を使用して、これらのアルゴリズムの概念を説明することから始めましょう。

2. 遺伝的アルゴリズムのしくみ

Genetic algorithms are a part of evolutionary computing、これは人工知能の急速に成長している分野です。

アルゴリズムは、populationと呼ばれるset of solutionsindividualsで表される)で始まります。 新しい母集団が古い母集団よりも優れている可能性があるため、1つの母集団からの解が取得され、new populationを形成するために使用されます。

新しいソリューション(offspring)を形成するために選択された個人は、fitnessに従って選択されます。適切であるほど、再現する必要がある可能性が高くなります。

3. バイナリ遺伝的アルゴリズム

簡単な遺伝的アルゴリズムの基本的なプロセスを見てみましょう。

3.1. 初期化

初期化ステップでは、generate a random Population that serves as a first solutionを実行します。 まず、Populationの大きさと、予想される最終的な解決策を決定する必要があります。

SimpleGeneticAlgorithm.runAlgorithm(50,
  "1011000100000100010000100000100111001000000100000100000000001111");

上記の例では、Populationのサイズは50であり、正しい解は、いつでも変更できるバイナリビット文字列で表されます。

次のステップでは、目的のソリューションを保存し、ランダムなPopulationを作成します。

setSolution(solution);
Population myPop = new Population(populationSize, true);

これで、プログラムのメインループを実行する準備が整いました。

3.2. フィットネスチェック

プログラムのメインループでは、evaluate each Individual by the fitness functionに移動します(簡単に言うと、Individualが優れているほど、適応度関数の値が高くなります)。

while (myPop.getFittest().getFitness() < getMaxFitness()) {
    System.out.println(
      "Generation: " + generationCount
      + " Correct genes found: " + myPop.getFittest().getFitness());

    myPop = evolvePopulation(myPop);
    generationCount++;
}

how we get the fittest Individualの説明から始めましょう:

public int getFitness(Individual individual) {
    int fitness = 0;
    for (int i = 0; i < individual.getDefaultGeneLength()
      && i < solution.length; i++) {
        if (individual.getSingleGene(i) == solution[i]) {
            fitness++;
        }
    }
    return fitness;
}

観察できるように、2つのIndividualオブジェクトを少しずつ比較します。 完全な解決策が見つからない場合は、次のステップに進む必要があります。これは、Populationの進化です。

3.3. 子孫

このステップでは、新しいPopulationを作成する必要があります。 まず、適合性に応じて、Population,から2つの親IndividualオブジェクトをSelectする必要があります。 現在の世代の最良のIndividualを、変更せずに次の世代に引き継ぐことができると有益であることに注意してください。 この戦略はElitism:と呼ばれます

if (elitism) {
    newPopulation.getIndividuals().add(0, pop.getFittest());
    elitismOffset = 1;
} else {
    elitismOffset = 0;
}

2つの最良のIndividualオブジェクトを選択するために、tournament selection strategyを適用します。

private Individual tournamentSelection(Population pop) {
    Population tournament = new Population(tournamentSize, false);
    for (int i = 0; i < tournamentSize; i++) {
        int randomId = (int) (Math.random() * pop.getIndividuals().size());
        tournament.getIndividuals().add(i, pop.getIndividual(randomId));
    }
    Individual fittest = tournament.getFittest();
    return fittest;
}

各トーナメントの勝者(最もフィットネスの高いトーナメント)が次のステージに選ばれます。これはCrossoverです。

private Individual crossover(Individual indiv1, Individual indiv2) {
    Individual newSol = new Individual();
    for (int i = 0; i < newSol.getDefaultGeneLength(); i++) {
        if (Math.random() <= uniformRate) {
            newSol.setSingleGene(i, indiv1.getSingleGene(i));
        } else {
            newSol.setSingleGene(i, indiv2.getSingleGene(i));
        }
    }
    return newSol;
}

クロスオーバーでは、ランダムに選択されたスポットで、選択された各Individualからビットを交換します。 プロセス全体は、次のループ内で実行されます。

for (int i = elitismOffset; i < pop.getIndividuals().size(); i++) {
    Individual indiv1 = tournamentSelection(pop);
    Individual indiv2 = tournamentSelection(pop);
    Individual newIndiv = crossover(indiv1, indiv2);
    newPopulation.getIndividuals().add(i, newIndiv);
}

ご覧のとおり、クロスオーバー後、新しい子孫を新しいPopulationに配置します。 このステップはAcceptance.と呼ばれます

最後に、Mutationを実行できます。 突然変異は、Populationのある世代から次の世代への遺伝的多様性を維持するために使用されます。 bit inversionタイプのミューテーションを使用しました。ここでは、ランダムビットが単純に反転されます。

private void mutate(Individual indiv) {
    for (int i = 0; i < indiv.getDefaultGeneLength(); i++) {
        if (Math.random() <= mutationRate) {
            byte gene = (byte) Math.round(Math.random());
            indiv.setSingleGene(i, gene);
        }
    }
}

すべてのタイプのミューテーションとクロスオーバーは、in this tutorialでうまく記述されています。

次に、サブセクション3.2と3.3の手順を繰り返して、たとえば最適なソリューションなどの終了条件に到達します。

4. ヒントとコツ

implement an efficient genetic algorithmにするには、一連のパラメーターを調整する必要があります。 このセクションでは、ほとんどのインポートパラメータから開始する基本的な推奨事項を示します。

  • Crossover rate –高いはずです、約80%-95%

  • Mutation rate –非常に低く、0.5%-1%前後である必要があります。

  • Population size –適切な母集団サイズは約20-30ですが、一部の問題ではサイズ50〜100の方が適しています

  • Selection –基本的なroulette wheel selectionは、elitismの概念で使用できます。

  • Crossover and mutation type –エンコーディングと問題によって異なります

チューニングの推奨事項は、多くの場合、遺伝的アルゴリズムに関する経験的研究の結果であり、提案された問題に基づいて変わる可能性があることに注意してください。

5. 結論

このチュートリアルintroduces fundamentals of genetic algorithms。 この分野の遺伝的アルゴリズムwithout any previous knowledgeについては、基本的なコンピュータープログラミングスキルしか持っていないので学ぶことができます。

このチュートリアルのコードスニペットの完全なソースコードは、in the GitHub projectで入手できます。

ゲッターとセッターを生成するためにLombokを使用することにも注意してください。 IDEin this articleで正しく設定する方法を確認できます。

遺伝的アルゴリズムのその他の例については、シリーズのすべての記事をご覧ください。