機械学習周りのプログラミング中心。 イベント情報
ポケモンバトルAI本電子書籍通販中

汎用行動選択モデルの3vs3対応 part08 学習率の調整【PokéAI】

強化学習アルゴリズムが正しくてもハイパーパラメータ設定により性能が大幅に変わってきます。1vs1バトル環境において、optunaによる調整を行ったところ学習率が最も大きな要素であることがわかりました。 しかしこのパラメータのまま3vs3バトル環境へ適用すると学習が不安定となったため、学習率を下げていました。3vs3に最適な学習率を調べました。最適な学習率はモデルのレイヤー数などに大きく左右されるため、具体的な数字に一般性はありません。

実験方法

異なる学習率で10,000バトルおよび100,000バトル強化学習させ、そのエージェント同士をレーティングバトルさせて平均レートを測定しました。学習・評価用パーティはランダムに生成した1000パーティです。

その他の学習パラメータ

trainer:
  dqn_params:
    epsilon: 0.3
    epsilon_decay: 2.0e-06
    epsilon_min: 0.01
    gamma: 0.95
    lr: 1.0e-04
  feature_params:
    party_size: 3
  model_params:
    bn: false
    n_channels: 64
    n_layers: 3
surrogate_reward:
  hp_ratio: 0.25
  alive_ratio: 0.25
match_config:
  random_std: 100.0

結果

10,000バトル時点での結果です。

学習率 平均レート
3e-6 1479
1e-5 1512
3e-5 1512
1e-4 1516
3e-4 1482

3e-6とは、 3 \times 10^{-6}のことです。念のため。

100,000バトル時点での結果です。

学習率 平均レート
3e-6 1515
1e-5 1514
3e-5 1503
1e-4 1481
3e-4 1487

10,000バトル時点では、1e-4~1e-5が良い領域で、小さくても大きくても強さが低下します。100,000バトルでは最良の学習率が3e-6でしたが、1e-5とはわずかな差でした。 結論としては、今回の実験設定では1e-5程度を設定するのが安定しそうです。しいて言えば、学習の最初のほうは学習率高めで、徐々に下げていくのが望ましいと考えられます。教師あり学習では徐々に学習率を下げるというテクニックは当たり前に行われています。学習率を下げるタイミングとして、学習を進めても正解率が変化しなくなったときという目印が使えます。しかし強化学習ではこのような使いやすい指標がないので、応用は比較的難しいといえます。

次回は3vs3環境でのQ関数を用いたパーティ生成について解説する予定です。実験自体は1か月前に終わっているのですが、執筆時間が取れず溜まってしまっています。

汎用行動選択モデルの3vs3対応 part07 強化学習中の対戦相手【PokéAI】

今回も強化学習の改善を目指します。ポケモンバトルの強化学習の特徴的な要素として、バトル開始時にエージェントに操作すべきパーティが割り当てられるという点があります。バトルごとに異なるパーティが割り当てられ、相手のパーティとの関係性により有利不利がある程度決まっています。つまり、パーティの組み合わせによって、いくら最善の行動を選択したとしても勝てない相手と当たったり、また戦力差が大きすぎて適当に行動していても勝ってしまったりする場合が考えられます。強化学習では適切な行動を選択した場合に高い報酬が得られ、そうでない場合に低い報酬が得られるという枠組みによってエージェントがより適切な行動を選択できるように学習していきます。そのため、どんな行動を選んでも結果が変わらない、また相手にかかわらず同じ行動を選び続けても結果が変わらないという状況は強化学習に悪影響を及ぼすと考えられます。事前に結果を述べると、今回の提案手法はあまりうまくいきませんでした。

現在の学習システムでは、学習対象となる1000パーティから毎回ランダムに2パーティを選択し、エージェントに操作させて対戦させます。パーティ選択の結果、次のような組み合わせになる場合もあり得ます。

パーティ1

ラプラス,55,,すてみタックル,れいとうビーム,なみのり,ずつき
エレブー,50,,かみなりパンチ,はかいこうせん,れいとうパンチ,かみなり
キングドラ,50,,どくどく,すてみタックル,なみのり,とっしん

パーティ2

バタフリー,55,,かげぶんしん,どくのこな,はかいこうせん,ギガドレイン
ギャラドス,50,,すなあらし,ロケットずつき,かげぶんしん,ふぶき
アリアドス,50,,ギガドレイン,ナイトヘッド,サイケこうせん,サイコキネシス

このような組み合わせだと、ポケモン自体の強さや技構成に差がありすぎて、パーティ1はれいとうビームを連打するだけで勝ち、パーティ2は何をしても負けという状況になってしまいます。より強化学習の効果を高めるためには、強さが均衡しているパーティ同士を対戦させ、行動によって勝敗に影響が生じるべきであると考えられます。 このアイデアを実現するため、学習中の勝敗に基づきパーティのレートを計算し、そのレートが近いもの同士を対戦させる手法を提案します。より具体的には、次のようなアルゴリズムになります。

  1. 全パーティにレート1500を割り当てる。
  2. 各パーティのレート+乱数(正規分布(平均0, 標準偏差200))をソートし、隣接するパーティ同士を1回ずつ対戦させる。
  3. 対戦結果に応じ、各パーティのレートを変動させ、2.に戻る。勝ったパーティのレートが上昇、負けたパーティのレートが下降。

なお、強さは同程度だがタイプ相性上一方的な展開になるような組み合わせについては回避できません。また、学習中はエージェントの行動にランダム探索が入っているため、緻密な行動が必要となるパーティのレートが低く見積もられることに注意が必要です。

学習中にパーティに割り当てられたレートの例(最大最小5パーティずつ)を表示します。レートの数値の下にパーティ構成が書かれます。

1976.1585539549626
スイクン,55,,バブルこうせん,どろかけ,おんがえし,たきのぼり
ライコウ,50,,いわくだき,10まんボルト,どろかけ,スピードスター
ブースター,50,,すてみタックル,どくどく,のしかかり,でんじほう
1907.6473566568743
フリーザー,50,,おんがえし,すてみタックル,れいとうビーム,かげぶんしん
レアコイル,50,,どくどく,スピードスター,でんじほう,かみなり
サンダース,55,,かげぶんしん,ずつき,どろかけ,かみなり
1899.8400806585537
カビゴン,55,,のしかかり,じしん,どろかけ,いわくだき
ギャラドス,50,,れいとうビーム,バブルこうせん,ふぶき,なみのり
ファイヤー,50,,すてみタックル,どろかけ,はがねのつばさ,ゴッドバード
1889.6782005805987
サンダース,55,,10まんボルト,ロケットずつき,のしかかり,おんがえし
オドシシ,50,,サイコキネシス,ずつき,スピードスター,どろかけ
プテラ,50,,どくどく,じしん,そらをとぶ,げんしのちから
1881.7262223082878
ラプラス,55,,すてみタックル,れいとうビーム,なみのり,ずつき
エレブー,50,,かみなりパンチ,はかいこうせん,れいとうパンチ,かみなり
キングドラ,50,,どくどく,すてみタックル,なみのり,とっしん
941.2403493021229
バタフリー,55,,かげぶんしん,どくのこな,はかいこうせん,ギガドレイン
ギャラドス,50,,すなあらし,ロケットずつき,かげぶんしん,ふぶき
アリアドス,50,,ギガドレイン,ナイトヘッド,サイケこうせん,サイコキネシス
1037.789914338687
ウソッキー,50,,かみなりパンチ,ほのおのパンチ,かげぶんしん,ばくれつパンチ
ハピナス,55,,どくどく,ソーラービーム,すなあらし,バブルこうせん
ダグトリオ,50,,げんしのちから,どくどく,いわくだき,どろかけ
1074.775682922385
ヨルノズク,50,,はかいこうせん,スピードスター,どろかけ,つばさでうつ
カモネギ,55,,ロケットずつき,スピードスター,かげぶんしん,どくどく
フシギバナ,50,,すてみタックル,かげぶんしん,ずつき,ロケットずつき
1074.9070024754321
パラセクト,55,,どくどく,どくのこな,ロケットずつき,とっしん
キレイハナ,50,,どくのこな,はかいこうせん,どくどく,ソーラービーム
エレブー,50,,はかいこうせん,おんがえし,のしかかり,サイコキネシス
1082.91523438976
フシギバナ,50,,かげぶんしん,どろかけ,いあいぎり,とっしん
ヨルノズク,55,,はがねのつばさ,スピードスター,どくどく,かげぶんしん
ラッタ,50,,かみなり,ふぶき,すてみタックル,いわくだき

定性的に見て、妥当な序列になっているように見えます。

提案手法で学習したモデル(id: 5ab)を従来手法(id: 78e)とレーティングバトルで比較しました。学習に用いたパーティ群と同じパーティ群で対戦しています。

手法 平均レート
提案 1504
従来 1496

残念ながら、わずかな差しかありませんでした。後日別記事で書きますが、この手法で得られたモデルのQ値がパーティ生成に使いにくいというのもあり、しばらくはこの手法は使わないで行こうと思います。

汎用行動選択モデルの3vs3対応 part06 学習バトル数と強さ【PokéAI】

モデルの強化学習におけるバトル数は、1vs1の時のパラメータを引き継いで10万に設定していました。3vs3ではそもそもバトル1回あたりのターン数が違うこと、学習すべき行動がより複雑であることから、この値が適切なのかどうか検証しました。

バトル数を10万より長くするにあたり、エージェントがランダムに行動する確率 \epsilonの減衰後の下限 \epsilon_{min}を新たにパラメータとして加えました。ステップ数 stepに対するランダム行動率 \epsilon(step)は、減衰率 \epsilon_{decay}を用いて \epsilon(step) = \max((1 - \epsilon_{decay})^{step} \epsilon, \epsilon_{min})と定義します。今回、 \epsilon=0.3, \epsilon_{decay} = 2 \times 10^{-6}, \epsilon_{min} = 0.01に設定しました。この場合、およそ50万ステップで \epsilon(step)が下限になります。なおバトル1回あたりの1エージェントの行動回数は平均20回程度で、バトルに参加する2プレイヤー両方の行動を学習サンプルとして用いるので、40ステップ分になります。すなわち1.25万バトルで下限に達するということです。

10000バトルごとにモデルを保存するようにして、50万バトルまで学習を進めてみました。 モデルIDは78eで、学習率は従来通り1e-5です。 バトル数1万、3万、10万、30万、50万の時点のモデルをレーティングバトルで比較しました。ランダムは弱すぎて細かい差を測るのに邪魔になると考えて外しました。

学習バトル数 平均レート
10000 1449
30000 1496
100000 1510
300000 1528
500000 1517

結果として、1万から10万にかけては大きな改善が見られる一方、それ以上は伸びが弱く、30万から50万にかけてはむしろ弱くなっています。 実験時間としては、10万バトルで24時間程度かかります。むやみに伸ばすのはコストのわりにメリットが少ないようなので、10万バトルを今後も標準のパラメータとして使おうと思います。

汎用行動選択モデルの3vs3対応 part05 補助報酬の調整【PokéAI】

前回エージェントの強化学習に対して、バトル途中でのHPの増減などに応じた補助報酬を導入し、定量的には強さが向上することを確認しました。 今回は、補助報酬の大きさなどを調整してさらに強くできないか実験します。あらかじめ結果を述べると、前回のパラメータが最善でした。

