Aoba振り飛車とAobaZeroとの違い

振り飛車の定義
飛車を振ることにボーナスを
headに追加するだけでは振ってくれない
自己対戦では先手、後手は完全に独立した探索
振る筋の生成確率
どこに飛車を振っても勝率5割に調整
人間の知識使ってますよね?
他の設定
NNの入力
NNの出力

振り飛車の定義
・振り飛車の定義は不明なので、11手目から24手目までの先手後手、各7局面で一番多い回数存在した筋をX筋飛車、とします。
・例えば先手の飛車が6筋に3回、7筋に4回いた場合は3間飛車です(▲78飛、なら7筋なので3間飛車)
・同一回数は手数の少ない方を優先。すべて0の場合は居飛車としてます。
・飛車が2段目以外にいる場合も数えます。例えばひねり飛車も振り飛車(3間飛車)と判定されます。
・11手や24手に根拠はないです。人間の場合は6手目に飛車を振ることが一番多いです。
・人間の感覚だと先手は5筋より左に飛車がいて(縦には動かない)、王が右側の場合を振り飛車、としていると思います。
 矢倉中飛車やひねり飛車は居飛車に分類されてる感じです。

飛車を振ることにボーナスを
・1筋から9筋まで、すべての筋に飛車を振ってどんな指し方になるか調べます。
・先手、後手ともに振ります。先手四間飛車、後手向飛車、の相振りなども含みます。
・人間の知識は与えません。
・ただし、そのままだと飛車を振ることはないので、希望した筋に飛車を振れた、場合にボーナスを与えます。
・ボーナスは

    (実際の勝敗)*(1-a) + (希望した筋に飛車を振れた)*a

  とします。a=0.3 です。
  つまり希望する筋に飛車が振れた場合に0.3勝った、とするわけです。実際は

    (実際の勝敗+探索勝率)/2 * (1-a) + (希望した筋に飛車を振れた)*a
    a = 0.3 - 0.3/(80-24)*(手数 - 24)

  となっています。「希望した筋に飛車を振れた」のボーナスは25手目から徐々に下がり80手目に消える、ようにしてます。
  24は24手目でどの筋の振り飛車かが決定するためです。
  MCTSの探索が深いと初手からの探索でも深さ24手目以上を探索してまうため、こうしています。
  この値は試行錯誤中です。

・この値を大きくすると負けても飛車を振る、ようになります。
・この値を小さくしつつ、希望する筋に飛車を振れるようにすることも目的の一つです。
・ニューラルネットワーク(NN)の入力には希望する振り飛車の筋、を与えます。
・1筋から9筋まで、それぞれ1面(9x9)のOne Hotです。
・3間か4間のどちらか、など2から9個所まで複数の希望する筋を指定可能です。9個所だと「どこでもOK」です。
・自分の希望のみで、相手がどんな振り飛車を目指すかは教えません。
・1168万棋譜から個別の筋に対してボーナス、に切り替えました。
  「希望した筋に振れた」場合に「実現した筋」の個別ボーナスにしたのですが成功率がどんどん下がっていったため、
  「希望した筋」の平均のボーナス、にしたところ安定しました。複数希望があるため。

headに追加するだけでは振ってくれない
・最初はPolicy head, Value headと同じように「希望する筋に飛車を振れたか Head」を試したのですが、
  まったく着手に影響を与えなかったので勝率(Value)に直接影響を与えるようにしました。
  希望する筋に振れたか、の判定だけ上手くなる感じでした。
・学習側でValueのlossに影響を与えていますが、MCTSの探索で報酬に組み込む(valueに足す)手法もあると思います。

自己対戦では先手、後手は完全に独立した探索に
・NNの入力では自分の希望する振る位置のみ与えてるので大丈夫だろう、と思っていたのですが
  650万棋譜まで学習させた時に▲居△中、▲居△4間のノイズなしサンプルで
  先手の初手が変わってるのに気づきました。▲居△中の初手は▲76歩で、▲居△4間は▲96歩です。
  原因は探索内部では先手番では居飛車を希望、後手番では中飛車(4間)を希望、としていたことでした。
  このため探索すると相手が4間の場合▲96歩の方が得、になります。
  Weightは同じで乱数要素はないです。
  これは求めるNNではないので、探索中にRootの手番でない方は常に「どこに振ってもOK(111111111)」を
  与えるようにしました。ハッシュ表もRoot先手番、Root後手番で分けてます。

振る筋の生成確率
・どの振り飛車の棋譜をどんな割合で生成するか、は人間(私)が指定します。学習初期はすべて同じ確率です。
・先手が(1筋から9筋+複数)、後手が(1筋から9筋+複数)。複数は2か所から9個所までを指定します。個々の筋の生成確率で選びます。
・先手(1から9筋)、後手(1から9筋)、先手(1から9)後手複数、先手複数 後手(1から9)、複数の割合(2-9)、8種類。
 で 9*9 + 9*2 + 8 = 107 個の確率値。
・最終的には人間が指す棋譜の割合に近づける予定です。ただし相居飛車の棋譜は除きます。
・「先手1間飛車、後手3間飛車」、「先手3間飛車、後手居飛車」も同じ割合で生成しています(学習初期の現在)。
・最初は勝率の調整で出現確率もコントロールで出来る(9間飛車の出現割合が低ければ少し勝率を上げてやる)かと思ったのですが、
 あまりにも不安定そうなのと、どこに振るか指定できないと面白くないので見送りました。

