読者です 読者をやめる 読者になる 読者になる

chainerでオセロAIを作りたかった話

 chainerでオセロAIを作りたかったのですが、ひとまず失敗したという話です。
 高速化の世界に触れてみたいなと思った時期があり、そこそこの終盤読み切りプログラムを持っていたためどうせならオセロAIも作りたいよねという動機で始めました。機械学習でオセロAIを作るとなるととりあえずDQNだろということになるのですが、DQNでは成果が見え始めるまでに計算資源がかなりかかるという話を聞いていたので別の方法を探ってみました*1
 まず、ニューラルネットに盤面を入力して、何を表現させるかという話がありますが、黒から見た時の盤面の評価値としました。次に着手するべき場所を返すようなものを構成している人もいましたが、合法手を打つまで学習させるのがそもそもつらそうなのでやめました。
 深層学習が何をやっているかというと結局のところニューラルネットのパラメータのチューニングなので、適当にパラメータをいじって改善されたら更新するということを繰り返せばAIとして強くなるのではないかと考えました。これは一種の山登り法のようなものなので最適解が得られる保証は一切ありませんし、ほぼ絶対に得られませんが、強くなってはいくはずだと考えました。実際に、遺伝的アルゴリズムニューラルネットを構成するという手法も存在するようでした。
 山登り法のような方法をとる場合、初期値が重要で、初期値によってどこまで高い山を登れるかが決まります。最初からある程度強い評価値を返すニューラルネットを構築するために、既存の簡易的な盤面評価法をニューラルネットに学習させました。具体的には以下のサイトの二つ目の図です。
オセロ(リバーシ)の作り方(アルゴリズム) ~石の位置による評価~
 上記の盤面評価を学習させた後により多くの特徴も抽出できるようになってほしいので、ニューラルネットは少し大きめに全結合層からのみなる65->256->256->1の構成にしました。アルファ碁などはCNNを用いていますが、盤面を畳み込むとよいという感覚が納得できなかったのでやめました。
 とりあえず上記のことまでをやって、深さ3まで探索させたAIと対戦した動画が下記のものです。終盤20手は読み切りますが、負けとわかると適当に置くようになってしまっています。僕自身、あまりオセロは強くないので僕に負けているこのAIも強くないです*2
www.youtube.com
 ここからが本題で、ニューラルネットをランダムに変化させながらもとのAIと対戦させ、勝てたら更新するということを繰り返します。オセロにはもちろん偶然性があるため、何度も対戦させてある程度の勝率だったら更新するという方針を取ります*3。乱数としてはそれぞれのパラメータの絶対値をxで割ったものが標準偏差になるようなガウス分布を用い、これを元のパラメータに足しました。xは気分でチョコマカと変えました。
 最初は10戦して7勝すれば更新というようにしていたのですが、しばらく走らせた後に対戦してみると、隅の重要性を意識しなくなっており、とても弱いAIになっていました。よって更新の条件を厳しくする必要があると考えたので100戦して80勝すれば更新というようにしました。しかし、今度は全く更新されなくなってしまいました。このあたりのパラメータをいじる作業は色々試してみたのですがなかなかうまくいきませんでした。
 コードは以下のような感じです。既にmodelには上記のサイトの盤面評価を学習したものが入っており、complete_readという終盤読み切り用のプログラムも別にあります。
gist.github.com

 現状はここで止まっています。このままパラメータをいじっていればいい感じに更新されていく可能性があるのか、それとも大人しく(?)DQNをするべきなのか行き詰ってます。何か進展が生まれればまた記事を書きたいなと思います。

*1:VM上でCPUしか使えない環境のためより辛い

*2:そもそもこのAIの評価関数は現状では上記のサイトの盤面評価を埋め込んだものの下位互換です

*3:このために序盤の着手には多少ランダム性を持たせます