まずは、 \lambda_H (HPに対する報酬の係数),  \lambda_A (瀕死に対する報酬の係数)を同じ値にする条件で、いくつかの値を試しました。

表に示す5通りの条件のモデルを学習(1つはランダム)、レーティングバトルさせ、平均レートを計算しました。

 \lambda_H, \lambda_A モデルID 平均レート
- ランダム 1306
0, 0 6ee 1533
0.125, 0.125 75f 1540
0.25, 0.25 fdf 1563
0.5, 0.5 29c 1559

前回のパラメータである、 \lambda_H, \lambda_A = 0.25, 0.25が最も強いという結果でした。 \lambda_H, \lambda_A = 0.5, 0.5とは僅差です。

次に、パラメータのバランスを変えた場合で比較しました。

 \lambda_H, \lambda_A モデルID 平均レート
- ランダム 1308
0.125, 0.125 75f 1538
0.25, 0.25 fdf 1566
0.5, 0 c69 1558
0, 0.5 1da 1527

この実験でも、 \lambda_H, \lambda_A = 0.25, 0.25が最も強いという結果でした。 \lambda_H, \lambda_A = 0.5, 0のほうが \lambda_H, \lambda_A = 0, 0.5より強いことも分かります。この理由として、HPを基準にするほうがより短い期間で報酬が得られるため学習しやすいという点が考えられます。

さらに、補助報酬のアルゴリズムを変更したものを2つ試しました。1つ目は、相手に関する値だけを計算に含めるものです。すなわち、 H_f(t)=0, A_f(t)=0とします。自分のポケモンのHPが減っているときに、倒されて負の報酬を受けるのを回避するために無駄に交代するという挙動を避ける目的です。

アルゴリズム モデルID 平均レート
- ランダム 1334
変更前 fdf 1588
相手状態のみの補助報酬 924 1578

変更しないのが良いことがわかりました。2つ目のアルゴリズムは、ゲーム終了時に今までの補助報酬を打ち消す補助報酬を与えるものです。すなわち、バトル終了時の報酬として、勝敗によるものに過去ターンの補助報酬の総和の符号を反転させたものを加算します。目的は、僅差で勝利した場合も圧勝した場合もバトル全体での合計の報酬を同じにすることにより、被害の大きさにかかわらず勝敗に注力させることです。

アルゴリズム モデルID 平均レート
- ランダム 1335
変更前 fdf 1584
補助報酬の打ち消し 412 1581

この手法は、結果にほとんど影響がないようでした。

補助報酬の調整を試みましたが、今回試した範囲ではオリジナルの手法より良い結果は得られませんでした。今後、他の側面から改善を試みます。

汎用行動選択モデルの3vs3対応 part04 補助報酬【PokéAI】

前回バトルログを可視化してわかったのは、学習したエージェントの行動でタイプ相性などがある程度考慮されているものの、まだまだ改善の余地が大きいということでした。 この記事から、強化学習手法の改善を試みていきます。

今回は、初代ルールの3vs3のときに提案した、補助報酬を与える手法を金銀ルールでも試してみます。

select766.hatenablog.com

考え方を再掲します。通常の強化学習では勝敗に対してのみ報酬が得られますが、3vs3では1vs1と比べて勝敗が決するまでのターン数(行動数)が多くため、各ターンの行動の良し悪しを判断しづらくなります。 より短い期間で行動を評価できるよう、相手にダメージを与えたり、相手を1体倒した時点で少量の報酬を与えることを考えます。

