NNUE評価関数の学習方法について

やねうら王でNNUE評価関数の学習をする方法について解説記事がなかったのでざっとまとめておきます。

教師局面の生成

gensfenコマンドを使います。KPPT型のときと同じなので割愛。

学習用の実行ファイルのビルド(MSYS2)

OpenBlasという行列演算などが速くなるライブラリを有効にしてビルドします。(OpenBlasが有効でないと学習に倍以上時間がかかります。)

MSYS2上でビルドするとき、pacmanでOpenBlasをインストールします。(32bit版のときは、OpenBlasを用いないので以下の操作は不要)

64bit版
$ pacman -S mingw-w64-x86_64-clang mingw-w64-x86_64-toolchain mingw-w64-x86_64-openblas

あとはMakefileを使って、そのままビルドできるかと思います。

$ mingw32-make clean YANEURAOU_EDITION=YANEURAOU_2018_TNK_ENGINE
$ mingw32-make -j8 evallearn COMPILER=g++ YANEURAOU_EDITION=YANEURAOU_2018_TNK_ENGINE

学習用の実行ファイルのビルド(Visual Studio)

Visual Studio上でビルドする場合、USE_BLASを定義してやります。これはプロジェクトの設定のほうでやってもいいですし、extra/config.hに

#define USE_BLAS

などと追加しても良いです。次に、”libopenblas.dll.a”というファイルをlibとして追加して、実行ファイルの配置されるフォルダにlibopenblas.dll , libgcc_s_seh-1.dll , libgfortran-3.dll , libquadmath-0.dll を配置します。

このへんの手順の解説は以下の記事に譲ります。

[VC++] OpenBLASを使ってみた : https://qiita.com/t–k/items/69c43a667a1283578012

libgcc_s_seh-1.dll , libgfortran-3.dll , libquadmath-0.dllは、MSYS2のなかにあるようですが、私はOpenBlasのサイトからダウンロードしてきて配置しました。

※ https://sourceforge.net/projects/openblas/files/v0.2.12/mingw64_dll.zip/download

学習時オプション


を参考に。

KPPT型との違い
・eta 1.0 ぐらいにすべき(KPPTのときのように32とかにすると発散する)
・mirror_percentage 50 : これを指定しておくとミラーの次元下げをするのか学習効率が少しよくなる
・batchsize 1000000 : これで最初のうちは問題なさげ。これを変更してもあまり強さは変わらないっぽい
・lambda 0.5 : lambdaの最適値はよくわかっていない 0.5とか1.0とかで正常に学習できることは確認済み。
・nn_batch_size 1000 : とりあえずデフォルトのまま
・eval_limit 32000 : これの最適値もよくわかっていない
・validation_set_file_name (検証データファイルパス) : 学習のときのlossの計算をするために検証用のデータセットは別のものにしたほうが良いということで別の教師ファイルを指定できるようになっている(指定しなくとも学習自体はできる)
・newbob_decay 0.5 : これを指定すると学習のスケジューラーの挙動が変わる。eval_save_interval局面学習させるごとに前回のロスの値と比較して、ロスが下がっていない場合は、一旦前回の結果にロールバックし、内部的なetaの値をnewbob_decay倍したうえで学習を続行する。

あと、SkipLoadingEvalは、初回はtrueにしておかないと評価関数を読み込もうとして失敗するような。2回目以降はEvalDirオプションで評価関数の配置しているフォルダを指定すると良い。

学習コマンドの例)

$ YaneuraOu2018NNUE_LEARN.exe , evaldir eval\zero , evalsavedir yanehome\eval\learn_777 , threads 80 , hash 16 , evalshare false , skiploadingeval true , learn newbob_decay 0.5 mirror_percentage 50 nn_batch_size 1000 loop 1 basedir yanehome batchsize 1000000 eta 1 lambda 0.5 eval_limit 32000 save_only_once no_shuffle targetdir learn_sfen\sfen2018D10 , quit

学習時間・学習効率

