はじめに
https://rikiyat.github.io/blog/weight-space-programming/ でLLMにネットワークの重みを直接書き換えさせるのが話題になっていたので試してみた。
今回はWCSC36で使用したResNet36x512のモデルからResNet10x154への蒸留と強化を試してみた。 来年のWCSC37ではハードウェアの都合上大きなモデルを搭載できないため、知識蒸留等を行って小さいモデルで精度を上げる必要があるが、これがうまくいけばほとんど学習をさせずにモデルの精度を上げられるとの目論見がある。
実験条件
今回はGitHub CopilotでモデルをClaude Opus5.5をに設定して実験を行った。
ネットワークの重みはONNX形式で渡した。 ただしGitHub CopilotのClaude Opus5.5だとONNXファイルを直接読み込むことができなかったため、プロンプトでONNXファイルのパスを与えて読み込ませた。
機械学習ライブラリやcshogiなどのツール及び学習データ・棋譜の使用は学習用途以外での使用のみ認めた。
また、プロンプトで以下のリンクを渡し、この手法に則ってパラメータを編集するように指示した。
https://rikiyat.github.io/blog/weight-space-programming/
モデルの解析
手始めにResNet35x512とResNet10x154のモデルの解析をさせ、どのブロック・チャンネルでそれぞれどのような役割を担っているか解析させてみた。 それらしい解析結果が出てきたが検証のしようがないため正しいかどうかは不明である。
ResNet35x512
LLMの解析結果をそのまま貼る。
個別の特徴で最も重視されているのは、自玉と敵玉の利き、利き数1以上、歩と香です。代表的なチャンネルは次のとおりです(3×3カーネルは、ほぼ中央の1マスだけに重みがあります)。 玉と金のチャンネル(ch470、ch237、ch86、ch418)は、多くのブロックが読みに行く中心的なチャンネルです。後段で生まれる重要なチャンネルも、主にこの4本から作られています。 fc 層の ReLU を無視して線形近似した値です。正の値は手番側の勝率を上げる方向を意味します。 まとめると、評価は玉の安全度(ch329、ch500)が中心です。そこに、大駒の成り駒(自馬は+、敵の馬・竜は−)と自分の利きの厚み(ch166) が加わっています。盤上のマス別に見た value の感度は、四隅と盤の端が大きくなりました。これはゼロパディングによる影響を含むので、そのまま「隅が重要」とは読まないでください。 ch309 と ch397 は、ほぼすべての移動ラベルで上位に入ります。「何かが動ける」ことを表す汎用のチャンネルです。 成るかどうかで使われるチャンネルが分かれます。不成では ch397 と ch309、成りでは ch317・ch469・ch448 が中心です。 桂の移動では ch224・ch324・ch218 が専用に使われています。 駒打ちは、持ち駒を表すチャンネルと直接つながっています。 なお、打歩は ch174・ch172 で、持ち駒の歩 ch297 は59位と、つながりは弱めです。 value の上位30本と policy の上位30本は1本も重なりません。 最後の段階で、評価用と指し手用にチャンネルの役割がはっきり分かれています。ResNet35x512 の解析結果
全体の構造
入力層:生の入力情報を受けるチャンネル
入力カテゴリ
1特徴あたりの重みの大きさ
利き数(自・敵)
3.7〜3.9(最大)
駒の配置
約3.0
利き
約2.7
王手
1.5
持ち駒
約0.5(歩の5枚目以降はほぼ0)
value(局面評価)に効くチャンネル
ch
寄与
内容
主に書き込むブロック
329
−43.2
途中で生成。主に自玉・敵玉・敵金・自金の情報から作られます。玉の危険度に相当する特徴だと推測されます
14、15、18
500
+32.5
ほぼ途中で生成。元は自玉・敵玉・自金・自銀です。玉の安全度か、相手玉を攻めている度合いと推測されます
13、8、7
263
+19.2
自馬(敵の香とは逆符号)
33、34、29
328、331、507
+11〜17
途中で生成
中盤〜後半のブロック
166
−15.0
自分の利き数が少ないほど評価が下がる(利きの薄さ)
18、7、17
17
−14.5
敵の馬・角・竜
34、28
375
+12.9
自分の持ち駒の桂
33、34
470
−10.9
自玉
33、32
4
+10.8
敵玉の利き
20、7
23
−9.6
敵の竜・飛
34、1
policy(指し手)に効くチャンネル
ResNet10x154
LLMの解析結果をそのまま貼る。
ResNet10x154 の解析結果
全体の特徴
残差ブロックの役割
ブロック
書き込み量
役割(推定)
無効化すると減る手(倍率)
無効化の影響(policy loss / value の誤差)
書き込みの大きさと相関する局面の特徴
0
0.141
局面の基本情報の組み立て。自分の利きの数を整理する(ch80「利き2以上」、ch23「利きちょうど1つ」)、飛・竜の利き(ch68)
打歩 0.67、上成 0.69
+0.702 / +0.531(policy への影響が9ブロック中最大)
盤上の駒の数 +0.50
1
0.118
入玉の検出(相手の利きのチャンネル ch52 に書き込む)
上成 0.77、打飛 0.78
+0.372 / +0.385
自玉の入玉 +0.36、敵玉の入玉 +0.37
2
0.123
両玉の周りの攻防の評価(敵玉と敵玉の利き ch125 に書き込む)
打金 0.74、打銀 0.78
+0.269 / +0.354
自玉の周りの相手の利き +0.38、敵玉の周りの自分の利き +0.38
3
0.124
両玉の周りの攻防(桂・香を使う攻め。自玉の利き ch37、相手の持ち桂 ch60 に書き込む)
打桂 0.83、打香 0.89
+0.209 / +0.369
自玉の周りの相手の利き +0.31
4
0.131
桂を使った攻防(ch60、ch73、両玉の利き ch62 に書き込む)
打角 0.84(桂左は1.33倍、打飛は1.24倍に増える)
+0.289 / +0.437
自玉の周りの相手の利き +0.23
5
0.148
入玉・終盤での玉の位置(自玉 ch85)と相手の飛車(ch126)
打歩 0.70
+0.310 / +0.387(王手のかかった局面の value に大きく影響)
入玉 +0.29〜0.33、盤上の駒の数 −0.27
6
0.157
大駒が下がって成る手(相手の飛・竜の利き ch116、角・馬の利き ch102 に書き込む)
左下成・右下成 0.08
+0.299 / +0.122(value への影響は小さい)
目立った相関なし
7
0.170
駒打ちの種類の選択(自玉の利き ch108・ch117 に書き込む)
打角 0.51、打桂 0.61(打飛は1.48倍に増える)
+0.277 / +0.137(value への影響は小さい)
相手の持ち駒の数 +0.21
8
0.190
王手の局面の処理と、横に動いて成る手(自玉の利き ch108・ch14・ch109 に書き込む)
右成 0.06、左成 0.08
+0.472 / +0.598(王手のかかった局面の value への影響が最大)
王手 −0.27
9
0.522
出力の最終組み立て。ブロック8が作った横成りの候補を絞り込む。value が最も強く読む ch79 への書き込みの大部分を担う
上 0.39、左上 0.29(左成・右成は約12倍に増える)
+4.028 / +3.418
王手 −0.55
残差チャンネル(ブロック間の154本)の主なもの
駒の配置を表すチャンネル(入力層での意味)
ch
入力層での意味
備考
57
自玉
ブロック0・2・3・4・5・9が読む。大きいモデルの ch470 に相当(方向の類似度 0.92)
41
敵玉
ほぼすべてのブロックが読む中心的なチャンネル。大きいモデルの ch237 に相当(0.93)
100
自金・と・成香
大きいモデルの ch86 に相当(0.92)。ブロック9が読む
148
敵金・と・馬
大きいモデルの ch418 に相当(0.93)。ブロック3が読む
12
敵竜・飛
大きいモデルの ch23 に相当(0.94)
107
敵角・馬
大きいモデルの ch17 に相当(0.79)
64
自馬・竜
大きいモデルの ch263 に相当(0.73)
133
自角・馬
大きいモデルの ch346 に相当(0.95)。ブロック7が読む
88
自飛・竜
大きいモデルの ch340 に相当(0.96)。ブロック6・7が読む
20
敵玉の利き
大きいモデルの ch4 に相当(0.72)
82
相手の利き1以上・自飛
ブロック4〜8が読む
98
自分の銀・香・金
ブロック9が読む。policy では左下(−0.54)・桂左(−0.52)を抑える
policy に直接効くチャンネル
ch
入力層での意味
policy での使われ方
補足
0
自分の歩の利き
上 +0.61、上成 +0.38
歩を突く手を支える。大きいモデルの ch220 に相当
58
敵の飛・角・銀・桂・金
上 +0.50、左上 +0.44、右上 +0.42
敵の駒の前に上がる手を押し上げる
15
途中で生成
上 +0.32(上の重みは全チャンネル中4位)、上成 −0.19
銀や金が前の空きマスへ上がれることを表す。ブロック8・9が強く書き込む
136
自分のと・との利き
打角 −0.44、打金 −0.37、打銀 −0.27、打飛 −0.27、打香 −0.15
最終層では「敵玉に隣接する空きマス」で特に強く出る(隣接マス 1.04 / 遠いマス 0.23)。敵玉の隣への駒打ちを抑える向きに働く
123
自分の持ち金がない(自持金1 −0.18)
打金 −1.36
持っていない金を打つ反則手を抑える部品
8
相手の利きなし・敵玉の利き
打銀 +0.42、打金 +0.41、左下成 +0.31
支えのある、敵玉に隣接したマスで強く出る
83
自分の利きあり・相手の歩の利きなし
打銀 +0.56、打金 +0.49、上 +0.35、打歩 +0.29
駒打ちの候補のマスを示す
21
相手の持ち金・自金・敵玉の利き
打歩 +0.17、打銀 +0.13、上成 −0.28、下 −0.26
ブロック6〜8が重ねて書き込む
50
相手の歩が利いていないマス
打桂 −0.30、打飛 −0.26、打金 −0.12、打銀 −0.12
ブロック7・8が書き込む
23
自分の利きがちょうど1つ(入力層)
打歩 +0.32
最終層では、利きの数による値の違いがほぼなく、入力層での意味を失っている
7
相手の歩
打桂 −0.38、打銀 −0.33
ブロック4が書き込む
91
相手の香の利き
打歩 +0.30、打桂 +0.27
112
自分の銀・飛
打歩 −0.62
37
自玉の利き(負)
上成 −0.24、左 −0.22
ブロック3・5が書き込む
11
相手の香・歩の利き
打銀 −0.50、打金 −0.45
72
敵飛・敵飛の利き
打金 −0.40
34、93、135、137
途中で生成
34:上・上成を抑える/93:右上・左を抑える/135:斜めに上がって成る手/137:斜めに下がる手
value に効くチャンネル
ch
入力層での意味
役割
79
敵玉の利き +0.26、自分の利き1以上 +0.22、相手の利き1以上 −0.21
value ヘッドが最も強く読むチャンネル(value_conv1 からの読み込みの重みが全チャンネル中1位)。最終層の合計は駒の点数差(+0.60)・自分の持ち駒の数(+0.40)と相関し、優勢度に相当する。書き込みの大部分はブロック9(平均 +15.5)で、ブロック0は負(−4.4)に書き込む
3、7、11
3:利きの数の差/7:相手の歩/11:相手の香・歩の利き
value_conv1 からの読み込みが強い(平均の1.7〜2.0倍)
中間チャンネル(各ブロックの conv1 出力)で役割が特定できたもの
ブロック・中間ch
読む残差ch
書き込む先と効果
役割
b7 中間ch104
相手の歩の利き(ch120)、相手の利き(ch63)、敵玉の利き(ch43)、自玉の利き(ch96)をいずれも負で読む。周りに利きの少ない、静かなマスで働く
自玉の利き(ch96)+1.28、飛・竜の利き(ch149)+1.25、ch27 +1.13、ch142 +1.05 ほか。policy への合計効果は、左下成 −2.05、右上成 −1.95、左上成 −1.86、桂右成 −1.54、左 −1.45
静かな空きマスで成る手を抑える部品。両玉入玉の局面ではこの抑えが強すぎ、無効化すると両玉入玉の局面で policy が確かに改善する(基準の最善手への log 確率 +0.010 / +0.023)。入玉のない局面への影響はほぼ0
b9 中間ch139
敵玉の利き(ch67)を負で読む。相手の駒(ch41、ch58)を正で読む
ch24 −3.20、ch77 +2.66、ch51 +2.55 ほか(主に駒打ちの経路)。ch79 にはわずかに負(−0.18)
持ち駒を持って攻めている状態に反応(攻めとの相関 +0.30、自分の持ち駒の数との相関 +0.36)。主な役割は駒打ち
b9 中間ch62、ch131
—
ch79 に正(+0.29、+0.17)
攻めに反応する(相関 +0.26〜0.34)。ただし攻めだけに反応するわけではない
value ヘッド
value_conv1 の出力マップ(27枚)
マップ
役割
24
自玉が敵陣にいることの目印。敵陣3段の合計は、自玉が入玉していると中央値18.1、入玉していないと3.5(95%点 9.7)。1〜2段目に絞るとより分かれる(13.8 / 1.7)。自玉の位置との相関 0.526
21
敵玉が自陣にいることの目印。自陣3段の合計は、入玉していると18.2、入玉していないと1.8(8〜9段目に絞ると 13.5 / 0.9)
15
盤上の駒の数(局面の段階)。駒の数との相関 0.739(合計の平均は、駒26枚未満で10.3、39枚以上で33.6)。敵玉の位置とも相関(0.487)
18
自玉の位置(相関 0.418)
6
敵玉の位置(相関 0.355)。9段目に絞ると敵玉の入玉の目印になる
20、14
王手がかかると小さくなる(王手 8.3 / 王手なし 19.4)
12
駒の損得に反応する隠れユニットが主に読むマップ
value_fc1 の隠れユニット(154個)
ユニット
役割
25、9、104、141、27、50、142、137、41、66、74、7(value_fc2 が負)
駒の点数差に反応(駒の点数差との相関 −0.62〜−0.71、相手の持ち駒の数との相関 +0.43〜+0.56)。入玉局面では入玉なしの2〜5倍強く働き、評価を大差に振りすぎる原因になる
29、72、71、2、68、135、79、61、122、118、51、116(value_fc2 が正)
上と同じく、入玉局面で強く働き、評価を振りすぎる側に寄与する
131、96、44、24、134、43、81、31、98、76、17、69(value_fc2 が正)
攻めの評価。自分の持ち駒の数(相関 +0.33〜+0.50)と敵玉の周りの自分の利き(+0.23〜+0.43)に反応。入玉局面や攻めていない局面でも同じように働く
146、42、93
使われていない(value_fc2 の重みが約 1e−40)。93は一度も働かない
その他
154個のうち103個は、1個だけ無効化しても value の誤差の変化が0.001未満
ネットワークパラメータの書き換え
上記の解析結果を基にネットワークパラメータの書き換えを行った。
書き換え内容は以下の通り。
- 入玉ゲートの書き換え
- 入玉局面で駒の損得に過剰反応する
value_fc1の24ユニットにおいて、入玉の目印(マップ24の敵陣1〜3段、マップ21の自陣7〜9段)の重みを0.02減らした- 入玉局面での駒の損得への過剰反応を抑える狙い
- 入玉局面で駒の損得に過剰反応する
- バイアス補正
- 悲観的な評価(−0.11)を打ち消すため、
value_fc2.biasを +0.1 にした
- 悲観的な評価(−0.11)を打ち消すため、
- 評価値の補正
value_fc2の重みとバイアスを1.2倍にして、中程度の評価値を広げた- 使われていなかった隠れユニット146・42で、大差の局面における評価値の伸びを抑える折れ線を作った
この書き換えを行い、書き換え前とResNet35x512に対するvalue・loss及びテストデータに対するaccuracyの計測を行った。 テストデータにはDL将棋本付属のテストデータを使用した。(floodgate_test_2017-2018_r3500_eval5000.hcpe)
ResNet35x512に対する計測結果
| モデル | policy loss | value loss(logit の L1) | policy accuracy |
|---|---|---|---|
| 元のモデル(resnet10x154-144) | 1.4436 | 0.6178 | 69.37% |
| 書き換え後モデル | 1.4436 | 0.5787 | 69.37% |
テストデータに対する計測結果
| モデル | policy accuracy | value accuracy |
|---|---|---|
| 元のモデル(resnet10x154-144) | 0.4883 | 0.7567 |
| 書き換え後モデル | 0.4883 | 0.7546 |
| ResNet35x512(参考) | 0.5469 | 0.7840 |
ResNet35x512に対するvalueのlossを低くし、評価値のスケールを近づけることはできたがpolicyの分布を近づけることができなかった。 また、テストデータに対するvalue accuracyは書き換え前に比べてわずかに悪化した。
対局実験
パラメータ書き換え前と書き換え後でどれくらい強くなったか計測するための対局実験を行った。
思考エンジンにはやねうら王(YANEURAOU_ENGINE_DEEP_TENSOR_RT_UBUNTU)を使用し、探索パラメータはデフォルト値を使用した。
やねうら王互角局面集2025を初期局面とし、1分2秒フィッシャーで200局対局した結果を以下に示す。
なお勝率において引き分けは0.5勝0.5敗として計算している。
パラメータ書き換え前と書き換え後の対局結果
| 書き換え後モデルの勝敗 | 書き換え後モデルの勝率(%) |
|---|---|
| 77勝91敗32分 | 46.5 |
レート差は-24.4±44.4となり、有意差はなくネットワークパラメータ書き換えの効果はなかった。
対局実験の棋譜解析
対局実験の棋譜解析を行い、パラメータ書き換え後モデルの敗因を分析した。 その結果を以下に示す。
入玉の有無ごとの勝敗・勝率内訳
| 局の種類 | 局数 | 書き換え後モデルの勝敗 | 書き換え後モデルの勝率(%) |
|---|---|---|---|
| 入玉なし | 138 | 48勝60敗30分 | 45.7 |
| 書き換え後モデルだけ入玉 | 13 | 10勝3敗0分 | 76.9 |
| 元のモデルだけ入玉 | 16 | 9勝6敗1分 | 59.4 |
| 相入玉 | 33 | 10勝22敗1分 | 31.8 |
- 宣言勝ち: 元のモデル 17局、書き換え後モデル 6局
- 相入玉: うち19局は両方入玉した時点で点数負けしていた
この表から相入玉の将棋の勝率が著しく低く、正確に局面を評価できていないことがわかった。 これは入玉ゲートを書き換えた影響であると考えられる。 入玉局面の駒の損得に対する過剰反応はあくまでResNet35x512と比べたときの話であり、実際にはこれによって入玉将棋の点数勝負で有利に働いていたようだ。
対局実験の棋譜解析を踏まえたパラメータの書き換え
相入玉の勝率が著しく低くなったことを踏まえ、再度パラメータの書き換えを行った。 書き換え内容は以下の通り。
- これまでの書き換え内容の破棄
- ブロック7の中間ch104 の残差チャンネルへの書き込み要素をすべて0に
- 相手の利きや自玉・相手玉の利きが少ないマスで働き、成る手を抑制しないように
2回目の書き換え後のDL将棋本付属のテストデータに対する計測結果は以下の通り。
テストデータに対する計測結果
| モデル | policy accuracy | value accuracy |
|---|---|---|
| 元のモデル(resnet10x154-144) | 0.4883 | 0.7567 |
| 書き換え後のモデル | 0.4883 | 0.7546 |
| 2回目の書き換え後のモデル | 0.4882 | 0.7569 |
| ResNet35x512(参考) | 0.5469 | 0.7840 |
元のモデルに対し誤差の範囲内でしか精度が向上しておらず、ネットワークパラメータ書き換えの効果が薄いと判断したため、対局実験は行わずここで打ち切った。
まとめ
Weight-Space Programmingの記事を参考に将棋AIのモデルで知識蒸留・改善ができないかを検証した。 その結果、モデル内のどのブロックのどのチャンネルでどのような役割を担っているかを解析することはできたが、ネットワークパラメータの書き換えにより元のモデルより強くすることはできなかった。
今回参考にした記事がミスリーディングをしているという記事もあり、効果は限定的であると考えられる。
https://honnibal.dev/blog/astra-read-write-misleading
今後は実際に知識蒸留を試し、知識蒸留を行ったモデルと行っていないモデルでどのような差があるかLLMに解析させてみる予定である。