勝敗以外に強化学習アルゴリズムに与える報酬を補助報酬と呼ぶことにし、以下のように定式化します。

  • ターン tにおける状態を以下の記号であらわす。(自分のポケモンが倒れた場合にも行動選択が生じるので、厳密にはターンではなく t回目の行動)
  • ターン tにおける自分の有利さを P(t) = \lambda_H (H_f(t) - H_e(t)) + \lambda_A(A_f(t) - A_e(t))とする
    •  \lambda_H, \lambda_Aは正の定数(ハイパーパラメータ)
  • ターン tにおける行動に対する補助報酬を、 P(t+1) - P(t)とする

 H_f(t)はバトル開始時に1、自分が全滅すれば0になります。ほかの式も同様です。HPが1でも残っている状態と完全に倒してしまうのは状況に差があるため、HPとは別に瀕死でないポケモン数の指標を含めています。 P(t)は、自分が全滅に近ければ小さな値、相手が全滅に近ければ大きな値をとることになり、自分が有利な状態であるほど大きな値になるといえます。そして、ターン間の差をとることにより自分の有利が拡大すれば正の報酬、不利になれば負の報酬が与えられることになります。

この手法を実装し、実験しました。 \lambda_H=0.25, \lambda_A=0.25とし、他の学習条件は前回(id: 6ee)と同じです。

提案モデル(id: fdf)と前回のモデル(id: 6ee)、ランダムに行動するモデルの3つでレーティングバトルを行い、平均レートを比較しました。

モデル 平均レート
ランダム 1340
6ee 1567
fdf(提案) 1593

補助報酬を加えることにより、定量的に改善することがわかりました。ただバトル中の行動を観察すると、HPが減ったポケモンを控えのポケモンと交代する無駄な行動がみられました。自分のポケモンが倒されると負の報酬が発生するため、これを回避するため、勝敗全体で見れば不利な行動をとってしまう場合があるようです。短期的な報酬を与えることによる負の側面であるといえます。

次回は補助報酬のハイパーパラメータを調整してみます。

DNNの方策に従来型エンジンのbestmoveをブレンドする コードの動かし方【コンピュータ将棋】

今回の研究用に開発したコードの動かし方と、改良のアイデアを掲載します。私が所持していない、より強力なハードウェアで検証・強化したいという方がもしいらっしゃれば参考にしてください。

記事一覧

コード・環境構築

コード・バイナリ(Windows)はこちらです。python製のツールもあるため、バイナリだけでなくコードも必要になります。 Release DNNの方策に従来型エンジンのbestmoveをブレンドする実験コード · select766/DeepLearningShogi · GitHub

環境構築

実行方法

コマンドプロンプトを2つ立ち上げる。1つはelmoを評価関数として用いるためのサーバで、もう1つは自動対局用。サーバはTCP port8765で通信します。

elmoを評価関数として用いるためのサーバ

ソースコードのトップレベルのディレクトリで以下のコマンドを実行。

python -m searchblend.searchblend_pool path\to\YaneuraOu_NNUE_tournament.exe --options Threads:1,EvalHash:16,NodesLimit:1000 --pool 4

optionsはUSIエンジンにsetoptionで渡される設定です。NodesLimitは、実際にエンジンを動かしつつdlshogi側のnps低下が大きくないように設定する必要があります(PC性能により大きく変わると思います)。poolは立ち上げるエンジンのプロセス数で、CPUのコア数程度に設定するとよいと思われます。

自動対局

改造前後のdlshogiを1手1秒で対局させる場合。

python -m cshogi.cli path\to\blend\dlshogi_tensorrt.exe path\to\original\dlshogi_tensorrt.exe --byoyomi 1000 --options1 DNN_Batch_Size:16,Blend_Ratio_Policy:5,Blend_Ratio_Value:2 --options2 DNN_Batch_Size:16 --games 100 --opening path\to\records2016_10818.sfen
  • Blend_Ratio_Policyが方策関数にelmoのbestmoveを加える割合。0(elmoの出力を無視)~100の範囲。
  • Blend_Ratio_Valueが方策関数にelmoの評価値を加える割合。0(elmoの出力を無視)~100の範囲。

dlshogiから呼び出すelmoの評価関数としてKPPT,NNUEを比較する場合

サーバを2つ立ち上げる必要がある。--portによりポートを変更する設定を加える。エンジン側ではExternal_Eval_Portを設定。

