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評価関数の学習方法について” への62件のコメント

  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ずつしてくぐらいでいいと私は思いますけども..

  9. SkipLoadingEval trueで作成して教師局面3億をSkipLoadingEval trueで一周学習した評価関数にもう一周同じ教師局面3億を使って学習させれば、loop 2と同等の効果が得られますか?
    又、2回目もlambda 0としなければなりませんか?

    • あと一つ、学習の途中でlearn.exe消してしまったのですが、そこから再開する方法はありますでしょうか

    • 学習コマンドのloopは単に教師データを繰り返し与える回数だった気がします。なので1つ目の質問はYesです。2つ目の質問はいまひとつ意味がわかりませんが、初回がlambda 0を指定しているなら、2回目もlambda 0を指定しないとloop 2と同等ではないです。

      • 即ち、学習の最中に、右上にあるバッテンマークを誤ってクリックしてしまい、今までしていた分が水泡に帰したのです。もう一度最初からするのは億劫なので、バッテンマークを押す時に学習されていた所から再開する方法はあるのか?という意味でございまする。

  10. ①学習の際、何度か同じ学習をし、一番ロスが下がた
     ものを採用するのと、ひたすら、
     教師生成→学習→教師生成→学習…を繰り返すのと、
     どちらのほうが効率がよいのでしょうか?
    ②newbob_decayの試行回数を指定するにはどうすば
     良いですか?

    • > ①学習の際、何度か同じ学習をし

      同じ教師をloopで複数回学習させるかという意味でしたら、まあ、教師局面が少ないならやったほうがいいと思いますけど、あまり回し続けても過学習しますし、ほどほどに…。

      > ②newbob_decayの試行回数

      newbob_num_trialsでできたような?

  11. 例えば、嬉野流評価巻子を作ろうと、嬉野流の定跡(先手後手両方)を入れた状態で生成した教師で学習を進めると、
    ソフトが嬉野流側ではなく対嬉野流側の駒の位置関係のほうが良いと捉えてただ嬉野流をボコす評価関数が出来上がると思うのですが、どうすればソフト的にマイナーな戦法(振り飛車等)を上手く学習させることができるのでしょうか?(一般人に出来る方法で)

    • 嬉野流側が負けた棋譜を間引く(減らす)といいような?たややんさんがなんかそんな手法で振り飛車評価関数を作成されてますよね。
      教師局面の生成のコードのなかで、終局後にその1局分を書き出している箇所で、以下のようにやるなど..
      if (嬉野流側が負け && prng.rand(100) < 20) continue; // 嬉野流側が負けなら20%の確率で書き出さない

      • とても我が儘な話ですが、私の環境だとコードをいじれてもビルド出来ないので、
        それを、何らかの形で、一般に公開している
        やねうら王に標準搭載して頂くという事は可能でしょうか?

        • その機能、検証が大変そうで、私はあまり興味ないのでその検証までやりたくない感じです..すみません。ビルドに関してはAWSでVisual StudioつきのAMI借りれば速攻でビルドできるので、まあ、1時間かかってもスポットインスタンスの小さいマシンなら30円にもならないかと…。

やねうらお にコメントする コメントをキャンセル

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