ニューラルネットワーク(と遺伝的アルゴリズム)で長方形くんに道の走り方を学習させました。 今回長方形くんに学ばせたのは、「どう言う状況でどちらに曲がるか(または曲がらないか)」です。前進は必ず行い、壁との距離がどのような時にどう曲がるかを判断するネットワークを作成させました。 ちなみに1世代で作る個体の数は10体です。 長方形には画面左下に示すように5本のセンサがついており、それぞれ、その上のネットワークが示す図の白丸と対応しています。白丸がある1番下の横列を入力層と言います。センサは壁との距離を調べて、距離が近いほど強い信号を発します。受け取った信号は真ん中横列の隠れ層と言うところに届き、隠れ層の信号が、1番上横列の出力層に届きます。そして「左折、曲がらない、右折」の3つある出力層の信号のうち、1番信号が強かったものを実行します。この動作は全ての個体で毎フレーム行われています。 センサの入力から計算でどの出力をするのか決めている要素が、「重み」と「閾値」になります。 画面左のネットワークの図の、線の色が重み、丸の色が閾値を表しています。色が赤に近いほど値が大きいです。下の丸からの信号1つ1つにそれぞれ重みを掛け、それを全て足して、そこから閾値を引いた値をシグモイド関数に入れて出力を決めています。シグモイド関数については、調べるか僕の前の作品を見てみてください。 ちなみに画面のニューラルネットワークの図は今の世代の中で1番優秀な個体(1番長生きしている個体)のものを表示しています。そのため世代が変わっていないのに図が変わっていることがありますが、ネットワークが表示される個体が変わっているだけなので気にしないでください。 そしてその重みと閾値、いわば思考の判断基準となるパラメータを、より長い距離走れるようなものに変更していく動作が、ここで言う学習になります。 本当は誤差逆伝播方というモノなどを使って学習させたかったのですが、僕もまだ勉強中で理解することができなかったので断念しました。 ニュラルネットワークとはそもそも脳が思考する仕組みを再現したものであり、結果をもとにそれに対応する重みや閾値が変化するもの、つまり「進化」ではなく、1世代で完結する、「成長」による学習というイメージがあります。そのため、世代交代でパラメータを飛び飛びに入れ替えていく「進化」である遺伝的アルゴリズムを使っていいのかという思いがあったのですが、こちらの方が理解は簡単で、YouTubeで動画をみてみても遺伝的アルゴリズムを使っている方が多くいたのでこれでやってみることにしました。ニューラルネットワークに遺伝的アルゴリズムで学習させてもうまくいくのか、というのもこの作品で確かめたいことの1つでした。 そのため、結果的にうまく学習できていて自分でもびっくりしました。遺伝的アルゴリズムは学習させるに当たって設定することが山ほどあるのでとても奥が深いです。もっと効果的なやり方も間違いなく存在するので、それを試行錯誤するのも面白いなと思うようになりました。でもやっぱり先に「成長」の学習の方法を理解したいとも思います。 そして毎回道の形が変わっていることについて。正直これはやらなくても良かったかなとは思いましたが、ニューラルネットワークの醍醐味である柔軟性をアピールしたいなと思い、道を毎回変えるようにしました。 この話をするととてもややこしいので飛ばしていただいて構いませんが、例えば、今回は遺伝的アルゴリズムで重みと閾値を決めましたが、ニューラルネットワークを使わずに遺伝的アルゴリズムで、どう曲がるかを直接決めることもできます。ただし、その方法は道の形が一定であるときににしか使えないという欠点があります。道の形に適応した動きをする個体が生まれていくからです。 その点ニューラルネットワークを使えば、この状況の時はこう、という場合分け(特徴抽出)をすることができるので、毎回道が変わっても問題なく走行することができると考えられます。 その他、話し足りないこと、不明点 YouTubeでみた動画では、閾値について考えてなかった気がします。確かに重みだけでもうまくすれば同じことができるかもしれません。それが遺伝的アルゴリズムを使っているせいなのか他の方法でもそうなのかはよく分かっていません。すみません。 隠れ層が5個なのは自分でも説明ができません笑。隠れ層は特徴ごとに数を決めるらしいのですが、今回の学習は隠れそうもいらないんじゃないかというくらい単純なのでよく分かりませんでした。そもそも人間が、現れるであろう特徴の数を見越して隠れ層の数を指定するのはあまりいい学習とは言えないのではないかと思いましたがおそらく僕の解釈が間違っているのだと思います。結局隠れ層は入力層と同じ5個にしたのですが、ものによっては隠れ層が2層以上のものなどもあるので、もっと詳しく学んでおきたいと思います。 ここまで読んでいただきありがとうございました。最後に、細かい設定について書いておきます。ほぼメモなので読む必要はありません。 センサの長さ:30 入力の強さ:(30-壁までの距離)/30 重みと閾値の初期値:一律で0.00~1.00の乱数 その世代で1番目、2番目に優秀だった個体どうしを交配させる。 入れ替える重みの数:隠れ層12、出力層7 入れ替える閾値の数:隠れ層2、出力層1 入れ替えによって、一度に2個体できるので、全く反対の遺伝子の組み合わせを持つ個体が5組できる。 また、新しく生まれた個体が全て不遇だったときに停滞期間に入るのをなるべく防ぐために、1番優秀だった個体はそのまま次の世代へ連れていく。上で作った10の個体のうち1つはそれに置き換えられている。 突然変異は完全に乱数で、全ての個体で何回でも起こりうる。 重みの突然変異確率:1/50 閾値の突然変異確率:1/20 確率に当選した場合、その場所の値が0.00~1.00の乱数で置き換えられる。 突然変異を増やせば停滞期間に入った時に脱出しやすくなるが、最適解は出にくくなる。 突然変異を減らせば最適解は出やすくなるが、停滞期間に入るとなかなか脱出できない。
上の説明の半分以上は、後で見る自分に向けたメモのような意味で書きました。そのため説明が不十分なところがあるかと思いますがご了承ください。知識をひけらかしている訳ではありません笑。全てを説明していたらキリが無いのと、僕自身まだ手探りの状態で、そもそもひけらかせるほどの知識がなくて説明できないというのが大きいです。特に遺伝的アルゴリズムは一言では説明できませんが、上の文章でたくさん出てくることなので、もし興味がありましたら、お手数ですがご自分で調べてみてください。その他、用語以外で僕の説明不足のところは質問していただければ答えたいと思います。 また、ところどころ僕の独自の見解が入っているところがあります。文中で僕が断言しているものは間違いではないと思いますが、例外が存在することもあります。そのためすべてを鵜呑みにせず、やはりご自身で調べていただければと思います。そして僕が何か間違ったことを言っていれば、ちょっと引っかかる、レベルのことでも構いませんのでぜひコメントしてください。 このような機械学習などの分野は個人的にとても興味深く、もっと学んでいきたいと思っているので、今後もゆっくりとですが作品を出していけたらと思っています。 もし詳しい方がいらっしゃれば、アドバイスなどいただけるととてもありがたいです。