python -m searchblend.searchblend_pool path\to\nnue\YaneuraOu_NNUE_tournament.exe --options Threads:1,EvalHash:16,NodesLimit:1000 --pool 4 --port 10000
python -m searchblend.searchblend_pool path\to\kppt\YaneuraOu_KPPT_tournament.exe --options Threads:1,EvalHash:16,NodesLimit:1000 --pool 4 --port 10001
python -m cshogi.cli path\to\dlshogi_tensorrt.exe path\to\dlshogi_tensorrt.exe --byoyomi 1000 --options1 DNN_Batch_Size:16,Blend_Ratio_Policy:5,External_Eval_Port:10001 --options2 DNN_Batch_Size:16,Blend_Ratio_Policy:5,External_Eval_Port:10000 --games 100 --opening path\to\records2016_10818.sfen

デフォルトではTCP通信はlocalhost内で行われるが、マシンを分けたいときのためにsearchblend_pool側に--hostオプション、dlshogi_tensorrt.ext側にExternal_Eval_Hostオプションあり。ソースコード参照。 AWSの強力なGPUインスタンスだと、CPU側がボトルネックになるという話も聞きます。レイテンシが低いネットワークでCPUのみの別インスタンスに処理を投げればこのコードのままでも使えるかもしれません。

改良アイデア

実装面での改良アイデアを載せておきます。

  • elmoのプロセスを1つにまとめ、置換表を共有する
    • 特にCPUコア数が多い場合、過去の探索結果を再利用してより良い指し手を見つけられる確率が上がると思われます。
  • elmoの探索ノード数の自動調整
    • 現在は1000ノード固定としていますが、CPUの負荷に応じて動的に変動させ、dlshogi側のnpsへの影響を調整することが考えられます。
    • ノード数を変えず、一部の局面をランダムに無視するというようなやり方もありえます。

DNNの方策に従来型エンジンのbestmoveをブレンドする 実装編 part03(終)【コンピュータ将棋】

前回、dlshogiの方策関数にelmoの読み筋をブレンドする実験の結果を示しました。dlshogi同士でこの改造の有無を比較すると改造したほうが強くなるのですが、対戦相手としてelmo単体(dlshogiから呼び出すのではなく、elmoを普通に対局エンジンとして使用する)と比較すると若干弱くなっているという結果でした。dlshogiからelmoを呼び出す場合も、elmo単体の場合もelmoの評価関数が全く同じものだったので、これを変えた場合の比較を行います。ただし、elmoですべてのCPUコアを使うとdlshogiよりかなり強いため戦力差を測りにくい状況となっていたため、スレッド数を下げて強さの均衡を図りました。

今回は、elmoの評価関数としてNNUE型(WCSC29版)とKPPT型(WCSC27版)の2つを用いることで、評価関数が完全一致することによる悪影響の可能性を解消することとしました。まずは、dlshogiと組ませる評価関数を変えた場合の結果を示します。前回提示した結果も含まれます。

elmo(xT,y)は、xスレッド、評価関数yの設定を示します。無改造dlshogiは、電竜戦バージョンではなく実験コードの分岐元となったcommit cc722f5を私の開発環境でビルドしたものです。DNN評価関数はGCT(電竜戦2020)です。dlshogi+yは、dlshogiからelmoを呼び出して読み筋を得る場合にelmo内で使用する評価関数がyであることを表します。

測定対象 基準 勝-負-分
dlshogi+NNUE 無改造dlshogi 226-162-12 (58.0%)
dlshogi+KPPT 無改造dlshogi 55-41-4 (57.0%)
dlshogi+KPPT dlshogi+NNUE 43-52-5 (45.5%)
無改造dlshogi elmo(8T,NNUE) 122-369-9 (25.3%)
dlshogi+NNUE elmo(8T,NNUE) 68-227-5 (23.5%)
dlshogi+KPPT elmo(8T,NNUE) 24-74-2 (25.0%)

