やねうら王 — 日本将棋AIの探索基盤
やねうら王 は、やねうらお 氏が開発する将棋AIエンジン。 日本の将棋AI界では 探索エンジンのデファクトスタンダード であり、 「水匠」「Háo」「tanuki-」など、現在世界トップクラスの評価関数たちは すべて やねうら王の上で動いている。 このページでは、やねうら王の 歴史・アーキテクチャ・探索アルゴリズム・エコシステムを、 第7章 や 第8章 よりも一段深く掘り下げます。
やねうら王とは何か(概要)
探索エンジンのデファクトスタンダード
やねうら王は 「指し手の探索」 を担う将棋AIエンジン本体。
評価関数(NNUE)は別に学習され、ファイル(nn.bin)で差し替え可能。
GitHubで完全オープンソース
ソースコードもビルド手順も公開。個人でも改造して大会に出られる。 やねうらお氏のブログ・著書で技術解説も豊富。
エコシステムの土台
「やねうら王 + 水匠」「やねうら王 + Háo」「やねうら王 + tanuki-」… 探索の達人と 評価関数の達人を分業させる構図を作った。
💡 核心: やねうら王の最大の功績は 「探索と評価関数を分離するインターフェース」 を整備したこと。 これにより、探索の改良と 評価関数の学習を別チームが並行して進められるようになり、 日本将棋AIは個人開発者の集合知で世界トップに上り詰めた。
1. 歴史 — やねうらお氏の歩み
やねうら王の歴史は、「将棋AIの民主化」 の歴史でもあります。 以下、主要な節目をたどります。
| 年 | 出来事 | 意義 |
|---|---|---|
| 2005年 | Bonanza(保木邦仁氏)が機械学習で評価関数を獲得 | 「Bonanzaメソッド」の衝撃。やねうらお氏もこれに触発される |
| 2013年頃 | やねうらお氏が将棋AI開発に本格参入 | Stockfish 系の探索を将棋に移植・改良 |
| 2015年 | やねうら王を GitHub で公開 | 本格的なオープンソース化。世界中の開発者が改造できるように |
| 2017年 | 第27回世界コンピュータ将棋選手権 で elmo(やねうら王ベース)が優勝 | 探索エンジンとしての地位を確立 |
| 2018年 | NNUE(那須悠氏)の登場、やねうら王に統合 | CPU 上の浅いMLP評価関数を載せた最強構成が誕生 |
| 2019年〜 | 水匠・たぬき・Háo などの評価関数チームが続々と「やねうら王 + 評価関数ファイル」で参戦 | 分業エコシステムの完成形 |
| 2020年代 | ふかうら王(DL 版やねうら王)公開 | NNUE 系だけでなく dlshogi 系の MCTS + 深いCNN も同じブランドでカバー |
| 継続中 | やねうらお氏のブログ・著書で技術解説 | 『コンピュータ将棋の進歩』『〜将棋AI開発でガチで使える本』など、後進への啓蒙 |
🏔️ 補足:やねうらお氏の人物像(クリックで展開)
やねうらお氏は、ハンドルネームで活動する個人開発者。本業はゲーム開発エンジニア。 Stockfish(チェス)の探索アルゴリズムを徹底的に読み込み、将棋向けに改造・拡張する形で やねうら王を育ててきた。
- ブログ『やねうら王公式サイト』で 開発記録を逐一公開
- 世界コンピュータ将棋選手権・電竜戦などに継続参戦
- 著書を通じて「将棋AIの内部構造」を後進に伝える
- 「個人でも世界トップを狙える」と示し続けたカリスマ
まっしー視点では「OSS と個人開発のロールモデル」として強く意識している人物。
📚 補足:Stockfish ベースから独自進化への流れ(クリックで展開)
やねうら王の初期は、チェスの世界最強オープンソースエンジン Stockfish の 探索コードを将棋に移植したものでした。
- α-β + LMR + Null Move などの探索テクニックは Stockfish 由来
- 将棋特有の「持ち駒」「成り」「打ち」を扱うため、指し手生成・置換表のキー設計を大幅改造
- その後、定跡データベース・並列化・将棋特有の枝刈りなどで Stockfish とは別の方向へ進化
逆方向に、NNUE は 将棋発でチェス Stockfish に逆輸入 された珍しい例。日本発の発明が世界標準になった瞬間。
2. アーキテクチャ — 探索特化のエンジン
やねうら王の中身は大きく 4ブロック に分けられます。 ここを理解すれば、「なぜ評価関数を差し替えられるのか」が一目でわかります。
ポイント:探索部と評価関数の境界が 明確に定義されている。
探索部は evaluate(position) -> int という関数を呼ぶだけで、
その中身が「水匠」か「Háo」かを気にしない。これが分業エコシステムを成立させる工学的な工夫です。
2.1 4ブロックの役割
| ブロック | 仕事 | 担当者 |
|---|---|---|
| 探索部 | 木をどこまで深く・どの手を読むかを決める | やねうら王本体(やねうらお氏) |
| 評価関数 | 1局面を1つの評価値に変換する | 水匠・Háo・tanuki- など別チーム |
| 定跡 | 序盤の手を DB から即決 | 各エンジン同梱 / コミュニティ作成 |
| 並列化 | マルチコアで木を並列展開 | やねうら王本体 |
3. α-β木探索とは何か — 詳細
やねうら王の心臓は α-β木探索。Minimax の改良版で、明らかに悪い枝を早めに刈り取ることで 同じ深さでも遥かに少ないノードで読めるアルゴリズムです。
3.1 Minimax の発想(前提)
Minimax は「自分は評価値を最大化、相手は最小化」と仮定して、 木を末端まで読み、葉ノードの評価値を上に伝播させる:
function minimax(node, depth, maximizing):
if depth == 0 or node が終局:
return evaluate(node)
if maximizing: // 自分の手番
best = -∞
for child in children(node):
val = minimax(child, depth-1, false)
best = max(best, val)
return best
else: // 相手の手番
best = +∞
for child in children(node):
val = minimax(child, depth-1, true)
best = min(best, val)
return best
問題:将棋は1局面あたり約80手の候補があるので、深さ d 読むと 80d ノード。 d=10 で約 1019 ノード。到底読み切れない。
3.2 α-β枝刈りの直感
α-β は、Minimax と 同じ答え を出しつつ、「もう調べる必要のない枝」を読まずに飛ばします。 直感は「相手が選ばない手を読んでも仕方ない」:
3.3 α-β の擬似コード(JS風)
// 自分(max)の手番から探索を開始
function alphaBeta(node, depth, alpha, beta, maximizing) {
if (depth === 0 || isTerminal(node)) {
return evaluate(node); // ← 評価関数を呼ぶのはここ(NNUEなど)
}
if (maximizing) {
let value = -Infinity;
for (const child of moveOrder(node)) {
value = Math.max(value, alphaBeta(child, depth-1, alpha, beta, false));
alpha = Math.max(alpha, value);
if (alpha >= beta) break; // ★β枝刈り:これ以上読んでも無駄
}
return value;
} else {
let value = +Infinity;
for (const child of moveOrder(node)) {
value = Math.min(value, alphaBeta(child, depth-1, alpha, beta, true));
beta = Math.min(beta, value);
if (alpha >= beta) break; // ★α枝刈り
}
return value;
}
}
// 反復深化(Iterative Deepening)
function search(root, maxDepth) {
let best;
for (let d = 1; d <= maxDepth; d++) {
best = alphaBeta(root, d, -Infinity, +Infinity, true);
// ★ 浅い結果を moveOrder のヒントに使う → 枝刈り効率UP
}
return best;
}
反復深化 がポイント:いきなり深さ10を狙わず、深さ1, 2, 3, ... と順に読む。 浅い読みの結果を moveOrder(指し手の並べ替え)に流用すると、 「最善手から先に試す」ことになり α-β の枝刈り効率が劇的に上がる。
📚 補足:α-β の効率 — 「同じ答え」で「ノード数 √ になる」(クリックで展開)
最良の手順序で枝刈りすると、α-β のノード数は Minimax の 平方根オーダーになります:
$$ N_\text{Minimax} = b^d \quad\Rightarrow\quad N_\text{αβ最良} \approx b^{d/2} $$
将棋(b ≈ 80)で d=10 の場合:
- Minimax:8010 ≈ 1019 ノード(不可能)
- α-β(最良):805 ≈ 3.3×109 ノード(現代CPU で数秒〜数分)
つまり「同じ深さ d を読むコスト」が一気に現実的になります。
4. 高速化テクニック
やねうら王が世界トップ級になれるのは、α-β を「賢く・速く」走らせる多数のテクニックの積み重ねです。 ここでは主要4つを擬似コードで示します。
4.1 LMR — Late Move Reductions
候補手を「良さそうな順」に並べたあと、遅い順位の手は浅い深さで読む。 悪い手はどうせ評価値が悪いはずなので、深く読むコストを節約:
// 各子ノードを評価するループの中で
for (let i = 0; i < children.length; i++) {
const child = children[i];
let reduction = 0;
if (i >= 3 && depth >= 3 && !isCheck(child)) {
reduction = 1 + Math.floor(Math.log(i) / Math.log(2));
// ★ 「i 番目以降」「王手じゃない」「ある程度深い」とき、深さを削る
}
let val = -alphaBeta(child, depth - 1 - reduction, -beta, -alpha, !max);
if (reduction > 0 && val > alpha) {
// 削った結果が良すぎたら、フルの深さでもう一度読み直す
val = -alphaBeta(child, depth - 1, -beta, -alpha, !max);
}
}
4.2 Null Move Pruning — パスしても勝てるなら読み切らない
「もし自分が手番をパスして、それでも局面が良かったら、もう先は読まなくていい」という発想。 将棋では「パス」はルール上できませんが、探索木のアイデアとして使えます:
function alphaBeta(node, depth, alpha, beta, maximizing) {
// ... 標準処理 ...
// ★ Null Move Pruning
if (depth >= 3 && !inCheck(node) && hasNonPawnMaterial(node)) {
// 自分の手をパスして相手に渡す
const nullNode = makeNullMove(node);
const val = -alphaBeta(nullNode, depth - 3, -beta, -beta + 1, !maximizing);
if (val >= beta) {
return beta; // パスしても勝てる → これ以上読まない
}
}
// ... 通常の子探索 ...
}
4.3 置換表(Transposition Table)— 同じ局面を二度読まない
将棋では 違う手順から同じ局面に到達することが頻繁にあります(指し手の入れ替え可能性)。 一度評価した局面はハッシュ表に保存し、再訪したら即返す:
const TT = new Map(); // 置換表(実装では巨大な配列+Zobrist hash)
function alphaBeta(node, depth, alpha, beta, maximizing) {
const key = zobristHash(node);
const cached = TT.get(key);
if (cached && cached.depth >= depth) {
// ★ 既に十分深く読んだ結果がある → 即返却
return cached.value;
}
// ... 通常の探索 ...
TT.set(key, { value, depth, bestMove }); // 結果をキャッシュ
return value;
}
4.4 並列探索 — 複数スレッドで木を分担
やねうら王は マルチスレッド・NUMA に対応。複数CPUで木を並列展開し、 置換表を共有することで「同じ局面の重複探索」を避けつつスケールします:
// 概念図:ルート分割並列(Lazy SMP)
function parallelSearch(root, numThreads) {
const sharedTT = new ConcurrentMap();
const workers = [];
for (let t = 0; t < numThreads; t++) {
workers.push(spawn(() => {
// 各スレッドが少しずらした深さ・ヒューリスティクスで同じ木を探索
// 置換表を共有することで知見が伝播する
alphaBetaWithSharedTT(root, baseDepth + (t % 2), sharedTT);
}));
}
waitAll(workers);
return sharedTT.get(zobristHash(root)).bestMove;
}
📚 補足:その他の枝刈り — Futility / Razoring / SEE(クリックで展開)
- Futility Pruning:浅い末端付近で「評価値 + マージン < α」なら、その手は読まない
- Razoring:評価値が極端に悪いノードは静止探索(駒得駒損だけを追う)にショートカット
- SEE(Static Exchange Evaluation):駒交換が静的に得か損かを高速判定し、明らかに損な取り合いは読まない
- Killer Heuristic / History Heuristic:過去に良かった手を優先して試す → 早期β枝刈りを誘発
これらは すべて同じ答えを近似的に保ったまま速度を稼ぐ 工夫。やねうら王には全部入っています。
5. 評価関数の差し替え — 分業エコシステムの鍵
やねうら王の最大の発明(と言ってもいいくらいの)特徴は、評価関数を外部ファイルで差し替えられること。 これにより、探索の研究と 評価関数の研究が完全に分離されました。
5.1 関数境界 — search() と evaluate() の分離
やねうら王本体(探索部)は、評価関数の中身を知らない。「局面を渡したら数値が返ってくる関数」としてしか扱わない:
// ===== やねうら王本体(探索部) =====
function alphaBeta(node, depth, alpha, beta, max) {
if (depth === 0) {
return evaluate(node); // ★ ここだけが評価関数とのインターフェース
}
// ... α-β の標準処理 ...
}
// ===== 評価関数(差し替え可能) =====
// 起動時に nn.bin を読み込んで evaluator を構築
const evaluator = loadNNUE("suisho10.nn.bin");
// または
const evaluator = loadNNUE("hao.nn.bin");
// または
const evaluator = loadNNUE("tanuki-wcsc33.nn.bin");
function evaluate(node) {
// node の HalfKP特徴を抽出して、浅いMLPを通すだけ
return evaluator.forward(node);
}
この 「evaluate() の中身だけ差し替える」設計が、エコシステム全体を可能にしました。
5.2 「やねうら王 + ◯◯」エコシステム
| 組み合わせ | 評価関数の作者 | 特徴 |
|---|---|---|
| やねうら王 + 水匠 | たややん氏(杉村達也氏) | 長年 WCSC・電竜戦の上位常連。NNUE 系評価関数の代表格 |
| やねうら王 + Háo | Hao 開発者ら | 自己対局による教師生成で精度向上。最新世代のNNUE |
| やねうら王 + tanuki- | たぬきチーム | 独自の特徴量とハイブリッド学習 |
| やねうら王 + elmo | 瀧澤誠氏 | 2017年 WCSC 優勝(当時)。歴史的な組み合わせ |
| ふかうら王(DL系) | やねうらお氏 +dlshogi モデル | MCTS + 深いCNN。NNUE系とは別系統 |
🧠 上級補足:なぜ「分業」が決定的に効くのか(クリックで展開)
探索と評価関数は、求められる職能が まったく違う:
- 探索:C++・低レベル最適化・SIMD・並列化・アルゴリズム設計
- 評価関数:PyTorch・GPU学習・教師データ生成・ハイパーパラメータ調整
一人で全部やるよりも、それぞれの専門家が分業した方が 進化が速い。 やねうら王はそのインターフェースを整備することで、コミュニティ全体の知能を集約する装置になりました。
まっしー視点:これは「API設計が組織を作る」の好例。優れた境界線が、エコシステムを生む。
6. ふかうら王 — やねうら王の DL バージョン
やねうら王ブランドは、NNUE 系(CPU・α-β)だけでなく、DL 系(GPU・MCTS)もカバーします。 それが ふかうら王:
- 探索:α-β ではなく MCTS(モンテカルロ木探索)
- 評価:浅い MLP ではなく 深い CNN + ResNet(dlshogi 系モデル)
- 差し替え可能性:dlshogi の学習済みモデルをそのまま使える
- ハード:GPU 推論が必須
同じ「やねうら王」ブランドの下に NNUE型・DL型の両方が存在する。 ユーザーは用途に応じて使い分けられる。
📚 補足:NNUE型 vs DL型 — どちらを選ぶか(クリックで展開)
| 観点 | NNUE型(やねうら王+水匠) | DL型(ふかうら王+dlshogi) |
|---|---|---|
| ハード | CPU(多コアほど良い) | GPU(VRAM多いほど良い) |
| 秒間ノード数 | 数百万〜1億 | 数千〜数万(深い評価) |
| 序盤・中盤 | 強い(読みが深い) | 強い(戦略パターン認識) |
| 終盤・詰み | 非常に強い(深く読み切る) | 苦手な場合がある |
| 初期コスト | 低い(PC1台で動く) | 高い(GPU必要) |
まっしーは macOS Apple Silicon 機なので、現状は やねうら王 V9.00 + Háo(NNUE型)が主戦力。
7. やねうら王が将棋AI界に与えた影響
🔗 探索と評価関数の分業
インターフェースを整備し、研究の並列化を可能にした。 評価関数チームは探索の細部を知らなくてよく、その逆も成立。
👤 個人開発者の時代を作った
GitHub OSS とブログ解説により、個人開発者でも世界トップを狙えるエコシステムが成立。 巨大企業 AI と対極の文化を育てた。
🏆 評価関数チームの誕生
「水匠」「Háo」「tanuki-」「elmo」など、 評価関数特化型のチームが続々と参戦。WCSC・電竜戦の常連勢力に。
📖 教育的価値
ソースコードが世界中の将棋AI開発者・研究者の 必読書に。 α-β・LMR・置換表・並列化の実装例として、教育素材としても価値が高い。
🇯🇵 NNUE の世界輸出
将棋発の NNUE が、やねうら王での実装を経て Stockfish(チェス)に輸出。 日本発の発明が世界標準になる現象を実現した。
🌳 探索研究の継続発展
Stockfish 由来の探索を将棋に最適化し、独自の枝刈り・並列化を継続的に改良。 探索アルゴリズム単体でも研究フロンティアであり続けている。
💡 まとめ: やねうら王は単なる「強い将棋AI」ではなく、「将棋AI開発の社会インフラ」。 探索と評価関数の境界を整備することで、個人・チーム・コミュニティが 並走しながら全体として進化する仕組みを作った。 これが日本将棋AIが世界を引き続きリードできる理由です。
8. 関連リンク
このサイト内の関連ページ
- 第7章 将棋AIで全部確認 — NNUE型・DL型の全体像
- 第8章 CEDEC2024で深堀り — やねうらお氏・たややん氏本人の言葉
- 第9章 棋士視点で最先端 — プロ棋士から見た現代の将棋AI
- 🔎 詳細:NNUE — 評価関数の中身(HalfKP・差分更新・量子化)
- 🔎 詳細:dlshogi — DL派の対抗馬(MCTS + 深いCNN)
参考にした概念(このサイト内)
- 第1章:機械学習の全体像(Bonanzaメソッドの位置づけ)
- 第3章:MLP(NNUE 評価関数の中身)
- 第4章:勾配降下法・Adam(NNUE の学習に使われる)
- 第5章:CNN・ResNet(ふかうら王 / dlshogi の評価ネット)
外部リソース
- やねうら王 GitHub:
github.com/yaneurao/YaneuraOu - やねうら王公式サイト・ブログ:開発記録・技術解説
- 世界コンピュータ将棋選手権(WCSC):年1回の最大の競技会
- 電竜戦:オンライン形式のコンピュータ将棋大会
まとめ
- やねうら王は 日本の将棋AI探索エンジンのデファクトスタンダード
- 2015年 GitHub 公開以降、個人開発者でも参加できるエコシステムを構築
- アーキテクチャは 探索部・評価関数(差し替え可能)・定跡・並列化の4ブロック
- 探索の心臓は α-β木探索 + 反復深化。LMR・Null Move・置換表・並列化で高速化
- 評価関数を
nn.binファイルで差し替え可能 にしたことが分業エコシステムを生んだ - NNUE 系の「水匠」「Háo」「tanuki-」、DL 系の「ふかうら王」など 派生が豊富
- 将棋AI界に 「探索と評価関数の分業」「個人参加可能性」「日本発の世界輸出」という構造変化をもたらした
もっと深く知るには
やねうら王の上で動く NNUE 評価関数の中身を詳しく知りたい人は:
対抗馬の DL 系(MCTS + 深いCNN)を見たい人は:
開発者本人(やねうらお氏・たややん氏)の言葉で歴史と技術を聞きたい人は: