「NNUEのネットワークサイズってNNUEの作者の那須さんが最適なものを選んでるんでしょ、いまさら工夫しても無駄だよ」という声がどこからともなく聞こえてきたのでここで反論しておきます。
那須さんは、開発当時、AVX2のCPU環境ですらありませんでした。NNUE評価関数のSSE4実装があるのは、ご自分のPCで動かすためでした。教師生成もするような計算資源もなく、やねうら王プロジェクトで公開していた教師局面データを用いて実験したとのことでした。まず、この意味において、やねうら王プロジェクト自体が(実験のための基本的なインフラを提供したという意味で)NNUEの開発に大きく貢献していたと言えると思います。
とりあえず、そんな事情ですので、ネットワークサイズに関しては十分な実験がなされているわけではありません。ただ、わりと最適値に近い値であることはその後の他の開発者の追試によりわかっています。
現在、評価関数の実行時間は全体の4割程度です。(実行環境で多少異なる)
「CPU cacheにNNUE評価関数のパラメータがちょうど収まるぐらいであるから、いまのネットワークサイズが最適」という意見もありますが、私はその点についてはやや懐疑的です。
仮に、NNUE評価関数のパラメーターがどれだけ大きくなってもCPU cacheに収まるとしても、評価関数の実行時間が2倍になっただけで、評価関数の実行時間 0.4×2倍 + 評価関数以外の時間 0.6 = 1.4 (1局面に要する時間が元の1.4倍、npsは28.6%ダウン)となります。
評価関数の実行時間が2倍になるようにネットワークサイズを大きくした場合、どれだけ強くなるのかという話なのですが、探索ノード数1M局面に固定した場合の対局でR5以下の差のようです。(計測できないレベルの差) 探索ノード数がその2倍になるとR10、4倍でR15と、差が広がっていくのかも知れませんが、そこまで計測しきれてないです。仮にそうだとしても、ちょっとやそっとでnps(探索速度)が下がった分だけ強くすることは不可能のように思えます。
そもそもで言うと、AlphaZeroのようなDeep Learning系の評価関数は、NNUE評価関数の100倍以上の計算時間を必要とするわけで、そのような時間のかかる評価関数でも思考時間を2倍にしたときにR250すら増えないということは(NNUEでR200~R210程度)、評価関数に要する計算時間を2倍にしたところで、ここがR5変わるかどうかという予想はつきます。
ここから、将棋というゲームでは、大局観(評価関数の質)でカバーできるのは、ごく僅かであるという、そういうゲームの性質のようなものが見えてきます。まあ、終盤で詰みを読み切るにはある程度局面を読まないと話にならないですからね…。
Stockfishに採用されたNNUE評価関数ですが、先後の駒の点数の総和の差が小さい時にのみNNUE評価関数を呼び出す改良が入りました。こうやってnpsを稼いだほうが強くなるそうです。
1 2 3 4 5 6 |
Value Eval::evaluate(const Position& pos) { bool classical = !Eval::useNNUE || abs(eg_value(pos.psq_score())) >= NNUEThreshold * (16 + pos.rule50_count()) / 16; Value v = classical ? Evaluation<NO_TRACE>(pos).value() : NNUE::evaluate(pos) * 5 / 4 + Tempo; |
チェスのほうは駒得がわりと正義なので、将棋とはまた事情が違うのかもしれません。また、チェスの元の評価関数はわりと軽めでしたので、NNUE評価関数にするとnpsがかなり下がるようで、終盤はそれだと読み負けするそうです。
しかしまあ、将棋のほうでも状況によっては同様の考え方はできるかもですね。(例えば終盤では小さなネットワークのNNUE評価関数を用いて、序盤は逆に、いまより大きなNNUE評価関数を用いるなど)
ともかく、デフォルトのNNUE評価関数のネットワークサイズは絶対ではないので、「どうせ那須さんや他の開発者がすでにやり尽くしているだろう」みたいには思わないで欲しいです。
そうですね。一昨年色々試しましたが当時はRyzenの選択肢がなかったので今やると結構最適値が変わるかもしれませんね。特に可変型ってのが楽しそうです。
そして、定跡部と、序盤と中盤、終盤の棋力の4つを個別に計測しないといけない時代に突入…。
「評価関数以外の時間 0.6」の内訳は、主に読みの量で占められてるんでしょうか?
可変ネットワークサイズも、効果があるとすればエキサイティングな話題ですね(・∀・)
> 「評価関数以外の時間 0.6」の内訳は、主に読みの量で占められてるんでしょうか?
evaluate()以外のすべての時間なので千日手のチェック、指し手生成~指し手オーダリング(良い順に並び替え)、枝刈りするかの判断、局面を1手進める、局面を1手戻す、みたいな時間ですね。
そもそも終盤かどうかの判定がものすごく難しいんですよね。
それがはっきりすれば詰み探索df-pn+を使いだすタイミングがわかるわけですし。
可変サイズ、可変深層構造、これも学習により決められたら・・・・夢が広がるなー。
勿論実行時はその学習結果に基づく固定で。
SIMD命令用の汎用的なデータ構造とか、頭痛そう。
> そもそも終盤かどうかの判定がものすごく難しいんですよね。
進行度はKPだけでわりと簡単で正確に(小さな計算コスト、小さな実装コストで)、求まりますので…。
古くはやねうら王系では読み太が導入していました。
知りませんでした。ありがとうございます。
>> CPU cacheにNNUE評価関数のパラメータがちょうど収まる
『深掘り!「AMD Next Horizon」 – Zen 2 / 7nm EPYC、Deep Dive (4) EPYC“Rome” | マイナビニュース』とか見ると、呪文のようで何書いてあるかさっぱりだけどL4 Cacheって書いてある。zenってL4 まであるんだ
ネットワークサイズって小さく小さく小さく小さく小さく小さくしてくとどうなるんだろ。やっぱり突拍子もない手を打つんだろうか
> ネットワークサイズって小さく小さく小さく小さく小さく小さくしてくとどうなるんだろ。
K-P-256の評価関数でも指し手自体は普通なので(標準NNUEと比べるとR50程度弱かったですけども)、まあ、それくらいの棋力帯においては、突拍子もない指し手で勝てるほど将棋は甘くないのかも。
よく読むとL4 Cacheと書いてある図4について「これらを元に、I/Oチップの内部を推定したのが図4」と書いてあります。AMDの資料でもL4があるようなことは一言も書かれていないので外れた予想だと思われます。