やねうら王の学習コマンド - mizar/YaneuraOu GitHub Wiki

やねうら王の学習コマンド

やねうら王の評価関数パラメーターを学習させるためには、学習用のコマンド(learnコマンド)を用います。

learnコマンドは、学習用のやねうら王(LEARN版)でしか使えません。

「評価関数パラメーターを学習」させることを略して、ここでは「評価関数の学習」だとか、単に「学習」と呼びます。

LEARN版について

config.hでEVAL_LEARNのシンボルを定義してあると学習用の実行ファイルができます。

配布されている実行ファイルでファイル名に"learn"とついているものは学習用の実行ファイルです。

教師生成や学習時にはスレッドごとに異なる局面を探索する必要があるため、このような特別な実行ファイルが必要になります。

💡 "gensfen"コマンドや"makebook think"コマンドを用いる時は、この学習用の実行ファイルを使いましょう。

評価関数の学習の流れ

いわゆる強化学習を用います。

そのため、

  1. 教師となる局面を自己対局によって生成
  2. 生成された教師から機械学習

という2つの手順を繰り返します。

1.には、gensfenというコマンドを用いて、2.には learn というコマンドを用います。

また、学習させる前に局面をシャッフルしたほうが良いです。このためのコマンドも用意してあります。

教師局面の生成

評価関数の学習で用いる教師局面の生成するコマンドの使い方を解説します。

⚠ このコマンドは、やねうら王 LEARN版のみでしか使えません。

gensfen [depth 探索深さ] [loop 生成する棋譜の数] [output_file_name ファイル名] [eval_limit 評価値]  : 学習用の自己対局棋譜の生成
    例) gensfen depth 6  (残りは省略可)
        eval_limitは、評価値の絶対値がこの値を上回った時点でその対局を終了するという値。

    その他に指定できるオプション

    write_minply N :
        初期局面周辺は、類似局面ばかりなので、初期局面から数えてN手未満の局面は教師局面として書き出さない。
        デフォルトでは16。
        初期局面を書き出すなら、Nに1を指定する。
    write_maxply N :
        書き出す局面の初期局面からの手数の最大。この手数を超えると引き分け扱いとする。
        デフォルトでは400。

    random_move_minply,random_move_maxplyとrandom_move_countオプション
        教師局面の生成時にランダムムーブを行なう最小手数と最大手数と1局でランダムムーブを行なう回数
        デフォルトではrandom_move_minply = 16 , random_move_maxply = 32 , random_move_count = 5。
        // 16手目から24手目までに5回のランダムムーブを行なうという意味
        gensfen random_move_maxply 16 random_move_maxply 32 random_move_count 5 ...
        みたいに指定する。

        特殊な指定として、
        random_move_minplyに-1を指定すると、
        定跡を抜けるところまで定跡に従って指して、そのあと定跡局面を抜けた直後に
        random_move_count回のランダムムーブを行なうという挙動になる。

    random_move_like_apery N : ランダムムーブのときに玉を移動させる指し手の確率を上げる。
        例えば、N = 3を指定すれば1/3の確率で玉を移動させる。
            (そしてこのとき、玉を移動させたあとは1/2の確率で相手番もランダムムーブが入る。)
            玉を移動させないときは普通に合法手から1手選択。(玉を移動させる指し手も含まれる)
        このオプションに0を指定すると、この機能は無効化される。

    random_multi_pv N : ランダムムーブの代わりにMultiPV Nでrandom_move_count手指すオプション。
        ConsiderBookMoveCount = trueと組み合わせると実現確率の高い局面からスタートできるかも…。
        0を指定するとこの機能は無効。
    random_multi_pv_diff m : random_multipvでmulti pvで指し手を採択するときに、
        1位の指し手の評価値との評価値の差がmに収まる範囲の指し手しか採択しない。
        デフォルトでは32000。(範囲の限度なし)
    random_multi_pv_depth : random_multipvするときの探索深さ。指定しない場合、gensfenで指定したdepth。

    use_eval_hash b : 同じ局面に遭遇したときのために評価値を保存しておく機能。
        これをオンにすると、hash衝突したときに間違った局面の評価値を使ってしまうため、
        オフにすることを推奨。ただし、eval_limitを32000などのように大きくとる場合、
        間違った評価値でもいずれは新しい局面で上書きされるため、影響は軽微であるからオンのほうが良いかも。
        (オンにしないと局面の生成が2割ぐらい遅くなりかねないので)
        オンにするにはuse_eval_hash 1のようにbのところに1を指定する。オフにするには0を指定する。

    save_every m : ファイルの分割保存オプション。
        教師局面をmだけ書き出すごとにファイルに保存する。
        AWSのspot instanceのterminate対策。
        mは1万の倍数を指定する。端数は無視される。

    random_file_name b : 生成されるファイル名をランダム化するオプション
        random_file_name 1と指定すると有効。
        random_file_name 0と指定すると無効。デフォルト、無効。
        このオプションが有効だとoutput_file_nameで指定したファイル名にランダムな数字を結合する。
        例) output_sfen_2549869
        さらにsave_everyオプションと組み合わせると
        例) output_sfen_2549869 , output_sfen_2549869_1 , output_sfen_2549869_2 , ..
        のように連番で保存されていく。
        ※ AWSで複数インスタンスを立ち上げるときに、startupのスクリプトでgensfenコマンドを叩きたいときに
        それぞれのインスタンスで出力ファイル名が違っていて欲しいため。

