『強い将棋ソフトの創りかた』ではじめての将棋AI開発

本記事は[フューチャーAdvent Calendar](https://qiita.com/advent-calendar/2023/future)8日目の記事です。

2023年4月新卒入社の@Shu2424と申します。
入社後はじめての記事投稿になりますが、よろしくお願いいたします。

# はじめに
私は大学からの将棋経験者で、現在も社内の将棋部に参加しています。
普段から将棋とITに関わってるということもあり、この機会に将棋AIの開発に挑戦することにしました。
今回は、[山岡忠夫](https://twitter.com/TadaoYamaoka)さんと[加納邦彦](https://twitter.com/k_kanou)さんが書かれた[『強い将棋ソフトの創りかた』](https://www.amazon.co.jp/o/ASIN/4839977348/mynavibooks-22/)で学びながら将棋AIを開発した感想を書いていこうと思います。

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622115/e4fb7e5d-3058-779a-9d85-d04f3120b4e1.png)](https://www.amazon.co.jp/o/ASIN/4839977348/mynavibooks-22/)
（表紙のイラストがかっこいい）

# 本書の全体像
本書は「導入編」「理論編」「実践編」「発展編」から構成されています。
詳しい目次は[公式サイト](https://book.mynavi.jp/ec/products/detail/id=126887)をご覧ください。
「導入編」「理論編」の簡単な感想と「実践編」で作ったものについて書いていきます。
「発展編」は作った将棋AIをさらに強くする内容が書かれていますが、実行に必要なGPUが用意できていないためまだ実践できていません・・・。

## 1. 導入編（第1章）
コンピュータ将棋の歴史とディープラーニングのインパクトについてまとめられています。
個人的には、ディープラーニングを利用した将棋AIがコンピュータ将棋の大会で初優勝したのが、2020年と割と最近だったのが少し意外でした。
少し調べてみると、ディープラーニング系の将棋AIは大局観や形成判断は優れるものの、最終盤での読み合いで比較的ミスが起きやすいという話もあり、「ディープラーニング＝強い」という単純な話ではいかないようです（[参考](https://logmi.jp/tech/articles/324157)）。

## 2. 理論編（2章～3章）
コンピュータ将棋におけるアルゴリズムとディープラーラーニングの基礎が解説されています。
ディープラーニングの解説が非常にわかりやすく、今まで理解できていなかった畳み込みニューラルネットワークのイメージをざっくり掴むことができたのが良かったです。
理論的な解説は最低限にされているので詳細に知りたい場合は別の解説を読む必要がありますが、実装の前におおまかに動きを理解する上で大きな助けになりました。

## 3. 実践編（4章～7章）
ここから将棋AI開発に入ります。
書籍のお手本にならってGoogle Colabで実装しました。
Colabは利用できるリソースに制限があるため、本格的に開発する場合はGPUを用意する必要があります。
ニューラルネットワーク以外にも、指し手の探索アルゴリズムや[USI(Universal Shogi Interface)プロトコル](http://shogidokoro.starfree.jp/usi.html)についても解説されているのですが、長くなるため省略します。

### ニューラルネットワーク
将棋AIに用いられるニューラルネットワークとして、Value NetworkとPolicy Networkがあります。
Value Networkは2クラス分類のためのネットワークで、その局面から対局したときに「勝ち」「負け」のどちらにつながるかを予測します（「引き分け」を含めて3クラスの分類とすることもできます）。
Policy Networkは多クラス分類のためのネットワークで、その局面で指すことのできる全ての候補手の中から、次の手を予測するネットワークです。
実装の際は、Value NetworkとPolicy Networkを一つのニューラルネットワークにします（→[マルチタスク学習](https://ai-kenkyujo.com/term/multitask-learning/)）。
実装コードは基本的に著者の[GitHub](https://github.com/TadaoYamaoka/ShogiAIBook2)にならって作成しました。
ざっくりとした構成は下図のようになっており、Residual Network（残差ネットワーク）が採用されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622115/e60fb93e-8520-e2e0-917f-08e8b5634ec7.png)
（『強い将棋ソフトの創りかた』p.103-106「5.3.4 ニューラルネットワークの構成」を基に作成）


### 教師データ
東京大学の[コンピュータ将棋連続対局場所 (floodgate)](http://wdoor.c.u-tokyo.ac.jp/shogi/floodgate.html)の棋譜を学習元データとして、教師あり学習をします。
floodgateは将棋AI同士の対局が自動で行われるサーバです。
学習元データは多いほうがよさそうですが、Google Colabでは実行時間に制限があるため、今回は2022年12月の1か月分の棋譜のみ利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622115/7affbf4b-d6c8-a1c6-f066-2294172cf611.png)
（ホームページが更新されていませんが2023年現在も動き続けています）

### 訓練実行
異常終了した対局、手数が異常に少ない対局、不正な指し手がある対局、低レートの対局を除外したあと、訓練を実行します。
```shogi.ipynb
!python practice_01/train.py train.hcpe test.hcpe --epoch 10

2023/12/07 02:43:10	INFO	batchsize=1024
2023/12/07 02:43:10	INFO	lr=0.01
2023/12/07 02:43:11	DEBUG	Initializing MLIR with module: _site_initialize_0
2023/12/07 02:43:11	DEBUG	Registering dialects from initializer <module 'jaxlib.mlir._mlir_libs._site_initialize_0' from '/usr/local/lib/python3.10/dist-packages/jaxlib/mlir/_mlir_libs/_site_initialize_0.so'>
2023/12/07 02:43:11	DEBUG	etils.epath found. Using etils.epath for file I/O.
2023/12/07 02:43:11	INFO	Reading training data
2023/12/07 02:43:11	INFO	train.hcpe
2023/12/07 02:43:11	INFO	Reading test data
2023/12/07 02:43:11	INFO	test.hcpe
2023/12/07 02:43:11	INFO	train position num = 87979
2023/12/07 02:43:11	INFO	test position num = 10059
2023/12/07 02:44:17	INFO	epoch = 1, steps = 85, train loss avr = 5.5062653, 0.6650221, 6.1712874, test loss = 4.4160679, 0.6728920, 5.0889598, test accuracy = 0.2020399, 0.5775825
2023/12/07 02:44:17	INFO	Saving the checkpoint to checkpoints/checkpoint-001.pth
2023/12/07 02:44:29	INFO	epoch = 2, steps = 100, train loss = 4.2624816, 0.6442503, 4.9067319, test loss = 4.1495724, 0.6723186, 4.8218910, test accuracy = 0.2109375, 0.5625000
2023/12/07 02:45:26	INFO	epoch = 2, steps = 170, train loss avr = 3.9174752, 0.6312185, 4.5486937, test loss = 3.6442114, 0.6707965, 4.3150079, test accuracy = 0.2669271, 0.5907118
2023/12/07 02:45:26	INFO	Saving the checkpoint to checkpoints/checkpoint-002.pth
2023/12/07 02:45:50	INFO	epoch = 3, steps = 200, train loss = 3.2926952, 0.5932679, 3.8859632, test loss = 3.4587047, 0.6749541, 4.1336588, test accuracy = 0.2861328, 0.5966797
2023/12/07 02:46:36	INFO	epoch = 3, steps = 255, train loss avr = 3.2352604, 0.5724498, 3.8077102, test loss = 3.3200725, 0.6847532, 4.0048257, test accuracy = 0.2860243, 0.6129557
2023/12/07 02:46:36	INFO	Saving the checkpoint to checkpoints/checkpoint-003.pth
2023/12/07 02:47:12	INFO	epoch = 4, steps = 300, train loss = 2.7979842, 0.4858817, 3.2838659, test loss = 3.1762872, 0.7170963, 3.8933834, test accuracy = 0.3134766, 0.6328125
2023/12/07 02:47:46	INFO	epoch = 4, steps = 340, train loss avr = 2.7799392, 0.4649910, 3.2449302, test loss = 3.1284448, 0.7248617, 3.8533065, test accuracy = 0.3117405, 0.6194661
2023/12/07 02:47:46	INFO	Saving the checkpoint to checkpoints/checkpoint-004.pth
2023/12/07 02:48:34	INFO	epoch = 5, steps = 400, train loss = 2.4157652, 0.3585368, 2.7743019, test loss = 3.2075515, 0.7888587, 3.9964101, test accuracy = 0.3046875, 0.6259766
2023/12/07 02:48:56	INFO	epoch = 5, steps = 425, train loss avr = 2.4379311, 0.3513481, 2.7892792, test loss = 3.0914729, 0.7854127, 3.8768856, test accuracy = 0.3243273, 0.6239149
2023/12/07 02:48:56	INFO	Saving the checkpoint to checkpoints/checkpoint-005.pth
2023/12/07 02:49:55	INFO	epoch = 6, steps = 500, train loss = 2.1247365, 0.2783431, 2.4030796, test loss = 3.1475456, 0.9264752, 4.0740207, test accuracy = 0.3164062, 0.6230469
2023/12/07 02:50:05	INFO	epoch = 6, steps = 510, train loss avr = 2.1374287, 0.2788329, 2.4162616, test loss = 3.1065659, 0.9123264, 4.0188924, test accuracy = 0.3263889, 0.6232639
2023/12/07 02:50:05	INFO	Saving the checkpoint to checkpoints/checkpoint-006.pth
2023/12/07 02:51:15	INFO	epoch = 7, steps = 595, train loss avr = 1.8456889, 0.2499077, 2.0955966, test loss = 3.1954306, 0.9700384, 4.1654691, test accuracy = 0.3297526, 0.6281467
2023/12/07 02:51:15	INFO	Saving the checkpoint to checkpoints/checkpoint-007.pth
2023/12/07 02:51:19	INFO	epoch = 8, steps = 600, train loss = 1.4058522, 0.2330416, 1.6388938, test loss = 3.2406147, 0.9426155, 4.1832302, test accuracy = 0.3417969, 0.6445312
2023/12/07 02:52:24	INFO	epoch = 8, steps = 680, train loss avr = 1.5551872, 0.2368844, 1.7920716, test loss = 3.3911205, 1.0723756, 4.4634961, test accuracy = 0.3192274, 0.6279297
2023/12/07 02:52:24	INFO	Saving the checkpoint to checkpoints/checkpoint-008.pth
2023/12/07 02:52:41	INFO	epoch = 9, steps = 700, train loss = 1.1471334, 0.2218279, 1.3689613, test loss = 3.5189421, 1.0575274, 4.5764695, test accuracy = 0.3310547, 0.6396484
2023/12/07 02:53:34	INFO	epoch = 9, steps = 765, train loss avr = 1.3002569, 0.2271768, 1.5274338, test loss = 3.5589656, 1.0003043, 4.5592699, test accuracy = 0.3293186, 0.6264106
2023/12/07 02:53:34	INFO	Saving the checkpoint to checkpoints/checkpoint-009.pth
2023/12/07 02:54:02	INFO	epoch = 10, steps = 800, train loss = 0.9361269, 0.2160465, 1.1521733, test loss = 3.7504494, 1.0659581, 4.8164076, test accuracy = 0.3408203, 0.6093750
2023/12/07 02:54:44	INFO	epoch = 10, steps = 850, train loss avr = 1.0537626, 0.2181789, 1.2719415, test loss = 3.7589464, 1.0975931, 4.8565395, test accuracy = 0.3350694, 0.6376953
2023/12/07 02:54:44	INFO	Saving the checkpoint to checkpoints/checkpoint-010.pth
```
`train loss` `test loss`が3つ、`test accuracy`の値が2つ出ていますが、それぞれPolicy Network、Value Network、Policy NetworkとValue Networkの合算に対応しています（`test accuracy`では合算の算出はなし）。
本来はlossがもっと低く、accuracyがもっと高くでてほしいのですが、いろいろパラメータをいじっても改善できず断念・・・
学習元データが少なすぎるのかもしれません。
残念ですが、とりあえず今回は動くことだけを目標にしました。

### 対局させてみる
既存の将棋エンジンである[Lesserkai](http://shogidokoro.starfree.jp/download.html)をダウンロードして対局させます。
本当は人間（私）と対局させてみたかったのですが、バージョンの問題かGoogle Colab上で対局することができず、コンピュータ同士の対局のみ行いました。
秒読みは1000ミリ秒で10回対局させて結果を見てみます(先手後手は1回ずつ交代)。

```shogi.ipynb
from cshogi import cli
cli.main('./mcts_player.sh', '/content/LesserkaiSrc/Lesserkai/Lesserkai', games=10, byoyomi=1000)

practice_01 vs Lesserkai 1.5.0 start.
まで89手で先手の勝ち
1 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 1-0-0 (100.0%)
Black vs White: 1-0-0 (100.0%)
practice_01 playing Black: 1-0-0 (100.0%)
practice_01 playing White: 0-0-0 (0.0%)
Lesserkai 1.5.0 playing Black: 0-0-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-1-0 (0.0%)
Lesserkai 1.5.0 vs practice_01 start.
まで46手で後手の勝ち
2 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 2-0-0 (100.0%)
Black vs White: 1-1-0 (50.0%)
practice_01 playing Black: 1-0-0 (100.0%)
practice_01 playing White: 1-0-0 (100.0%)
Lesserkai 1.5.0 playing Black: 0-1-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-1-0 (0.0%)
practice_01 vs Lesserkai 1.5.0 start.
まで89手で先手の勝ち
3 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 3-0-0 (100.0%)
Black vs White: 2-1-0 (66.7%)
practice_01 playing Black: 2-0-0 (100.0%)
practice_01 playing White: 1-0-0 (100.0%)
Lesserkai 1.5.0 playing Black: 0-1-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-2-0 (0.0%)
Lesserkai 1.5.0 vs practice_01 start.
まで46手で後手の勝ち
4 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 4-0-0 (100.0%)
Black vs White: 2-2-0 (50.0%)
practice_01 playing Black: 2-0-0 (100.0%)
practice_01 playing White: 2-0-0 (100.0%)
Lesserkai 1.5.0 playing Black: 0-2-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-2-0 (0.0%)
practice_01 vs Lesserkai 1.5.0 start.
まで89手で先手の勝ち
5 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 5-0-0 (100.0%)
Black vs White: 3-2-0 (60.0%)
practice_01 playing Black: 3-0-0 (100.0%)
practice_01 playing White: 2-0-0 (100.0%)
Lesserkai 1.5.0 playing Black: 0-2-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-3-0 (0.0%)
Lesserkai 1.5.0 vs practice_01 start.
まで46手で後手の勝ち
6 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 6-0-0 (100.0%)
Black vs White: 3-3-0 (50.0%)
practice_01 playing Black: 3-0-0 (100.0%)
practice_01 playing White: 3-0-0 (100.0%)
Lesserkai 1.5.0 playing Black: 0-3-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-3-0 (0.0%)
practice_01 vs Lesserkai 1.5.0 start.
まで75手で先手の勝ち
7 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 7-0-0 (100.0%)
Black vs White: 4-3-0 (57.1%)
practice_01 playing Black: 4-0-0 (100.0%)
practice_01 playing White: 3-0-0 (100.0%)
Lesserkai 1.5.0 playing Black: 0-3-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-4-0 (0.0%)
Lesserkai 1.5.0 vs practice_01 start.
まで46手で後手の勝ち
8 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 8-0-0 (100.0%)
Black vs White: 4-4-0 (50.0%)
practice_01 playing Black: 4-0-0 (100.0%)
practice_01 playing White: 4-0-0 (100.0%)
Lesserkai 1.5.0 playing Black: 0-4-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-4-0 (0.0%)
practice_01 vs Lesserkai 1.5.0 start.
まで89手で先手の勝ち
9 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 9-0-0 (100.0%)
Black vs White: 5-4-0 (55.6%)
practice_01 playing Black: 5-0-0 (100.0%)
practice_01 playing White: 4-0-0 (100.0%)
Lesserkai 1.5.0 playing Black: 0-4-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-5-0 (0.0%)
Lesserkai 1.5.0 vs practice_01 start.
まで46手で後手の勝ち
```
**対局結果**
```
10 of 10 games finished.
practice_01 vs Lesserkai 1.5.0: 10-0-0 (100.0%)
Black vs White: 5-5-0 (50.0%)
practice_01 playing Black: 5-0-0 (100.0%)
practice_01 playing White: 5-0-0 (100.0%)
Lesserkai 1.5.0 playing Black: 0-5-0 (0.0%)
Lesserkai 1.5.0 playing White: 0-5-0 (0.0%)
{'engine1_name': 'practice_01',
 'engine2_name': 'Lesserkai 1.5.0',
 'engine1_won': 10,
 'engine2_won': 0,
 'black_won': 5,
 'white_won': 5,
 'draw': 0,
 'total': 10}
```
訓練がうまくいっていないのであまり期待していませんでしたが、全勝という結果になりました。
ただログを見てみると、先手-後手の組み合わせによってほぼ全て同じ手数で終わっており、特定の勝ちパターンに入っているだけかもしれません。
今後は他の将棋ソフトとの対局も行って、棋譜も見ながら検証していく必要がありそうです。

# まとめ
[『強い将棋ソフトの創りかた』](https://www.amazon.co.jp/o/ASIN/4839977348/mynavibooks-22/)を読んで、将棋AIを開発しました。
もともと私は趣味でPythonを触っている程度で、機械学習についてはほとんど経験がありませんでしたが、きちんと動く将棋ソフトを作ることができました。
将棋ソフトの開発だけ書かれてそうなタイトルですが、序盤のディープラーニングの解説は初心者でもわかりやすく、初めてのAI開発でもスムーズに成功体験を得られる1冊だと思います。
今回はおおむね書籍の内容に沿って開発しましたが、より強い/面白い将棋ソフトの開発にも挑戦していきたいと思っています。

最後まで読んでいただきありがとうございました。
[フューチャーAdvent Calendar](https://qiita.com/advent-calendar/2023/future)はまだまだ続きます。
引き続きお楽しみください！