「強化学習と深層学習」の1章のコードをPythonで書き換えてみる

「強化学習と深層学習」の本を題材に勉強会をしようということになりました。
1章は軽いので各自読んでくださいということなので、読んでたらCのプログラムがあったので、
せっかくなのでPythonで書き直してみました。

 

 

基本的なアルゴリズムは同じなのですが、
自分好みに大分書き換えているので少し解説を加えます。

 

問題

 

本書より問題文を抜粋します。

一対一のじゃんけん勝負を繰り返すじゃんけんプログラムj.cを作成せよ。
ただし、対戦を繰り返す間に、自分の手の選び方を相手の手の選び方の癖に応じて変更することで、
より強いプログラムとなるように学習をすすめる機能を付加せよ。
なお対戦相手は見かけ上ランダムに手を選ぶが、実は、ある傾向(偏り)を持って手を決定しているものとする。

 

コード全体

 

まずコード全体です。

 

 

結果

 

結果です。
まずは敵が「グー : チョキ : パー = 2 : 1 : 1」の比率で出す癖がある場合です。

 

最終的な各手を出す割合は以下のようになりました。
me:2 opponent:0 gain: 1 1.159 0.724 45.530
つまり、「グー : チョキ : パー = 1.159 : 0.724 : 45.530」の割合で出しています。

 

「こいつめっちゃグー出すからパー出しとけばええやろ」という感じに学習したことがわかります。

 

同様に敵が「グー : チョキ : パー = 4 : 3 : 1」の比率で出す癖のある場合を考えてみます。
下の二枚は同じように比率を設定したのですが、結果がだいぶ違いますね。
こういうところが強化学習っぽかったりするのでしょうか。(わからない)
上の画像では、相手がグーとチョキを出しがちなのでグー出しとけば負けることはないということをちゃんと学習していますね。

 

解説

 

では、少し解説をしていきます。

 

比率の設定をする

 

自分の出す比率の初期値と、相手の出す比率を設定します。
下の例では相手はグー、チョキ、パーをそれぞれ4:3:1の比率で出すようにセットしています。

 

今回の例の醍醐味は自分の出す手の比率を良い感じに調整していくところにあります。
最初はどれも同じ比率で出しますが、徐々に学習します。

 

出す手関数を作成

 

「各手を出す割合」が入ったリストを引数に取り、
それぞれに適当な乱数をかけて出す手を決める関数です。

 

各手を出す割合には偏りがありますが、
それぞれに異なる乱数をかけるので、すこし偏りが和らいだりもするということですね。

 

相手の出す手リストを作成

 

先ほどの関数も使って相手の出す手のリストを作成します。
この中には最初に設定した比率で0(=グー),1(=チョキ),2(=パー)がランダムに入っています。

 

確認してみる

 

o_listに本当に4:3:1の割合で入っているかを確認してみましょう。
collectionsライブラリのCounterクラスを利用します。
これを使うとリストの中に各要素がいくつずつ入っているかをカウントしてくれます。

 

Counter({0: 608, 1: 364, 2: 28})

このように確かに4:3:1になっています。

 

勝ち負けの報酬を設定

 

勝敗のリストです。
わかりにくくて恐縮ですが、
1 : win
0 : draw
-1: lose
を表しています。
これはそのまま報酬になります。
つまりグーで勝てばグーに1点の報酬が入ります。

 

これをpay_off_matrix[自分の手][相手の手]というふうに実行することで勝敗を得られます。
例えば自分がグー、相手がパーを出す時
pay_off_matrix[グー][パー] = pay_off_matrix[0][2] = -1 = lose
というふうに負けたことがわかります。

 

学習する

 

以上で用意したものを使って学習していきます。

 

重要なのは5行目ですね。
相手とじゃんけんをして、その勝敗によってその手を出す割合を変えていきます。

 

グーで勝った!→グー出す割合ちょっと上げよう
パーで負けた!→パー出す割合をちょっと下げよう

 

というふうにプログラムしています。

 

学習率は、その「ちょっと」がどれほどかを示しています。
今回は0.01に設定しました。

 

相手が1:1:1で出す場合

 

相手が1:1:1の割合で出す場合を見てみました。
エポックを50万回、学習率を0.000001にしています。

若干わかりにくいのですが、
縦軸は1.0003から0.9997の範囲を表しています。

この結果から、相手が完全に同じ割合で出す場合は
直感と同じように、こちらもほぼ1:1:1の割合で出すように学習しています。

コメントを残す