教師局面から評価関数の学習

⚠ このコマンドは、やねうら王 LEARN版のみでしか使えません。

learn [教師棋譜ファイル名1] [教師棋譜ファイル名2] …   : 生成した棋譜から評価関数パラメーターの学習をさせる。

    教師棋譜ファイル名はいくらでも書ける。
    gensfenコマンドで生成したファイルを指定する。
    このファイルを指定しない場合は、以下のtargetdirオプションで教師棋譜が入ったフォルダを指定する必要がある。
    
    batオプション
        learn bat 200 [ファイル名1][ファイル名2]..のように mini batchのサイズを設定できる。
        200だと200万局面ごとに評価関数パラメーターの更新が行われる。
    basedirオプション
        learn basedir c:/kif [ファイル名1][ファイル名2]..のように指定すると c:/kif/ファイル名1 c:/kif/ファイル名2 のように
        書いたのと同じ効果がある。
    targetdirオプション
        learn targetdir c:/kif
        とするとc:/kifフォルダ内にあるファイルを根こそぎ学習対象とする。
    loopオプション
        learn loop 3 [ファイル名1][ファイル名2]..のように指定すると、3回ループする。
        (手抜き実装のため大きな数字を指定すると、ファイル名の文字列バッファをたくさん消費するので1000ぐらいまでの指定でお願いします)
    batchsizeオプション
        minibatchのサイズを指定できる。デフォルトは100万局面。
    eval_limitオプション
        教師局面の深い探索での評価値の絶対値が、この値を超えているならその局面を読み捨てる。
        指定しないときは32000が指定されているものとする。
    save_only_onceオプション
        評価関数を保存するときに都度フォルダを掘らないようにするフラグ。
        デフォルトではオフ。
    no_shuffle
        読み込み時に先読みでのシャッフルを行わない。
        これを指定しないときは1000万局面ごとにシャッフルしながら読み込む。
        (デフォルトではオフ)
    lambda elmo(WCSC27)式を内分形式にしたときのlambda。
        elmo(WCSC27)と同じにするには0.33を指定すれば良い。
        参考)
            grad = (1 - lambda) * (eval_winrate - t) + lambda * (eval_winrate - teacher_winrate);
    lambda2 , lambda_limit
        深い探索の評価値の絶対値がlambda_limit以上のときは、lambdaではなくlambda2のほうを適用する。
        デフォルトではlambda_limit = 32000なのでlambda2が適用されることはない。

    freeze_kk  bool : 
    freeze_kkp bool : 
    freeze_kpp bool :

        KK,KKP,KPPのうち、KK/KKP/KPPを学習させないオプション。trueにするとその特徴因子は学習しない。
        オンにするにはfreeze_kpp 1のように1を指定する。オフにするには0を指定する。

        また、KKPP_KPPTのようなKKPPを持つ評価関数の場合、freeze_kkppというオプションが使える。
        同様に、KPPP_KPPTのようなKPPPを持つ評価関数の場合、freeze_kpppというオプションが使える。

    eta 学習率
        AdaGradの学習率を設定する。30.0が標準的な学習率。
        これを上げるとパラメーターの更新のときの一回の変化量が大きくなる。
        (大きければ良いというわけでもない)
        etaの代わりにeta1と指定しても良い。
        また0を指定するとデフォルト値(30.0)になる。

        etaを連続的に変化させるには、
            eta1 0.01 eta2 500 eta1_epoch 100 eta3 30 eta2_epoch 500
        のように指定する。

        この場合、etaは0.01から始まり、epoch 100までに徐々に増加し、epoch 100で500になる。
        そのあと、徐々に減り、epoch 500で30になる。そこ以降は30のまま。
        eta1_epoch , eta2_epochを指定しなければこのような機能はオフになる。
        たとえばeta2_epochを指定しない場合、eta3は無視される。


    保存するフォルダは"EvalSaveDir"で指定したフォルダ。
    デフォルトでは"evalsave"。このフォルダは事前に用意されているものとする。
    このフォルダ配下にフォルダを"0/","1/",…のように自動的に掘り、そこに評価関数ファイルを保存する。
    save_only_onceが指定されているときは、"0/","1/"のようなフォルダは掘らない。

教師局面のシャッフル

教師局面をシャッフル(順番をランダムに)しないと、データが偏っている可能性があるので、そのためのコマンドです。

対局が偏るというのは、例えば並列自己対局をして、それを同時に書き出しているので、ファイルの最初のほうに出力されるのは、序盤の局面ばかりになっている可能性があります。このような状態ですと学習に悪い影響があるので、シャッフルする必要があります。