無改造dlshogiとの対局においては、dlshogiと組ませる評価関数がNNUEでもKPPTでもほとんど差はないようです。dlshogi+NNUEとdlshogi+KPPTの直接対局では、NNUEのほうが若干強い可能性があります。一方で、elmoとの対局では、dlshogi+KPPTのほうがdlshogi+NNUEよりわずかに強い可能性が残ります。

elmoが強すぎるため、elmo単体のスレッド数を変えた場合の強さを示します。

測定対象 基準 勝-負-分
無改造dlshogi elmo(1T,NNUE) 56-40-4 (58.0%)
無改造dlshogi elmo(2T,NNUE) 34-64-2 (35.0%)
無改造dlshogi elmo(4T,NNUE) 16-84-0 (16.0%)
無改造dlshogi elmo(8T,NNUE) 28-68-4 (30.0%)
無改造dlshogi elmo(1T,KPPT) 71-26-3 (72.5%)
無改造dlshogi elmo(2T,KPPT) 50-48-2 (51.0%)
無改造dlshogi elmo(4T,KPPT) 34-64-2 (35.0%)
無改造dlshogi elmo(8T,KPPT) 44-56-0 (44.0%)
elmo(1T,NNUE) elmo(1T,KPPT) 221-77-2 (74.0%)

一貫して、elmoの評価関数としてはNNUEのほうが強いという結果です。無改造のdlshogiと強さが均衡するのはelmoが1~2スレッドの時のようです。elmoのスレッド数をあえて下げないときの設定として8を設定していましたが、4のほうが強いようです。物理コア4コア、ハイパースレッディングなしの環境ではこれが最適のようです。従来型エンジンの測定に慣れておらず、「物理コア数の2倍に設定する」という説明を盲目的に使用してしまっていました。

elmoを1スレッドに固定し、評価関数の組み合わせを変えて比較しました。dlshogiからelmoを呼び出す際のnps低下の影響を考慮するため、elmoを呼び出すが結果を無視する場合も試しました。dlshogi+0%と表記しています。

測定対象 基準 勝-負-分
無改造dlshogi elmo(1T,NNUE) 56-40-4 (58.0%)
dlshogi+0% elmo(1T,NNUE) 55-44-1 (55.5%)
dlshogi+NNUE elmo(1T,NNUE) 51-47-2 (52.0%)
dlshogi+KPPT elmo(1T,NNUE) 56-43-1 (56.5%)
無改造dlshogi elmo(1T,KPPT) 71-26-3 (72.5%)
dlshogi+0% elmo(1T,KPPT) 76-23-1 (76.5%)
dlshogi+NNUE elmo(1T,KPPT) 67-33-0 (67.0%)
dlshogi+KPPT elmo(1T,KPPT) 68-31-1 (68.5%)

ブレンドによって勝率が低下しているようです。dlshogi+0%は無改造dlshogiより純粋にnpsが低下しただけですが、elmo(1T,KPPT)に対する勝率が若干上がっており原因不明です。dlshogiの改造前後の直接対決ではブレンドしたほうが強くなるものの、elmoに対しては若干不利になるという結果でした。深層学習系の将棋エンジンがトップを争う状況であれば、今回の手法で少し優位に立てるかもしれないということになります。対戦相手によって手法の有効性が異なるという結果に対する仮説として、(1)dlshogi同士では相手の見落としを咎めることで有利になる可能性があるが、elmoに対してはdlshogi側のミスは減るが決勝打にはならない、(2)深層学習モデルの棋風が発揮されるのを阻害してしまっているという可能性がありますが、これらを実証する方法は現状思いついていません。棋風などについて詳しい方なら検証できるかもしれません。

手元の環境・知識でできそうな実験は終わったので、本連載はここで終わりとします。最後に、今回実装したソフトの動かし方を記事にします。