電王トーナメントの開催日も迫る中、やねうら王のMovePickerにバグが発見されました。
@yaneuraou move_picker_2016Q2.h の if (abs(int(v) >= 324)) ですが、これ括弧の位置が間違ってますよね?
— merom686 (@merom686) October 5, 2016
あ~これでやねうら王ライブラリのチーム全部強くなってしまう〜(´・_・`)
— 平岡 拓也(´・_・`) (@HiraokaTakuya) October 5, 2016
まあバグ発見したら報告してみんな強くなるのは非常に健全な状態だと思います!(´・_・`)
— 平岡 拓也(´・_・`) (@HiraokaTakuya) October 5, 2016
ここは、そのnodeで良かった指し手にbonusを加点するところなのですが、bonusはdepth の2乗に比例する形で与えるので√324 = 18で、depth 18以上でないと関係して来ません。depth 18以上の対局でこのわずかな変更で有意差が出るぐらい対局を回すのはいまからでは間に合いません。Stockfishを信じて修正しておくしかないです。
やねうら王の修正前のコードでは、v(bonus)が-324以下のときもbonusを加点(減点?)していたことになります。
そもそも、vの絶対値が324以上なら何故bonusを加点しなくて良いのでしょうか?
depthが深いときのオーダリングがdepthが浅いときのオーダリングにいい影響がないからなのだと思いますが、このへん、本来なら将棋に合わせてチューニングすべきです。
このif文自体、無いほうが強くなる可能性があります。値が大きくなりすぎると悪影響があるということなら、絶対値が324を超えていれば絶対値が324になるように足切りすればいいわけで…。
あるいは、本当に絶対値が324以上なら加点しないという処理なら、この呼び出し元(forループで回しているところがある)で、そのチェックをすれば、諸々の処理を端折れます。
そうして見るとこのStockfishのコードは、ちょっとおかしいのではないかと思うのですが。
本文を読む限りにおいては必要性を感じないですね。
4コア8スレッドのPCで考えるなら、
勝負に影響が最も出る中盤でもdepth18↑は2秒。
探索に負担がかかってくる終盤でもdepth18↑は5秒。
とかなので、強くなるかどうかは検証が必要でしょうが、このコード関係が無いほうが到達depthは圧倒的に早くなりそうです。
このバグ(?)を修正するとdepth(残り探索深さ)が18以上のときの挙動に違いが出るので、例えば、中盤で2秒でdepth18まで到達するとしたら、2秒目以降の思考に影響が出ます。
これを修正して、強くなるかどうかはよくわからんですが…(´ω`)
そのへんの検証は電王トーナメント終わってからですなー。
以前SMの成り駒バグ修正で、バグ修正後の成り駒の確認という項目がひとつカムだけですごい遅くなると言いましたが、
具体的には終盤付近で、
バグ有り=depth24=1億ノード
バグ修正=depth24=3億ノード
とかになります。しかし発生頻度は極めて少なく、四間飛車VS居飛車穴熊が千日手くさい状況で飛車角がチョロチョロ動き出すときとかに影響があるくらいです。
他には指し手が飽和して29飛車と引いておくとかの場合は、普通に良い手なのでバグのままでも問題なかったりします。
評価関数が限界付近に到達してきている昨今、指し手探索結果が同じようなソフト同士だと変な話、バグったままで到達depthが早いほうが全体勝率が良かったりします。
やねうら王さんクラスの一流プログラマーだと、バグは絶対に許せない気質かもしれませんが、こんなこともあるということで。
本文の内容が正しく伝わっていないのだと思うのですが、それを説明するにはこのコメント欄は狭すぎる。(本文上で言うdepthというのが「残り探索深さ」(≠ 将棋所の表示上の「深さ」)のことなのですが、この説明を詳しく書く時間がなさげです。)
すみません。余計な追加コメントをしたみたいで。
本文のバグと追加コメントのバグが全然違うのは理解しています。
同じバグという括りで違う例を書いただけでした。
本文中のコードが今までの場合、浅い探索で影響が出るので、評価関数の学習が上手くいってなかった可能性等があったぽい感じですよね?
その他、余計な仕事をしているので探索が遅くなっていたりしていたかもしれない、みたいな感じかなと捉えています。
> 本文中のコードが今までの場合、浅い探索で影響が出るので
逆です。残り探索depth 18以上のとき(将棋所で見て探索深さが19以上ぐらいから)影響が出ます。評価関数の学習自体は、depth 6で教師を生成して、depth 0で学習していますので、影響はないです。
というか、この本文のバグ修正してもR2変わるかどうかレベルだとは思います。そもそも修正したほうが強くなるかどうかすら悩ましいレベルで…。(´ω`)
まあ、そういうR1とか2を積み重ねていくのが現代の将棋ソフトなわけですね。
> やねうら王の修正前のコードでは、v(bonus)が-324以下のときもbonusを加点(減点?)していたことになります。
depth18以下のときかと思いました。逆なんですね。
だとしたら思い当たる挙動としては、やねうら王とSMを見比べると、スレッド1とかゆっくりとした探索で対局している設定で、終盤探索がきつくなってくる所で毎手depth16~20とかの設定秒数なのに、これが絶対手だと言わんばかりに突然depth23とか行くときがあります。
follow up movesがヒットしたにしては行き過ぎで、正体不明の現象だったのですが、コレ関係?
> 設定秒数なのに、これが絶対手だと言わんばかりに突然depth23とか行くときがあります。
それはLazySMPの影響ですね。本文の処理部分は、そのnode(局面)で良かった/悪かった指し手に対してhistoryにbonusを加点/減点する部分なのでオーダリング(指し手の並び替え)に影響があるのですが、将棋所上で見えてくる部分ではないと思います。指し手/読み筋にもほとんど影響ないと思いますし。
なるほど。本文の処理部分は理解できました。
ただ上記はスレッド1対局でして、LazySMPの影響では無いと思いますので、変な挙動が確認されればまた報告したいと思います。
はい(`・ω・´)ゞ
簡単のためStatsのupdate()のコードが下記だけだったとして
仮に同じbonusが続いた場合のstatsの値を計算してみました。(初期値0)
void update(Piece pc, Square to, Value bonus) {
table[to][pc] -= table[to][pc] * abs(int(bonus)) / 324;
table[to][pc] += int(bonus) * 32;
}
・bonus=100が続く場合
0→3200→5412→6942→7999→…→10368に収束
・bonus=200が続く場合
0→6400→8849→9787→10146→…→10368に収束
・bonus=300が続く場合
0→9600→10311→10364→10368→…→10368に収束
・bonus=324が続く場合
0→10368→10368→10368→10368→…→10368に収束
・bonus=400が続く場合
0→12800→9798→10502→10337→…→10368に収束
・bonus=500が続く場合
0→16000→7309→12030→9465→…→10368に収束
・bonus=648(=324*2)が続く場合
0→20736→0→20736→0→…
・bonus=1000が続く場合
0→32000→-34765→104535→-186104→…→発散
bonusが324以下の場合は単調増加で、しばらくすると10368(=324*32)に収束するのですが、
bonusが324を超えると単調増加ではなくなり、
bonusが1000などになると、激しく振動して発散してしまいました。
bonusの絶対値が324を超えると、加点しているつもりが減点されてしまったりするので
if文でreturnしたり絶対値324で足切りしたりしているのかと思います。
(あと、statsの値を-10368~10368の範囲に収めたいという意図もあるのかもしれません。)
CounterMoveStatsの場合は324のところが936になるので
収束する値が29952(=936*32)になり、
bonusの絶対値が936を超えると増減がおかしくなる場合が出てくるようです。
はい、そこはEMA(指数移動平均)みたいなことしてあるので、returnしないなら324で足切りするべきでしょうね。おっしゃる通り、最悪の場合、発散します。