はじめに
将棋AI「技巧(ぎこう)」を自分の手で訓練して強くしてみる開発日記、第5回です。
ついに全パーツが揃い、将棋GUIに載せて実戦投入します。そして名前も付けます。……が、対局中にクラッシュします。
技巧の本家リポジトリはこちら(オープンソース・GPL)。
前回までのあらすじ
-
第1回:技巧をビルドして起動、
score cp 0(知識ゼロ)を確認
- 第2回:floodgateから棋譜12.8万局を集め(後手勝ち消失バグを修正)、進行度を学習
-
第3回:評価関数を13時間学習、
score cp 0を卒業
- 第4回:指し手の実現確率を学習(メモリ49GBを使い果たすやらかし付き)
そして第4回のラストで「この実現確率モデルが、後でクラッシュの原因になる」と予告しました。今回はその回収回です。
相変わらず Claude(Claude Code)と一緒に やっています。
定跡も作って、ついにフル装備に
最後のピース、定跡データベースを作ります。
./bin/release --create-book
これで progress.bin/params.bin/probability.bin/book.bin が全部揃い、技巧が"フル装備"になりました。
Gikou(フル装備)
├─ プログラム本体 ✓
├─ 進行度(progress.bin) ✓
├─ 評価関数(params.bin) ✓
├─ 実現確率(probability.bin) ✓
└─ 定跡(book.bin) ✓
(余談:定跡作成も第2回と同じ「7大棋戦だけ採用するフィルタ」が効いていて、最初は中身が空っぽでした。floodgate棋譜を使うようフィルタを外して解決。本当に同じ罠に何度もかかります。)
命名:「パンくん」誕生
せっかく自分で育てたAIなので、名前を付けました。
まだプロトタイプ版ということで、人間の3歳児程度の知能を持つといわれるチンパンジーの「パンくん」に敬意を表し、本AIを「パンくん」と命名しました。強さ調節機能はないので強すぎる可能性もあります。
「3歳児程度」と言いつつ、中身は世界コンピュータ将棋選手権で準優勝した技巧の探索エンジン+自前学習の評価関数なので、たぶん人間にはまあまあ強いです。強さ調節を実装していないので、対局相手としては容赦がありません。ごめんね。
研究室メンバーに配りたい → 配布物(zip)の作り方
完成したパンくんを研究室のみんなにも触ってほしい。でも、ここで問題が。
僕の技巧は WSL(Windows上のLinux環境)でビルドしたLinuxの実行ファイルです。これをそのまま渡しても、Windowsの将棋GUIからは起動できません。WSL経由で起動するラッパーも考えましたが、各自のPCのWSL設定に依存してしまい、配布物として現実的じゃない。
そこで、WSL不要・DLL不要で単体で動くネイティブWindows版をクロスコンパイルすることにしました。技巧のMakefileには元々Windows向けビルド設定(gikou ターゲット)があるので、mingw-w64というクロスコンパイラを使えば一発です。
# posix版mingwを使う(技巧は std::thread / OpenMP を使うため)
make gikou CXX=x86_64-w64-mingw32-g++-posix
# → bin/gikou.exe(静的リンクのWindows実行ファイル)が生成される
あとは、gikou.exe と学習データ一式を同じフォルダにまとめてzipにするだけ。将棋GUIはエンジンの.exeがあるフォルダを基準にデータを読むので、この構成でそのまま動きます。
Pankun_Gikou_trained/
├─ gikou.exe ← ネイティブWindows版(WSL不要)
├─ params.bin ← 評価関数
├─ progress.bin ← 進行度
├─ probability.bin ← 実現確率
├─ book.bin ← 定跡
└─ README.txt
zipがデカすぎて貼れない → GitHub Releasesへ
できたzipは約153MB(評価関数の params.bin だけで259MBあるので…)。社内wikiに直接添付しようとしたら「大きすぎ」と弾かれました。
そこで GitHub の Releases にアップロード。Releaseのアセットは最大2GBまでOKで、リポジトリ本体を太らせずにダウンロードURLが手に入ります。これで誰でもURLから落とせるようになりました。
いざ実戦 → そしてクラッシュ
将棋GUIにパンくんを登録して、いざ対局。序盤は普通に良い手を指してくれて「おお〜」となったのですが、中盤、局面が複雑になってきたあたりで、パンくんが突然沈黙 → 時間切れ負け。
何度やっても、複雑な局面で落ちる。これはおかしい。Claudeと一緒に原因を追いました。
デバッグ版で再現させたところ、エンジンは時間切れではなく**プロセスごとクラッシュ(segfault)**していました。GUIからは「応答が来ない=時間切れ」に見えていただけだったのです。そしてクラッシュ箇所は――
第4回で学習した、あの実現確率モデルでした。
仕組みはこうでした。深い探索(複雑な局面ほど深く読む)で実現確率を使うとき、
- 「合法手の数」と
- 「実現確率モデルが返す確率の配列の長さ」
が、ある条件で食い違うことがあり、配列の範囲外にアクセスして落ちていました。普段の浅い探索では踏まないので、序盤は平気で、複雑な中盤で初めて牙をむく、という厄介なバグでした。
修正はシンプルに、配列の範囲を絶対に超えないようガードを入れるだけ。
// 確率の数を超えてアクセスしないようにする(範囲外アクセス=クラッシュ防止)
double pr = (i < probabilities.size()) ? probabilities[i] : 0.0;
これで複雑な終盤までクラッシュしなくなりました。実現確率モデルもそのまま有効なので、強さも落ちていません。直したexeで再ビルド&再配布して、一件落着。
教訓:AIが「時間切れ負け」しても、時間管理を疑う前に"そもそも生きているか"を疑え。 今回は完全にクラッシュ(突然死)でした。
遊びかた
というわけで、安定版のパンくんで遊べます。
-
将棋GUIをインストール
-
パンくんのzipファイルをダウンロードして展開
-
GUIにパンくんを追加
-
遊ぶ
- メニューバーの対局
- 先手・後手の持ち時間等を設定
- 対局開始をクリック
持ち時間は10分切れ負けくらいが無難です(強さ調節がないので、短時間でも普通に強いです)。
ここまでのまとめ
ゼロから始めて、対局できるところまで来ました。
第1回 ビルドして起動(score cp 0)
第2回 棋譜を集めて進行度を学習
第3回 評価関数を13時間学習(score cp 0 卒業)
第4回 実現確率を学習(メモリ事件)
第5回 定跡を作り、GUIで対局、クラッシュを直して配布 ← イマココ
棋譜集めから学習・ビルド・配布まで一通り自分の手で回せて、「パンくん」として人に渡せる形になりました。途中、後手勝ち消失バグ・初手投了・OOM・クラッシュと毎回やらかしましたが、そのたびにClaudeと原因を追うのが一番面白かった気がします。
次回予告:パンくんを"もっと強く"する方針を考える
ここまではあくまで「ひとまず動いて対局できる」プロトタイプ。パンくんはまだ伸びしろだらけです。次回は、どの方向で強化していくかの作戦会議をします。候補はざっとこのあたり。
-
① 学習データの洗練
今回はfloodgateの棋譜を"全部入り"で使いましたが、中身は強いエンジンから弱いエンジンまでピンキリ(第2回のEDA参照)。レート上位エンジン同士の対局に絞る、重複を除く、局数を増やす…など、データの質を上げるだけでも評価関数は変わりそう。一番お手軽で効果が見込める王道。 -
② 強化学習(RootStrap/自己対局)
技巧には自己対局・自己探索で評価関数を磨く強化学習の仕組み(--generate-positions→--learn-with-rootstrap/--learn-with-regression)が入っています。本家技巧も、これを繰り返して段階的に強くなったとのこと。"棋譜から学ぶ"の次の"自分で打って学ぶ"フェーズ。 -
③ 別アルゴリズム(NNUE・ディープラーニング系)
そもそも評価関数の作り自体を、今どきの NNUE や ディープラーニング系(dlshogi等) に置き換える大改造ルート。第3回の余談で「技巧の学習にGPUは使えない」と書きましたが、こっちに行けばついにRTX 4090の出番。ただし技巧の枠から大きく外れる寄り道になります。
①の手軽さ、②の本格さ、③のロマン。どれから手を付けるか、次回じっくり検討します。パンくんはまだ3歳、これからの成長にご期待ください。
つづく。