⚠ このコマンドは、やねうら王 LEARN版のみでしか使えません。

learn shuffle basedir BASE_DIR targetdir TARGET_DIR output_file_name OUTPUT_FILE_NAME [教師棋譜ファイル名1] [教師棋譜ファイル名2] ...

    basedir BASE_DIR と targetdir TARGET_DIR と output_file_name OUTPUT_FILE_NAME とは省略できる。
    教師棋譜ファイル名も省略できる。教師棋譜ファイルはgensfenコマンドで生成したものとする。

    shuffleしないときのコマンド同様、教師棋譜ファイルを指定しないときは、targetdirで教師局面ファイルが
    入ったフォルダを指定してやる必要がある。

    targetdirを省略してファイル名をそのあとに並べることも出来る。
    tmp/
    というフォルダに一時ファイルが書き出され、最終的に
    OUTPUT_FILE_NAME
    というファイルが書き出される。
    output_file_name OUTPUT_FILE_NAMEを省略時には
        shuffled_sfen.bin
    というファイル名でカレントフォルダに書き出される。

    buffer_size BUFFER_SIZE
        シャッフルするときにテンポラリファイルはbuffer_size局面ずつtmp/フォルダにいったん書き出す。
        例えば、buffer_size = 20000000 (20M)ならば 20M*40bytes = 800MBのバッファが必要。
        メモリが少ないPCでは、ここを減らすと良いと思う。
        ただし、あまりファイル数が増えるとOSの制限などから同時にopen出来なくなる。
        Windowsだと1プロセス512という制約があったはずなので、ここでopen出来るのが500として、
        現在の設定で500ファイル×20M = 10G = 100億局面が限度。

learn shufflem basedir BASE_DIR targetdir TARGET_DIR output_file_name OUTPUT_FILE_NAME [教師棋譜ファイル名1] [教師棋譜ファイル名2] ...
    メモリに丸読みしてシャッフルして指定ファイル名で書き出す。
    (メモリが教師局面の2倍ぐらい必要)
    その他はlearn shuffleコマンドと同様。

learn shuffleq basedir BASE_DIR targetdir TARGET_DIR output_file_name OUTPUT_FILE_NAME [教師棋譜ファイル名1] [教師棋譜ファイル名2] ...
    それぞれの教師局面はファイル単位ではshuffleされていると仮定して、1passでシャッフルする。高速。
    その他はlearn shuffleと同様。

    複数台のPCで教師局面を生成するときに、各PCは生成直後に"learn shufflem"しているとして、
    それらのファイルをホスト側で"learn shuffleq"してから学習に使うというような使い方を想定している。

ゼロクリアされた評価関数パラメーターから学習を開始する方法

SkipLoadingEvalオプションは、評価関数ファイルがなくともエラーにならないようにするためにおまじないです。

これをtrueにしたあとisreadyを呼び出すと、ゼロ初期化された評価関数パラメーターになります。

EvalDir xyz              // 存在しないフォルダを評価関数の読み込みフォルダに指定する
SkipLoadingEval true     // こうしておけば評価関数ファイルの読み込みに失敗してもエラーにならない
isready                  // このタイミングで評価関数が読み込まれるが存在しないフォルダから読み込むのでゼロクリアされた評価関数を読み込んだことになる。

あとは普通にlearnコマンドを使うだけです。

ゼロクリアされた評価関数ファイルの作り方

色々作り方はあると思いますが、やねうら王のLEARN版を使えば、以下の手順で作れます。

EvalDir xyz              // 存在しないフォルダを評価関数の読み込みフォルダに指定する
SkipLoadingEval true     // こうしておけば評価関数ファイルの読み込みに失敗してもエラーにならない
isready                  // このタイミングで評価関数が読み込まれるが存在しないフォルダから読み込むのでゼロクリアされた評価関数を読み込んだことになる。
EvalSaveDir eval_zero    // 保存フォルダ名を"eval_zero"に設定(何でも良い)
test evalsave            // メモリ上の評価関数を保存するコマンド

これでeval_zeroフォルダにゼロクリアされた評価関数ファイルが保存されます。

教師局面の変換

教師局面の変換について。

⚠ このコマンドは、やねうら王 LEARN版のみでしか使えません。

簡単な説明) 「バイナリ形式」とは、 通常の教師局面形式。
    「テキスト形式」とは、テキスト(sfenと何か)で書かれた教師局面形式。
    詳しい形式については、learn.cppのconvert_plain()を見ればわかる。

learn convert_bin output_file_name [出力ファイル名] [入力ファイル名1] [入力ファイル名2]
    入力ファイル名1,2,…で指定されたテキスト形式の教師局面を読み込み、出力ファイル名のファイルに
    バイナリ形式で出力する。

learn convert_plain output_file_name [出力ファイル名] [入力ファイル名1] [入力ファイル名2]
    入力ファイル名1,2,…で指定されたバイナリ形式の教師局面を読み込み、出力ファイル名のファイルに
    テキスト形式で出力する。