NNUE

NNUE は、CPU 上で高速に使えることを強く意識して設計されたニューラルネットワーク型の評価関数である。 将棋AIの文脈で 2018 年に那須悠氏が導入し、その後 Stockfish 系にも広がって大きな影響を与えた。

概要

NNUE は Efficiently Updatable Neural Network の略で、 「一手進めるたびにネットワーク全体を最初から計算し直すのではなく、 差分だけを効率よく更新する」ことを重視した構造を持つ。

一般的な深いニューラルネットワークより軽く、 アルファベータ法中心の探索と組み合わせて CPU で大量に評価できるのが特徴である。

将棋AIとの関係

Chessprogramming Wiki でも、NNUE は

とのつながりの中で説明されている。

将棋AIでは、手作り評価から学習評価への大きな橋渡しとして非常に重要である。

基本的な考え方

NNUE の要点は次の通りである。

  • 入力は局面特徴
  • 最初の大きな層は accumulator として保持する
  • 一手進むたびに、変化した特徴分だけ加減算して更新する
  • 更新後の値から最終評価値を得る

これにより、毎ノードでフル推論するよりはるかに高速になる。

accumulator

NNUE の中心にあるのが accumulator である。 これは「現在局面に対応する中間層の値」を保持する配列で、 局面変化に応じて差分更新する。

静かな手なら、変化する特徴は少ないため、

  • 消える特徴の重みを引く
  • 新しく有効になる特徴の重みを足す

だけで済むことが多い。

実装イメージ

差分更新の最小イメージは次のようになる。

void updateAccumulator(Accumulator& acc,
                       const std::vector<int>& removedFeatures,
                       const std::vector<int>& addedFeatures) {
    for (int idx : removedFeatures) {
        for (int i = 0; i < HIDDEN; ++i) {
            acc.value[i] -= weight[idx][i];
        }
    }

    for (int idx : addedFeatures) {
        for (int i = 0; i < HIDDEN; ++i) {
            acc.value[i] += weight[idx][i];
        }
    }
}

これは概念説明用の単純化した例であり、実際には

  • 2 視点構成
  • 量子化
  • SIMD
  • lazy update

などの最適化が入る。

将棋からチェスへの波及

NNUE は将棋側で成果を出したあと、 Stockfish 系へ移植されて一気に広まった。 Chessprogramming Wiki でも、Shogi 由来であることと Stockfish NNUE で普及したことの両方が強調されている。

学習

NNUE の強さはアーキテクチャだけでなく、

  • 教師局面の作り方
  • 学習データの質
  • 探索器との整合
  • 量子化や出力スケール

にも強く依存する。

やねうら王側の記事でも、学習器やバージョン差で結果がかなり変わることが説明されている。

将棋AIでの位置づけ

現在の将棋AIでは、

  • 純粋な Deep Learning 系
  • NNUE + alpha-beta 系

が並立している。

NNUE は後者の中心技術であり、 従来の探索器を活かしたまま学習評価を強くできる点で非常に実用的である。

注意点

  • 推論が軽いとはいえ、手作り評価より遅くなることは多い
  • 学習データや学習条件に強く依存する
  • 差分更新が壊れると評価値全体が破綻しやすい

関連項目

参考にしたホームページ