Lazy SMP

Lazy SMP は、複数スレッドが同じルート局面をほぼ独立に探索しつつ、 共有置換表を通じてゆるく協調する並列探索方式である。 実装のしやすさに対して実用上の効果が高く、現代エンジンで広く採用されている。

概要

Lazy SMP では、各スレッドが

  • 同じ局面
  • 似た深さ
  • 少し違う手順や深さ設定

で探索を進める。

完全に仕事を厳密分担するのではなく、 どこかのスレッドが見つけた情報を共有置換表へ書き込み、 他のスレッドがそれを利用することで全体として得をする。

なぜ「lazy」なのか

この方式は、厳密な仕事分配や複雑な同期を避け、 「だいたい同じ探索を並列に走らせて、共有情報から自然に利益を得る」 という緩い協調を取る。

そのため、

  • 実装が比較的簡単
  • 複雑な並列 αβ より壊れにくい
  • 実戦強度で十分なスケーリングが出やすい

という利点がある。

Thread Voting

最近の実装では、各スレッドの最善手候補を集めて投票する thread voting が使われることがある。

各スレッドの

  • 深さ
  • スコア
  • 最善手

を見て、どの手を最終的なルート手として採用するかを決める。

実装イメージ

void startHelpers(const Position& root, int depth, int alpha, int beta) {
    for (Thread& th : helperThreads) {
        th.root = root;
        th.depth = depth + th.id % 2; // 少しだけ深さをずらす例
        th.alpha = alpha;
        th.beta = beta;
        th.start();
    }
}

実際には、

  • 共有ハッシュ
  • 停止フラグ
  • ルート手の投票
  • 反復深化との同期

を合わせて設計する。

Stockfish との関係

Chessprogramming Wiki にもある通り、 Stockfish は 2016 年ごろに YBW 系から Lazy SMP へ移行したことで知られる。 GitHub 上の議論でも、 「スレッド数を増やすと同じ答えへ早く到達するというより、 同じ時間でより強い手を見つけやすくなる」 という性質が説明されている。

将棋AIでの位置づけ

将棋AIでも、

を前提にした並列探索では、Lazy SMP 的な発想は非常に相性がよい。

ただし、スレッド数が増えると

  • メモリ帯域
  • ハッシュ競合
  • NUMA

の影響も大きくなる。

注意点

  • 厳密な仕事分割ではないので、理論上は重複探索が多い
  • 時間短縮と棋力向上は同じではない
  • 大規模マシンでは NUMA やメモリ帯域がボトルネックになりやすい

関連項目

参考にしたホームページ