40コアのPCで教師局面1億局面につき1時間程度。KPPT型の時の数倍ぐらいかかるようです。

以前公開していた月刊教師局面(depth 8で生成)、2億局面を用いて、ゼロから上の設定で学習させた場合、elmo(WCSC27)よりR200程度弱いものができました。

その他

NNUEの学習に関して、何か質問があればコメント欄にどうぞ。

ちなみに、NNUEは駒割(駒の価値)も全くのゼロから学習しているので、ゼロから棋譜を生成してそこから学習を繰り返すような場合、KPPT型に比べて時間がかかるかも…。

 

NNUE評価関数の学習方法について” への47件のコメント

  1. validation_set_fileとnewbob_decayについては使い方が非常に難しいですね。
    etaの値次第でeval_save_intervalの時に毎回rejectedされて全然学習が進まない事がよくあります。
    newbob_num_trialsがデフォルトでは2なので、2回rejectedされると次で学習が強制終了してしまうので、多めの数字にする必要があります。
    newbob_decayを1.0にしつつ、eta可変絞りを上手く設定してやった方が良いかもしれません。
    その場合はlogの中のlossを見比べて良かった物を選び出して採用する必要はありますね。

        • ほほー!これは実装が簡単でそこそこ期待できそうな手法ですね!
          (lossが下がることが確認できる “1 step” が小さくて済む場合ならば。NNUEでこの条件を満たすかは…わかりません。まあ、EvalSaveIntervalを1000万ぐらいに設定して、newbob_decay 0.5とかにしておけば、こまめにセーブして、そのときにloss下がってなからったらetaを1/2にしていくので、これくらいの挙動でもいいような気はしますけども。)

  2. これってShivorayのコードを弄ってできちゃったりします?その場合どこをどう弄ればいいんですかね

    • Shivorayで出来ないですし、やねうら王にはそのようなコマンドも用意してないです。ニューラルネットは単純には合成できない(合成しても意味がない)ので。
      ニューラルネットの研究を専門にしている人なら何らかアクロバティックな技で合成できるのかな?程度の意味です。

  3. すみません。やねうら王で教師局面を作っていたのですが、まったく進まなくなってしまいました。どうすれば良いでしょうか?
    YaneuraOu2018NNUE_learn_sse42.exe threads 4 , hash 4000 , bookmoves 32 , bookfile no_book , evaldir eval , gensfen depth 8 loop 1000000000 random_move_count 0 write_minply 1 write_maxply 160 eval_limit 3000 output_file_name generated_sfens.bin , quit

    • hashが小さすぎ&開始局面が1手目なので、初期局面に対応する置換表エントリーに詰みのスコアの局面が偶然書かれていて(hash衝突)、それで詰みのスコアなので即座に詰みのスコアが返ってくるのですが、eval_limit 3000になっているため、その情報はスキップされて…ということなのではないでしょうか。(´ω`) 以前は置換表、スレッドごとにわけてたのですが、これやると置換表効率落ちるので、それをやめた影響ですね。

      1秒間、教師情報の生成がなければ、TT.clear()を呼び出すなどすれば回避できます。あるいはply==1でabs(value)>=3000 みたいな値が返ってきたらTT.clear()を呼び出すだとか。

      まあ、しかし定跡なしで教師生成するのはお勧めしません…。

  4. やねうら王のhash 〇〇〇〇の設定についてですが、これを今余っているメモリをすべて使うような時はどのようにすればよいのでしょうか?hash 99999とかに設定すれば良いのでしょうか?

    • その機能はついてないです。
      (2エンジンでの対局ができなくなる、使っているうちに物理メモリが少し足りなくなってえらいことになる等が懸念されるため)

  5. ある程度学習された野良のNNUE評価関数に少数精鋭の局面食べさせようと思うのですが、その影響力を強くするには、学習時にどの値をどのように変えるべきですか?

    • Bonanzaの学習のように教師の指し手の評価値が、その局面の他の指し手の評価値より上回るように調整すれば良いような?Qhapaqさんが学習部にそういう改造されてたはず…。

      • いけました。返信ありがとうございます。
        後、gensfenコマンドで教師局面を生成する際に、教師局面を(save_every Nで保存されたもの)、指定したフォルダの中に保存したいのですが、どうすればよいでしょうか?

        • 後、手始めに、depth6の教師局面1500万程を一度食べさせてみたところ、評価値が、
          1,-1,13,-13しか出なくなったのですが、これは、どうしてでしょうか?

          • 最初はetaが30になっていて、評価値が永遠に±2945のどちらかをさしていたので、etaを1.0にしてもう一度ゼロからしてみたのですが、結果は先ほどの通りです・・・。
            etaが問題ではなさそうです・・。コマンドは以下の通りです。
            learn [教師棋譜ファイル名] bat 10 lambda 0.5 newbob_decay 0.5 eta 1.0

  6. なるほど・・・(;。□。;)
    了解です!確かにeta 1.0は大きすぎですね・・・・・。ありがとうございますドモ

  7. 評価関数をゼロから学習するときの、教師局面はすべてのパラメーターがゼロなので、
    depth1でも問題ないような気がするのですがどうでしょうか?

    • 最初はdepth低めで問題ないですけど、depth 1でいいかは、depth 1でやったことがないのでわかりません><
      5年ぐらい前はdepth 3ぐらいからスタートしてましたです..。

      • そうですか、ありがとうございます。
        因みに、リゼロ評価関数を作る時、定跡はどうしましたか?

          • ゼロから学習させる場合は、そうですね。
            SkipLoadingEval true
            とやると、ゼロクリアされた評価関数になるので、実際には評価関数ファイルは用いてませんけども。

          • ありがとうございます(^ω^)
            とても参考になりました!

  8. INFO: largest min activation = 0, smallest max activation = 0
    INFO: largest min activation = 0, smallest max activation = 0
    INFO: largest min activation = 0, smallest max activation = 0
    ↑永遠に此れが続いているのですが、此れは何ですか?
    後、
    learn Teacher.bin Teacher_1.bin bat 10 lambda 1.0 mirror_percentage 50 newbob_decay 0.5 eta 1.0 eval_save_interval 100000
    でしてみると、200万局面程で
    test_cross_entropyが全く減らなくなります。
    どうしてでしょうか?(それとも200万局面程度であーだこーだ言うのが短気なのでしょうか?)

    • すみません、bat 10 の所を
      batchsize 100000 nn_batch_size 1000 に、
      eta 1 の所ををeta 0.1に変えて読んで下さい。
      間違ったものをコピペしてました….

    • 教師がおかしいのでは?ゼロからの学習ですかね?であれば、最初は対局シミュレーションの勝敗に頼るしかないので、lambdaに0を指定する必要があるような…。(elmo式についての記事を参考にしてください)

      • 返信ありがとうございます。
        教師局面の生成は、NNUEでしてみると、何分待っても始まらなかったので、
        KPPTでしました。定跡は使ってません。
        コマンドは
        SkipLoadingEval true
        gensfen depth 3 loop 100000000 output_file_name Teacher_D3 eval_limit 3000 write_minply 1 random_move_minply 1 random_move_count 5 save_every 5000000
        こんな感じです。(Teacher_D3 は教師ファイル名)何処かおかしい所が見られますか?

        lambda 0でもう一度やってみます。

        • lambda 0 でも500万局面で
          loss: 0.69206 >= best (0.691917), rejectedとなりました・・・・。
          やね師匠、「これならまともな物が出来るだろう!」という様なサンプルのコマンドを頂けませんでしょうか?(出来れば一番最初の学習時のものと、2回目以降のものを・・・)

          • 何度も返信ありがとうございます。(๑´ڡ`๑)
            NNUEの育成には根気が必要なのですね(*>ш<*)

    • まあ…、そこまで無理にlossが下がるまで、現状のetaで頑張らずとも、数回やってlossが下がらないならetaを1/2ずつしてくぐらいでいいと私は思いますけども..

QWest にコメントする コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です