私は最近Redditを閲覧していて、「JavaScript遺伝的アルゴリズム」の例にリンクする投稿を見つけました。私は遺伝的アルゴリズムとプログラミングの概念に本当に魅了されていますが、グーグル操作を行った後でも、まだ少し混乱しています。それはどのように機能しますか?
私は語彙の用語が何よりも私を混乱させていると思います。簡単な例とおそらく説明をいただければ幸いです。遺伝的プログラミングの概念と、それをプロジェクトに実装する方法とその理由
あなたは遺伝的プログラミングよりも遺伝的アルゴリズムについて話しているように聞こえますが、これがあなたの理解への私の貢献です。
GAを構成する部分の観点からGAを考えると便利です。
それでは、何らかの問題があるとしましょう。最初に必要なのは、ソリューションがどのようになるかを表現する方法です。都市A、B、C、D、Eで 移動するセールスマン の問題があった場合、都市名の配列であるソリューション[B、C、A]の配列がすでにわかっています。 、D、E]。
これはGeneです。
そうでなければ問題の潜在的な解決策として知られています。 Steven A. Loweが述べているように、ビット文字列は遺伝子をエンコードする一般的な方法ですが、必須ではありません。特定のことが簡単になるだけです。重要な部分は、この配列のような方法でソリューションを表す方法があることです。
今。ソリューションが優れているかどうかはどのようにしてわかりますか?あなたはそれを教えてくれるソリューションが必要で、ソリューションを評価します。したがって、再びTSPで、パス[B、C、A、D、E]を使用して移動距離を測定する関数がある場合があります。割り当てる「等級」は、単に移動距離である可能性がありますが、より複雑な問題では、移動コストなどを含めることができます。
これはフィットネス関数です。
だから今、あなたは潜在的な解決策を取り、それが良いものかどうかを見つけることができます。次は何ですか?
次に、最初の世代を開始する必要があります。したがって、一連のランダムな解を生成します。彼らが良いかどうかは関係ありません。これが最初の、つまりシードの母集団です。これを遺伝子プールと呼ぶことができます。
したがって、最初の遺伝子プールを取得し、フィットネス関数をそれらすべてに適用して、すべてに等級を付けます。今、あなたはそれらのうちの2つを取り、それらから新しい人口を作る必要があります-次世代のために。誰を選ぶの?まあ、いくつかの問題が発生する可能性があるため、必ずしもフィットのフィットテストのみを選択する必要はありません。代わりに、選択関数が必要です。
視覚化が容易な選択方法の1つは、一種のホイールを使用することです。各遺伝子はホイール上のスライスであり、フィットネススコアはスライスの大きさを示します(フィットネスが良いほど、スライスが大きくなります)。ホイールを指すピンを置いて、スピンをかけます(つまり、乱数を生成します)。ピンは最初の親を指します。 2番目の親についても同じことを行います。
ここで、新しい子を作成する必要があります。親を組み合わせて、新しい母集団を作成したいとします。これを行うにはさまざまな方法がありますが、それらはすべてクロスオーバー関数と呼ばれています。それらを半分に分割して、親の間で半分を交換したり、ある種のインターリーブを実行したりできます。これは、哺乳動物の親が新しい子供を産むのと非常に似ています->どちらも新しい子供に遺伝子を提供しています。
この新しい世代を取得したら、ランダムにrare突然変異を各子にスローします。突然変異率が1%未満で発生するのをよく見ました。 変異関数は、コード化された遺伝子の何かをランダムに変更します。遺伝子がビット文字列の場合、ビットを入れ替えることができます。都市の配列の場合、リスト内の2つの都市を入れ替えることができます。重要な部分は、それが比較的まれな出来事であり、物事を混同していることです。
必要な世代数になるまで、またはフィットネス関数が常に高いフィットネススコアを持つ親を生成し、(うまくいけば、すべてを正しく実行した場合)最適なソリューションが得られるまで、このプロセスを繰り返します。
それは少し冗長だったので、メタファーで要約しましょう:
お役に立てれば。
問題の解決策をビット文字列としてエンコードする
エンコードされたソリューションにビット文字列がどの程度「良い」かを評価する関数(「フィットネス」関数と呼ばれます)を記述します-結果は通常0と1の間の数値です
これらのビット文字列の束をランダムに生成し、それらの適合性を評価します
束の一部を選択します-通常、より適切なものを選択し、それらを半分に切り、半分を交換していくつかの新しいビット文字列を作成します(クロスオーバー)
次に、新しいビット文字列のいくつかのビットをランダムに反転させます(突然変異)
適切なソリューションが進化するまで繰り返します
なぜこれを行うのか:いくつかの問題には非常に大きなソリューションスペースがあり、すべての可能性を評価することは非現実的です(c.f.巡回セールスマン問題)。
私は本 検索、最適化、機械学習における遺伝的アルゴリズム を強くお勧めします
遺伝的プログラミングは、コンピューターにプログラムを作成させる1つの方法です。
MS Wordのような「プログラム」ではなく、「プログラム」を次のように考えてください。
_function(x){ return x*2; }
_
この関数(またはプログラム)自体には、存在する理由はありません。問題の解決策を探しています。 2つの数値の合計を求める必要がある場合は、計算機を開いて計算を実行するだけです。誰かがあなたに次の表を渡して、result
とx
とy
の関係を理解するように頼んだらどうなるでしょう。
_x y result
99 1 (3.02)
79 88 2.01
21 62 5.01
84 52 (6.58)
12 70 5.54
67 18 0.73
_
このデータは「トレーニング」データです。コンピューターはこのデータを使用していくつかの仮説を生成し、実際のデータに対してテストします。
統計を知らなくて、この問題が自分で理解するには難しすぎると判断すると、コンピュータがそれを理解できるようになります。
コンピューターに100万回の回答を生成させ、それらのいずれかが当てはまるかどうかを確認します(当てはまると...以下は、いくつかの推測の例です。
_function(x,y){ return x+y; } // wrong
function(x,y){ return x/1*1*1*1*1*1+y; } //wrong, silly
_
あなたはこれを知っているかもしれませんし、知らないかもしれませんが、関数またはプログラムはツリーとして表すこともできます。たとえば、2番目の関数は次のようになります。
_(+ (/ x (* 1 (* 1 (* 1 (* 1 (* 1 1)))) y)
_
次のようにインデントすることで、ツリーのように見せることができます(ところで、逆ポーランド記法とLISP構文を調べてください...しかし、このようなプログラムをすぐに表現する理由はすぐに理解できます)。
_(+
(/ x
(* 1
(* 1
(* 1
(* 1
(* 1 1))))
y)
_
(_+
_は、_/
_とy
の2つの「葉」で一番上にあります。_/
_自体には複数の子があります。)
これが、遺伝的プログラミングの「木」についてよく読む理由です。いずれの場合でも、x
とy
の値をこの関数にプラグインすると、間違った答えが返されます。これをランダムに生成したので、当然のことです。
あなたは今、そのようなソリューションを100万個生成することにしました。それらのすべてが間違っています。ただし、一部の回答は他の回答よりも正しい回答に近いことがわかります。つまり、一部のソリューションは他のソリューションよりも「適合」しています。コンピュータが「正しい」と「間違っている」とは何であるかを認識していないので、独自の「フィットネス機能」を提供する必要があることに注意してください。この関数は、潜在的なソリューションであるトレーニングデータを受け取り、このソリューションがどの程度「適合する」かをGPシステムに伝える役割を果たします。ご想像のとおり、この関数は何百万回も実行されます。
ここに、遺伝的プログラミングが野生の推測と異なる点があります。あなたはさらに100万回の推測を行うことにしました。ただし、もう少しインテリジェントに行います。推測(実際の値に近いもの)の上位10%を取得し、それらを第2世代の一部にします。また、これらのソリューションの多く(おそらく同じ10%...覚えていません)を取り、「それらを混同する」ことにします。
2つのソリューションをランダムに選択し、サブツリーをランダムに選択して、それらの交換を開始します。したがって、ソリューションAの一部がソリューションBの下になり、逆もまた同様です。また、いくつかの解決策を取り、それらを単純に「変更」します。いくつかのサブツリーを取り、少し「上にねじ込みます」(ちょっと、解決策がひどい場合は、「理由もなくそれと一緒にねじ込む」と、実際に改善される可能性があります)。
これについての良い考え方は次のとおりです。お母さんとお父さんには、髪の色、身長、病気の可能性など、特定の属性があります。子供は、両親の両方から異なる属性を継承します。もし両親がオリンピック選手だったら、あなたもスーパーアスリートになりますよね?まあ、生物学者、社会学者そして歴史家さえもこの考えに問題を起こすかもしれませんが、コンピュータ科学者はここでは優生学の道徳性に関心がありません。彼らは「システム」がソリューションを提供するかなり良い仕事をしているのを見たので、それをソフトウェアでモデル化することに決めました。
それが実際に生物学と一致しないが、それでも良い答えを提供する場合...多くのコンピューター科学者は集合的に「何でも、そして用語に感謝します」と言います。また、すべての兄弟姉妹が同じではなく、同じ両親がいる場合でも注意してください。それぞれの人は、何らかの理由で変異する遺伝子を持っています(生物学者にこれを見せないでください。ポイントは、多くの用語の背後にある動機を理解することです)。
そのため、今ではコンピュータで数百万のプログラムを生成し、それらの適合性を測定しています。最高のソリューションは、次世代に生き残ります。また、「集団」を「変異」させ、交差させます(遺伝学および生物学の言語がどのように使用されているかに注意してください)。第2世代が作成されると、適合度が再び測定されます。この世代には前の世代からの最良のソリューションがあり、さらに(多様性を維持するために平凡な人口とともに)最良のソリューションをクロスオーバーして変異させたため、この世代は少なくとも前の世代よりも少し優れているはずです。
これを非常に多くの世代にわたって続けます。私たちが正しい答えを得るまで、各世代は(うまくいけば)より良いソリューションを提供します。例えば:
_(+ (- 2.2 (/ x 11) (* 7 (cos y))))
_
これを見てください、これは正しいです!
(これを http://en.wikipedia.org/wiki/Genetic_programming からコピーしました。これもこのツリーのグラフィック表現を持っています)
GPシステムで使用可能な「ターミナル」(_+, -, *, /, cos, sin, tan
_)をどのように決定するか、フィットネス関数をどのように作成するか、システムが_(1 + cos)
_または_(2 / "hello")
_(その他多数)。
方程式を発展させるのはかなり退屈です。ターミナルセットが次のようになっている場合(火災、敵の感知、移動など)、フィットネス機能があなたの健康と武道モンスターの死体の数を測定すると、さらに興味深いものになります。
私はこれのほとんどを記憶から書きましたが、これは基本的な考え方です。大学時代にGPをしました。あなたは間違いなくそれをいじる必要があります。すべての用語を理解する必要はありません。いくつかの無料のGPシステムをダウンロードし、いくつかの例を実行して感じて、独自の興味深い例を作成してください(さまざまなデータセット間の関係を見つけ、ゲームに接続してみてください) APIなど)
適者生存:Windowsフォームでの自然選択 は、私が遺伝的プログラミングを紹介された方法です。コードをダウンロードして簡単に読むことができます。欠点は、GPには実行時に作成されたコードを実行する手段が必要であり、記事の執筆時点ではC#はこのタスクにあまり適していないということです。これが、サンプルがCodeDOMを使用して実行時にコードを生成、コンパイル、および実行する理由です。これにより、コード自体がさらに複雑になります。
その後、状況は変化し、.NETには独自のExpressionTree APIが存在するようになりました。おそらく、記事で説明されているものよりも、C#でよりエレガントなGP実装が可能になります。しかし、GPのしくみを理解するには十分です。
ここ GPで無料の電子ブックをダウンロードできます。これには、非常に短いJavaコード例も含まれているので、興味深いと思うかもしれません。