RNN(LSTM)で藤井聡太と羽生善治と加藤一二三の将棋AI作ってみる〜フルスクラッチで挑戦！！

# はじめに
藤井聡太くんや加藤一二三さんなどで今年少し話題になっている将棋ですが
今勉強しているRNNでなんか面白いことはできないかと思ってやってみたものです

**細かい話抜きで、実際に使ってみたい方は後ろの方の使ってみたい方へ〜をご覧ください**

今回のAIは，パラメータが保存されているので，[github](https://github.com/Shunichi09/Deep_learning_full_scratch/tree/master/Shogi_game)からクローンしていただければ使用できます


![sports_syougi_taikyoku_suit.png](https://qiita-image-store.s3.amazonaws.com/0/261584/69224056-84cd-a4aa-bf1d-57f8fbd9c0d8.png)

![将棋.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/07140879-56cf-a279-c60f-0f2a780a829d.jpeg)


最近勉強していることリンク集

- [RNN](https://qiita.com/MENDY/items/99da56f61f9af51dda15)
- [経路計画](https://qiita.com/MENDY/items/c96e112d6fa0d7e29029)
- [強化学習](https://qiita.com/MENDY/items/4a896b9800775ad987a7)

# 目標
**藤井聡太と羽生善治と加藤一二三の戦略を持つ将棋AIを作る
ここでいうAIは，実際のゲームなんかで相手の手と自分の手を打ったら，
この手がいいんじゃない？と提案を行ってくれるものとします**

※AIという表現はいまいち不適切かと思いますが，いろんな方に理解していただきたく，この表現にしました！

# 結果と結論
なんとなく形になるものができました
実際のゲームに使うことができそう！！？

いろいろと問題はありますが
途中までAIを使って，戦況を有利にできるかもしれません！

# 環境
- windows10（Linuxだと棋譜のテキストファイルがasciiになっていて開かないので、今度時間があるときにLinuxでもできるようにします）
- python3.6.6
- anaconda
- matplotlib 2.2.2
- numpy 1.14.3

# 従来の将棋AI作成法
ゲームに対してよく用いられるのは強化学習です
強化学習については，[こちら](https://qiita.com/MENDY/items/4a896b9800775ad987a7)で，触れているように，価値が高くなるように自身の行動を決定します
簡単にいうと，たくさんプレイしてみて，覚えている中で一番いいなこれっていう場面になるように，自分のアクションを決定するってことです
詳細は，上記のリンクをみてください（0から説明しています）

ただ，これはいろんな人が提案しているし，囲碁ではAlpha碁なんかでも話題になりましたし，ちょっと実装するには手間がかかります
ゲームの詳細情報も作らなきゃだし，特に将棋は取った駒を使えるので難しいみたいですね

なので今回は簡単にやってみたいという思いから違う手法をとります

# 今回のアプローチと考え方
LSTMを用います
LSTMは時刻歴のデータを学習する手法です
つまり，言葉の流れなんかを学習できるわけです

翻訳や，画像の文章生成，文章生成などなどたくさんの言語の問題に応用されています

でふとおもったのですが

将棋の手の流れを学習することはできないかなぁということです

将棋は，

**’４三歩’**

のように，自分の打った手を表現することができます
そして，これらは棋譜として，記録されています

ということは

プロ棋士たちの戦いの棋譜を学習できるのではないかと考えたわけです

数学的な話に置き換えると
ある手が出てきたときに，次の手が’・・・’になる確率を求めることができれば，プロ棋士たちの指し手を表現できるのではないか？

ということです
これは言語モデルの考え方を参考にしています

**さらに，加藤一二三や，藤井聡太の棋譜ばかりあつめれば，彼らの手（流れ）を知っているAIができるのではないかというわけです！！**


![game_syougi.png](https://qiita-image-store.s3.amazonaws.com/0/261584/ea941743-7159-ac4e-63e3-8707f9713d6d.png)


参考として

- ゼロから作るDeep Learning ❷ ―自然言語処理編 斎藤 康毅　オライリージャパン
- ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装 斎藤 康毅　オライリージャパン
- 詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~ 巣籠　悠輔　マイナビ出版

を使ってます 

# データセット作成法
将棋　棋譜　ダウンロード
で調べるとサイトが出てくるので，
藤井聡太，羽生善治，加藤一二三の棋譜のデータをダウンロード

とりあえず，KIF形式で出力して保存しまくる

集められたのは

- 藤井聡太　18対戦
- 羽生善治 150対戦
- 加藤一二三　100対戦

で，集めた棋譜のデータを

**開始**

と

**投了**

で，一つの対戦の棋譜のデータを一つの配列にします

こんな感じ

```py
['開始' '２六歩' '３四歩' '７六歩' '４四歩' '４八銀' '４二銀' '６八玉' '４三銀' '５八金右' '３二金' '２五歩'
 '８四歩' '２四歩' '同歩' '同飛' '２三歩打' '２八飛' '８五歩' '７七角' '５四歩' '４六歩' '３三桂' '４五歩'
 '同歩' '４四歩打' '５二銀' '８八銀' '３一角' '４七銀' '７四歩' '７八玉' '７三桂' '２六飛' '６四角' '３六飛'
 '４二玉' '３四飛' '４六歩' '５六銀' '３八歩打' '１六歩' '３九歩 成' '１七桂' '６二銀' '２五桂' '同桂' '３二飛成'
 '同玉' '４三歩成' '同玉' '１一角成' '３三歩打' '４五香打' '４四 桂打' '２一馬' '３四玉' '４四香' '３七桂成'
 '５四馬' '４七歩成' '４五馬' '２五玉' '２六歩打' '投了']
```

で，これらをダウンロードした棋譜データすべてにおこない，extendして，一つの配列にします

```py

['開始' '２六歩' '３四歩' ... '同歩' '３三金打' '投了'] # all kifu data
```

そしたら，これを一つの文章と見立てて，corpusを作成します
corpusはID化された文章のことです
NNは，文字のままいれても計算することができませんので，それぞれIDに変換しておくことで学習を行えるようにします

```py

[  0   1   2 ...  14 225  61] # corpus
```

でこのcorpusで1つずらして（時系列的に），テストデータと教師データを作成します

```py
xs = corpus[:-1] # 入力データ
ts = corpus[1:] # 教師データ
```

これで準備完了です
なお，ID化されているものは
word_to_id と id_to_wordで表現され以下の感じで収納されています

```py
# id_to_word
{0: '開始', 1: '２六歩', 2: '３四歩', 3: '７六歩', 4: '４四歩', 5: '４八銀', 
6: '４二銀', 7: '６八玉', 8: '４三銀', 9: '５八金右', 10: '３二金', 11: '２五歩',
 12: '８四歩', 13: '２四歩', 14: '同 歩', 15: '同飛', 16: '２三歩打', 
17: '２八飛', 18: '８五歩', 19: '７七角', 20: '５四歩', 21: '４六歩', 
22: '３三桂', 23: '４五歩', 24: '４四歩打'...

# word_to_id
... '５四馬': 56, '４七歩成': 57, '４五馬': 58, '２五玉': 59, '２六歩打': 60, 
'投了': 61, '７八金': 62, '８六歩': 63, '３三角': 64, '５八玉': 65, '６二玉': 66, 
'９六歩': 67, '９四歩': 68, '３六歩': 69, '８二歩打': 70, '７七桂': 71, '７六飛': 72, 
'３七桂': 73, '５五角': 74, '８七金': 75, '７五飛': 76, '３八銀': 77, ' ９五歩': 78, 
'４四角': 79, '９六歩打': 80, '２四飛': 81, '３五歩 打': 82, '３六歩打'...
```

## ワンポイント
さて，ここからが大切です

今集めたデータの流れを学習させるとプロ棋士同士の戦いの流れを知っているものになります
しかし，流れだけを学習しても，もちろん勝てません

なので，データセットを
先攻用（先攻が勝ったデータセット）
と
後攻用（後攻が勝ったデータセット）

に分けてそれぞれのデータセットで，ネットワークを作成します

**そして自分が先攻の時と後攻の時でネットワークを切り替えることで勝利を目指します**

なので正確にいうとひふみんたちのスタイルを学習できるわけではないです
必ずひふみんたちが勝っているわけではないので
羽生さんはめっちゃ強いですけど

# ネットワーク構成

これは言語モデルを模倣するので基本的には

![image.png](https://qiita-image-store.s3.amazonaws.com/0/261584/5b33ad5a-129c-3bb7-507e-ef42fc2817ea.png)

になります
（**実際の忠実なネットワーク構成ではありません，あくまで基本形です**）

詳しくはNNs_shogi.pyをご覧ください

分類だとmany to manyで、下の図でいう

![image.png](https://qiita-image-store.s3.amazonaws.com/0/261584/e9a3c63a-ac88-c120-00b6-b13f5f9e308f.png)

右上の左下です

# 学習法
これは[この前まとめた話](https://qiita.com/MENDY/items/99da56f61f9af51dda15)ですが，今回は1つの大きな流れを学習すると仮定します
なので，シーケンシャルに与えます（シャフルしないバージョン）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/261584/85978d34-ade9-f7f5-e227-0f0642591a98.png)


# 学習結果

検証用データがないので過学習してるかなどは行ってませんが
とりあえず，収束していることはわかります

オレンジが先攻
下のepochの表示おかしくなっているので気にしないでください

![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/261584/4039e90d-ea10-6189-6d9c-c2065fda4a61.png)

# 戦ってみる
さぁ戦ってみましょう！
http://www14.big.or.jp/~ken1/application/shogi.html
にて勝負を申し込みます

![将棋.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/07140879-56cf-a279-c60f-0f2a780a829d.jpeg)


僕が先攻とします
やっていくと．．．

最初の方は定石の提案なのでしょうか？
それとも過学習しているからかもしれませんが，，，

この辺まではほぼAIの予想通りの展開

- **20手までの盤面**

![20手まで.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/f31e2d1e-9ead-b849-ae94-b9430d94d575.jpeg)

- **20手までのコマンドの画面**

![20手まで２.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/05e88015-fdbc-5763-470a-2e4dfb1e2b52.jpeg)


- **30手までの盤面**

![30手まで.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/6600b812-e35a-341c-8ca5-24f985366528.jpeg)

- **30手までのコマンドの画面**

![30手まで2.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/0b0c3531-9c96-f497-65f1-d85e6d2464d3.jpeg)

- **40手までの盤面**

![40手まで.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/5f23d659-ac5c-fe98-4930-35380e36f9d9.jpeg)

- **40手までのコマンドの画面**

![40手まで2.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/22a3693d-05e4-55be-e28a-025728c4234a.jpeg)

- **50手までの盤面**

![50手まで.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/068a84c8-8bb4-d0d2-2534-d225f02f7bd3.jpeg)

- **50手までのコマンドの画面**

![50手まで2.JPG](https://qiita-image-store.s3.amazonaws.com/0/261584/3507f6f4-b8bc-d253-ddc1-d3d9b862bd97.jpeg)


だんだん盤面が複雑になってくると厳しいですね．．．
相手の動きが，選択肢のない手を書かないといけなくなってきますね．．．

ただ，持っているコマを打ってくださいの指示も出てきますしすごいですね

最終的に，自分の手が選択肢の中のもので打てなくなって，難しくなってきたので，くしくもここで諦めました．．．
残念
さて考察

# 考察
## 問題点

**お気づきの通り，トレーニングデータの中にない，手があると，エラーでとまります**
つまり，未知の手には対応ができないわけです
ここは強化学習にたいしては大きく劣るところです

さらに，もっと大きな問題点は，ありえない手が出てきてしまうことです
どうしても，ゲームの条件で縛っていないので，あり得ない手を出力してしまいます
一応流れを学習しているので，そこになんとなく対応していないかと期待していたのですが
ゲームの中盤になると厳しそうです

これも学習データに左右されるところはあると思います

やっぱり強化学習なのかなぁ
あり得ない手をどう学習するかがポイントになりそうですね

## 良い点
良い点は簡単にできることと，データセットの増やし方次第ではかなり強いものが作れるのではないかと考えています
上記の問題点はデータセットが増えれば増えるほど解消に向かう可能性があるからです
ただ、将棋は選択肢が多いので、難しいところではありますが、、、

ハイパーパラメータやネットワーク構成によっては性能の向上が期待されますので
やってみたい方はぜひ！

# 実際に使ってみたい方へ
githubリンク
- https://github.com/Shunichi09/Deep_learning_full_scratch/tree/master/Shogi_game

投了までうまくいくのは難しいですか，
実際に使ってみたい方向けにどうやって使うかを説明します

[github](https://github.com/Shunichi09/Deep_learning_full_scratch/tree/master/Shogi_game)にプログラムが上がっていますのでまずそちらをクローンなどしてください

ファイルの中から

play_game.py

を実行

説明文が以下のようにでます

```

先攻=1ですか？後攻=0ですか？，数字は半角で入力
1
```

なので，試しにまず先攻を選択するために
**半角**で1を入力してください（後攻選択でももちろんできます）

```
８四歩，のように打ってください，棋譜の数字は全角です
王はすべて玉で打ってください

一番初めは，開始と打ってください
```

でこのコマンドが出るので

```
開始
```

と打ってください
すると
このような出力がでますので


```
開始
 60.0 ％ で，７六歩　という手を提案します
 35.4 ％ で，２六歩　という手を提案します
 2.4 ％ で，開始　という手を提案します
 0.89 ％ で，３五歩　という手を提案します
 0.4 ％ で，５六歩　という手を提案します
あなたのターンです（上記から実際に打った手を入力してください）
```

なのでここで上のやつから自分の好きな手を打ってみてください
(もちろん打てるもので！)

ここでは

```
７六歩
```

と打ってみましょう

```
７六歩
[ 12   2  10 ... 804 349 761]
 82.3 ％ で，８四歩　という手を打ってくると思います
 17.5 ％ で，３四歩　という手を打ってくると思います
 0.0 ％ で，３二金　という手を打ってくると思います
 0.0 ％ で，５四歩　という手を打ってくると思います
 0.0 ％ で，４四歩　という手を打ってくると思います
相手のターンです（上記から実際に打たれた手を入力してください）
８四歩
[  1 112 401 ... 144 454  44]
 89.3 ％ で，２六歩　という手を提案します
 9.3 ％ で，６八銀　という手を提案します
 0.6 ％ で，７八飛　という手を提案します
 0.3 ％ で，１六歩　という手を提案します
 0.2 ％ で，７八銀　という手を提案します
あなたのターンです（上記から実際に打った手を入力してください）
```

後は敵が打った手と自分の打った手をコマンドプロンプト上に打っていけば，勝手にAIが良いなと思う手がでてきます

**数字もすべて全角でうってください**

# プログラムについて

自身の棋譜データを使いたい方や学習の中身を知りたい方向けにプログラムの説明をしておきます

- main_shogi
これが学習のmainプログラムです
ここの中のハイパーパラメータやpathを再設定することでオリジナルのものが作れるかと思います
先攻用と後攻用で学習データを変えています
なお，ハイパーパラメータについては一切調整していません

- data_read_function
棋譜データを読み込むための関数が入ってます
今回の棋譜データは

```
1 ７六歩(77) (00:00/00:00:00)
2 ３四歩(33) (00:00/00:00:00)
3 ２六歩(27) (00:00/00:00:00)
```

のような形で保存されていることを想定しています
windowsで保存したのでasciiになってます
Linux用のプログラムを後日上げます

- layers_shogi
NNのレイヤーが入ってます

- functions_shogi
NNに使う関数が入っています

- NNs_shogi
NNを作成しています
ネットワーク構成についてはこちらをご覧ください

- trainer_optimizer_shogi
NNの最適化手法と学習法です

- play_game
上記で説明したゲームを遊ぶためのものです