はじめに
藤井聡太くんや加藤一二三さんなどで今年少し話題になっている将棋ですが
今勉強しているRNNでなんか面白いことはできないかと思ってやってみたものです
細かい話抜きで、実際に使ってみたい方は後ろの方の使ってみたい方へ〜をご覧ください
今回のAIは,パラメータが保存されているので,githubからクローンしていただければ使用できます
最近勉強していることリンク集
目標
藤井聡太と羽生善治と加藤一二三の戦略を持つ将棋AIを作る
ここでいうAIは,実際のゲームなんかで相手の手と自分の手を打ったら,
この手がいいんじゃない?と提案を行ってくれるものとします
※AIという表現はいまいち不適切かと思いますが,いろんな方に理解していただきたく,この表現にしました!
結果と結論
なんとなく形になるものができました
実際のゲームに使うことができそう!!?
いろいろと問題はありますが
途中までAIを使って,戦況を有利にできるかもしれません!
環境
- windows10(Linuxだと棋譜のテキストファイルがasciiになっていて開かないので、今度時間があるときにLinuxでもできるようにします)
- python3.6.6
- anaconda
- matplotlib 2.2.2
- numpy 1.14.3
従来の将棋AI作成法
ゲームに対してよく用いられるのは強化学習です
強化学習については,こちらで,触れているように,価値が高くなるように自身の行動を決定します
簡単にいうと,たくさんプレイしてみて,覚えている中で一番いいなこれっていう場面になるように,自分のアクションを決定するってことです
詳細は,上記のリンクをみてください(0から説明しています)
ただ,これはいろんな人が提案しているし,囲碁ではAlpha碁なんかでも話題になりましたし,ちょっと実装するには手間がかかります
ゲームの詳細情報も作らなきゃだし,特に将棋は取った駒を使えるので難しいみたいですね
なので今回は簡単にやってみたいという思いから違う手法をとります
今回のアプローチと考え方
LSTMを用います
LSTMは時刻歴のデータを学習する手法です
つまり,言葉の流れなんかを学習できるわけです
翻訳や,画像の文章生成,文章生成などなどたくさんの言語の問題に応用されています
でふとおもったのですが
将棋の手の流れを学習することはできないかなぁということです
将棋は,
’4三歩’
のように,自分の打った手を表現することができます
そして,これらは棋譜として,記録されています
ということは
プロ棋士たちの戦いの棋譜を学習できるのではないかと考えたわけです
数学的な話に置き換えると
ある手が出てきたときに,次の手が’・・・’になる確率を求めることができれば,プロ棋士たちの指し手を表現できるのではないか?
ということです
これは言語モデルの考え方を参考にしています
さらに,加藤一二三や,藤井聡太の棋譜ばかりあつめれば,彼らの手(流れ)を知っているAIができるのではないかというわけです!!
参考として
- ゼロから作るDeep Learning ❷ ―自然言語処理編 斎藤 康毅 オライリージャパン
- ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装 斎藤 康毅 オライリージャパン
- 詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~ 巣籠 悠輔 マイナビ出版
を使ってます
データセット作成法
将棋 棋譜 ダウンロード
で調べるとサイトが出てくるので,
藤井聡太,羽生善治,加藤一二三の棋譜のデータをダウンロード
とりあえず,KIF形式で出力して保存しまくる
集められたのは
- 藤井聡太 18対戦
- 羽生善治 150対戦
- 加藤一二三 100対戦
で,集めた棋譜のデータを
開始
と
投了
で,一つの対戦の棋譜のデータを一つの配列にします
こんな感じ
['開始' '2六歩' '3四歩' '7六歩' '4四歩' '4八銀' '4二銀' '6八玉' '4三銀' '5八金右' '3二金' '2五歩'
'8四歩' '2四歩' '同歩' '同飛' '2三歩打' '2八飛' '8五歩' '7七角' '5四歩' '4六歩' '3三桂' '4五歩'
'同歩' '4四歩打' '5二銀' '8八銀' '3一角' '4七銀' '7四歩' '7八玉' '7三桂' '2六飛' '6四角' '3六飛'
'4二玉' '3四飛' '4六歩' '5六銀' '3八歩打' '1六歩' '3九歩 成' '1七桂' '6二銀' '2五桂' '同桂' '3二飛成'
'同玉' '4三歩成' '同玉' '1一角成' '3三歩打' '4五香打' '4四 桂打' '2一馬' '3四玉' '4四香' '3七桂成'
'5四馬' '4七歩成' '4五馬' '2五玉' '2六歩打' '投了']
で,これらをダウンロードした棋譜データすべてにおこない,extendして,一つの配列にします
['開始' '2六歩' '3四歩' ... '同歩' '3三金打' '投了'] # all kifu data
そしたら,これを一つの文章と見立てて,corpusを作成します
corpusはID化された文章のことです
NNは,文字のままいれても計算することができませんので,それぞれIDに変換しておくことで学習を行えるようにします
[ 0 1 2 ... 14 225 61] # corpus
でこのcorpusで1つずらして(時系列的に),テストデータと教師データを作成します
xs = corpus[:-1] # 入力データ
ts = corpus[1:] # 教師データ
これで準備完了です
なお,ID化されているものは
word_to_id と id_to_wordで表現され以下の感じで収納されています
# id_to_word
{0: '開始', 1: '2六歩', 2: '3四歩', 3: '7六歩', 4: '4四歩', 5: '4八銀',
6: '4二銀', 7: '6八玉', 8: '4三銀', 9: '5八金右', 10: '3二金', 11: '2五歩',
12: '8四歩', 13: '2四歩', 14: '同 歩', 15: '同飛', 16: '2三歩打',
17: '2八飛', 18: '8五歩', 19: '7七角', 20: '5四歩', 21: '4六歩',
22: '3三桂', 23: '4五歩', 24: '4四歩打'...
# word_to_id
... '5四馬': 56, '4七歩成': 57, '4五馬': 58, '2五玉': 59, '2六歩打': 60,
'投了': 61, '7八金': 62, '8六歩': 63, '3三角': 64, '5八玉': 65, '6二玉': 66,
'9六歩': 67, '9四歩': 68, '3六歩': 69, '8二歩打': 70, '7七桂': 71, '7六飛': 72,
'3七桂': 73, '5五角': 74, '8七金': 75, '7五飛': 76, '3八銀': 77, ' 9五歩': 78,
'4四角': 79, '9六歩打': 80, '2四飛': 81, '3五歩 打': 82, '3六歩打'...
ワンポイント
さて,ここからが大切です
今集めたデータの流れを学習させるとプロ棋士同士の戦いの流れを知っているものになります
しかし,流れだけを学習しても,もちろん勝てません
なので,データセットを
先攻用(先攻が勝ったデータセット)
と
後攻用(後攻が勝ったデータセット)
に分けてそれぞれのデータセットで,ネットワークを作成します
そして自分が先攻の時と後攻の時でネットワークを切り替えることで勝利を目指します
なので正確にいうとひふみんたちのスタイルを学習できるわけではないです
必ずひふみんたちが勝っているわけではないので
羽生さんはめっちゃ強いですけど
ネットワーク構成
これは言語モデルを模倣するので基本的には
になります
(実際の忠実なネットワーク構成ではありません,あくまで基本形です)
詳しくはNNs_shogi.pyをご覧ください
分類だとmany to manyで、下の図でいう
右上の左下です
学習法
これはこの前まとめた話ですが,今回は1つの大きな流れを学習すると仮定します
なので,シーケンシャルに与えます(シャフルしないバージョン)
学習結果
検証用データがないので過学習してるかなどは行ってませんが
とりあえず,収束していることはわかります
オレンジが先攻
下のepochの表示おかしくなっているので気にしないでください
戦ってみる
さぁ戦ってみましょう!
http://www14.big.or.jp/~ken1/application/shogi.html
にて勝負を申し込みます
僕が先攻とします
やっていくと...
最初の方は定石の提案なのでしょうか?
それとも過学習しているからかもしれませんが,,,
この辺まではほぼAIの予想通りの展開
- 20手までの盤面
- 20手までのコマンドの画面
- 30手までの盤面
- 30手までのコマンドの画面
- 40手までの盤面
- 40手までのコマンドの画面
- 50手までの盤面
- 50手までのコマンドの画面
だんだん盤面が複雑になってくると厳しいですね...
相手の動きが,選択肢のない手を書かないといけなくなってきますね...
ただ,持っているコマを打ってくださいの指示も出てきますしすごいですね
最終的に,自分の手が選択肢の中のもので打てなくなって,難しくなってきたので,くしくもここで諦めました...
残念
さて考察
考察
問題点
お気づきの通り,トレーニングデータの中にない,手があると,エラーでとまります
つまり,未知の手には対応ができないわけです
ここは強化学習にたいしては大きく劣るところです
さらに,もっと大きな問題点は,ありえない手が出てきてしまうことです
どうしても,ゲームの条件で縛っていないので,あり得ない手を出力してしまいます
一応流れを学習しているので,そこになんとなく対応していないかと期待していたのですが
ゲームの中盤になると厳しそうです
これも学習データに左右されるところはあると思います
やっぱり強化学習なのかなぁ
あり得ない手をどう学習するかがポイントになりそうですね
良い点
良い点は簡単にできることと,データセットの増やし方次第ではかなり強いものが作れるのではないかと考えています
上記の問題点はデータセットが増えれば増えるほど解消に向かう可能性があるからです
ただ、将棋は選択肢が多いので、難しいところではありますが、、、
ハイパーパラメータやネットワーク構成によっては性能の向上が期待されますので
やってみたい方はぜひ!
実際に使ってみたい方へ
githubリンク
投了までうまくいくのは難しいですか,
実際に使ってみたい方向けにどうやって使うかを説明します
githubにプログラムが上がっていますのでまずそちらをクローンなどしてください
ファイルの中から
play_game.py
を実行
説明文が以下のようにでます
先攻=1ですか?後攻=0ですか?,数字は半角で入力
1
なので,試しにまず先攻を選択するために
半角で1を入力してください(後攻選択でももちろんできます)
8四歩,のように打ってください,棋譜の数字は全角です
王はすべて玉で打ってください
一番初めは,開始と打ってください
でこのコマンドが出るので
開始
と打ってください
すると
このような出力がでますので
開始
60.0 % で,7六歩 という手を提案します
35.4 % で,2六歩 という手を提案します
2.4 % で,開始 という手を提案します
0.89 % で,3五歩 という手を提案します
0.4 % で,5六歩 という手を提案します
あなたのターンです(上記から実際に打った手を入力してください)
なのでここで上のやつから自分の好きな手を打ってみてください
(もちろん打てるもので!)
ここでは
7六歩
と打ってみましょう
7六歩
[ 12 2 10 ... 804 349 761]
82.3 % で,8四歩 という手を打ってくると思います
17.5 % で,3四歩 という手を打ってくると思います
0.0 % で,3二金 という手を打ってくると思います
0.0 % で,5四歩 という手を打ってくると思います
0.0 % で,4四歩 という手を打ってくると思います
相手のターンです(上記から実際に打たれた手を入力してください)
8四歩
[ 1 112 401 ... 144 454 44]
89.3 % で,2六歩 という手を提案します
9.3 % で,6八銀 という手を提案します
0.6 % で,7八飛 という手を提案します
0.3 % で,1六歩 という手を提案します
0.2 % で,7八銀 という手を提案します
あなたのターンです(上記から実際に打った手を入力してください)
後は敵が打った手と自分の打った手をコマンドプロンプト上に打っていけば,勝手にAIが良いなと思う手がでてきます
数字もすべて全角でうってください
プログラムについて
自身の棋譜データを使いたい方や学習の中身を知りたい方向けにプログラムの説明をしておきます
-
main_shogi
これが学習のmainプログラムです
ここの中のハイパーパラメータやpathを再設定することでオリジナルのものが作れるかと思います
先攻用と後攻用で学習データを変えています
なお,ハイパーパラメータについては一切調整していません -
data_read_function
棋譜データを読み込むための関数が入ってます
今回の棋譜データは
1 7六歩(77) (00:00/00:00:00)
2 3四歩(33) (00:00/00:00:00)
3 2六歩(27) (00:00/00:00:00)
のような形で保存されていることを想定しています
windowsで保存したのでasciiになってます
Linux用のプログラムを後日上げます
-
layers_shogi
NNのレイヤーが入ってます -
functions_shogi
NNに使う関数が入っています -
NNs_shogi
NNを作成しています
ネットワーク構成についてはこちらをご覧ください -
trainer_optimizer_shogi
NNの最適化手法と学習法です -
play_game
上記で説明したゲームを遊ぶためのものです