「作って動かすALife」で人工生命を学ぶ その05 遺伝的アルゴリズム
2025-07-16 14:12:44
今回は第5章「個体の動きが進化する」
一番楽しみにしていた章なのだが、正直がっかり。
プログラム自体は悪くないんだけど、
説明が足りてなさすぎる。
深層学習の基礎を知っていないと、何故そういう発想になるのかや、
プログラムを何故そういうふうに書いたのかが分かりづらい。
色々無理矢理絡めている感じがするし。
まあ、とりあえずプログラムは作って動かしてみた。
まず、この章と7章に必要なライブラリは下記。
$ pip install pillow keras tensorflow
$ pip install vispy
$ pip install PyQt5
$ pip install pyglet
$ pip install pymunk
なお、2025年07月時点では、上記のようにインストールすると下記になった。
$ pip list
Package Version
----------------------- ---------
absl-py 2.3.1
astunparse 1.6.3
certifi 2025.6.15
cffi 1.17.1
charset-normalizer 3.4.2
flatbuffers 25.2.10
freetype-py 2.5.1
gast 0.6.0
google-pasta 0.2.0
grpcio 1.73.1
h5py 3.14.0
hsluv 5.0.4
idna 3.10
keras 3.10.0
kiwisolver 1.4.8
libclang 18.1.1
Markdown 3.8.2
markdown-it-py 3.0.0
MarkupSafe 3.0.2
mdurl 0.1.2
ml_dtypes 0.5.1
namex 0.1.0
numpy 2.1.3
opt_einsum 3.4.0
optree 0.16.0
packaging 25.0
pillow 11.3.0
pip 25.1.1
protobuf 5.29.5
pycparser 2.22
pyglet 2.1.6
Pygments 2.19.2
pymunk 7.1.0
PyQt5 5.15.11
PyQt5-Qt5 5.15.17
PyQt5_sip 12.17.0
requests 2.32.4
rich 14.0.0
setuptools 80.9.0
six 1.17.0
tensorboard 2.19.0
tensorboard-data-server 0.7.2
tensorflow 2.19.0
termcolor 3.1.0
typing_extensions 4.14.1
urllib3 2.5.0
vispy 0.15.2
Werkzeug 3.1.3
wheel 0.45.1
wrapt 1.17.2
この章では、前回のロボット掃除機みたいなやつを生命に見立て作っていく。
人工生命が歩き回って散らばっている餌を食べ回る感じ。
1体1体に遺伝子として、深層学習の重み(60個)を与える。
それを使って深層学習を走らせると、速度と角速度を計算してくれるので、
結果として前に進んだり回転して別方向に進んだりという仕組み。
なお、これは1フレームの動きなので、もちろん1フレーム毎に上記計算を行っている。
ただし、個体の遺伝子は動いたとしても変化しないので、
そのままでは毎回同じ速度と角速度を出力するだけになって全然面白くない。(生命っぽくない)
そのため、1計算毎にcontext_valという2つの変数値を次のフレームの入力にすることで、
次フレームの結果が以前と同じにならないようにしている。
その個体視点で言い換えると、今までの動いた結果によって次の行動を決めているとも言える。
個人的に新しいなと思った概念は、
深層学習の重みを遺伝子とみなす点と、context_valの導入。
だけど、この2つ、全然文章で説明してくれないからね。自分で読みとるしかなかった。
ちょうどたまたま別途深層学習の仕組みの勉強していたから分かったものの、これそうじゃない人は読み取れないよ。
で、これに遺伝的アルゴリズムを導入する。
評価関数は食べた餌の数。
次世代には、
- 現世代で最も餌を食べた遺伝子1個
- 現世代からランダムで選出(約1/3)
- 現世代から突然変異で一箇所重み変化させた(約1/3)
- 現世代からランダムで2つ選び、それを交叉させて作った2個体(約1/3)
を選出していくことで進化を促す。
突然変異やランダム選出は、局所的な適応度地形に留まってしまうのを防ぐためである。
書籍では、個体51、1個体あたり2000フレームで載っているが、
これがやってみると結構時間かかる。
なので、1個体あたりのフレーム数を200に落として、25世代まで進化させてみた。
まず第1世代で最も餌を食べた個体を、3000フレーム動かした結果。
次に第25世代で最も餌を食べた個体を、3000フレーム動かした結果。
線になっているのが食べた跡。
前者では同じところをぐるぐる回っていることが多く、
一度食べてしまった部分では餌がないのでほとんど食べれず、効率が悪いことが分かる。
しかし、後者では同じところを通ることは少なく、ある程度均質に範囲を探し回っているような感じが出ている。
(餌の密度を予め予測して動いているわけではないが、結果的にそういう動きをしたものが生き残ってきた)
1個体たった200フレームでこうなのだから、
2000フレームでやってみるともっと効率的に進化していくのかもしれない。
まあ、暇があったら走らせてみよう。
今回で良かったのは、深層学習にいかに遺伝的アルゴリズムを組み込むかということが学べた点
なお、今回のプログラムは間違いやヌケモレが少なかったな。
次は7章。
There are currently no comments on this article, be the first to add one below
Add a Comment
Note that I may remove comments for any reason, so try to be civil. If you are looking for a response to your comment, either leave your email address or check back on this page periodically.