どこに飛車を振っても勝率5割に調整
・1間飛車などは勝率が悪いことが予想されるため、どの筋に飛車を振っても勝率5割になるようにハンデを与えます。
・勝率が悪いと1間飛車を指定しても指してくれない(勝率のボーナスを増やさないといけない)、が予想されるためです。
・ハンデの与え方はAoba駒落ちで同じです。Rootの着手を最大探索回数の手でなく、探索回数の分布を元にしたSoftmaxの温度で選びます。
・(先手4間、後手3間)の相振りの直近1000局の勝率が0.543(+30) だった場合、その半分 +15 をハンデに追加します。
・前回の更新が50万棋譜(Replay Buffer)以前で1000局未満、例えば600局の勝率が 0.557(+40) だった場合は
  2000/600=3.3、 +40 / 3.3 = +12 をハンデに追加します。

人間の知識使ってますよね?
・人間の知識なし、と書きましたが厳密には「振り飛車の定義」、「Valueにボーナスをつけて学習」は人間の知識が入ってると言えます。

他の設定
  基本的にAlphaZeroと同じ設定です。以下は先頭が「=」は同じで「違」が異なる点です。
=・513手目を指せれば引き分け
=・Rootの手にはディリクレノイズを常に追加
違・Policyは、そのままでなく温度1.8のsoftmaxで平坦にして、順位が下位の手も探索されやすいように。
=・飛角歩の不成も生成。
=・30手目までは温度1のsoftmaxで着手を選択。31手目以降は基本は最大回数の手を選択。
違・31手目以降は81種類のハンデELOに対応した温度のsoftmaxで選択
違・30手目までで現在のハンデELOが443以上(温度1以上)なら、その温度のsoftmaxで選択
違・3手詰をすべてのノードで。また探索した訪問回数に応じてdfpnでの詰将棋も。
=・投了あり。投了しない棋譜を10%の割合で生成し、95%以上の投了が成功するように投了の勝率を自動調整。
=・1手800playout固定。MCTSで探索。UCBのパラメータはAlphaZeroと同じ cBASE = 19652, cINIT = 1.25, 勝率の初期値は負け。
=・探索部はAobaZeroと同じ。探索内部で千日手、持将棋宣言判定あり。
違・cPUCTを動的に変更。評価値の変動が大きい場合はcPUCTも大きく。
違・王が逃げる手が1手だけは1手延長。
違・Valueの学習を「棋譜の勝敗」でなく「棋譜の勝敗」「探索結果」「飛車の希望筋に振れたか」の混合に。
違・直近の50万棋譜(初期は10万棋譜)の全局面から128局面を乱数で選びミニバッチを作成して1回学習。
 ・10000回学習するごとに重みを作成。1棋譜平均128手なら、1局面を1回学習する割合。
 ・2分に一度、追加された棋譜数ぶんだけReplay bufferを更新して学習。

NNの入力
1. 盤上の駒の配置、先手、後手で14x2の28種類
  歩、香、桂、銀、金、角、飛、王、と、杏、圭、全、馬、竜 ... 14種類。
2.* 持ち駒の数、7種類x2、で14種類。最大数(歩なら18)で割った値。
3.* 過去に同一局面になった回数。1,2,3回。1回なら100、3回なら111と全部の面が1。

 (1),(2),(3)の合計45(28+14+3)を現在局面のみ(過去局面はなし) 45*1=45 種類。

4.* 希望する飛車を振る筋。9種類。
5. 盤上の駒が動ける位置。先手、後手で14x2の28種類。現在局面のみ。
6. 利きの合計数。0,1,2,3,4以上で5種類。を先手、後手で10種類。3なら 00010 と一つの面のみが1。現在局面のみ。
  間接の利きも含む。例えば平手の初形で26の地点の先手の利きは歩と飛で2、となる。
  16の地点も香車が利いて2、仮に17も香車なら13の地点の利きも2になる。
  例外として長い利きは相手の王は存在しない、として通過する。
  https://github.com/yssaya/komaochi/blob/master/src/usi-engine/bona/yss_net.cpp#L1478
7.* 王手がかかっているか。1種類。現在局面のみ。
8.* 現在手数。512で割る。1種類。
9.* 手番。1種類。

「*」がついている項目は9x9が全部同じ値です。持ち駒の数と手数以外は0か1。

合計で 45 + 9 + 28 + 10 + 1 + 1 + 1 = 95 種類。95 x9x9 = 7695 個のfloat。
(実際は全部0の面が他に267あり、362x 9x9。これはAobaZeroからの変更を減らすため)

NNの出力
1. 着手の確率(policy)。27x 9x9 = 2187通り。詳細は下記を。
  policy headの構造をdlshogiと同じ2187通り。
  http://www.yss-aya.com/bbs_log/bbs2021.html#bbs22
2. 勝率(value)。-1から+1までを返す。1通り。

合計 2187+1 = 2188個のfloat

ネットワークの構造はAlphaZero(AobaZero)と同じ、3x3のfilterが256個、ResNetが20blockです(256x20b)。
400万棋譜ぐらいまでは128x10b で。