将棋AIで全部確認 — 学んだ概念の集大成
これまで学んできた 機械学習・ニューラルネット・学習アルゴリズム・CNN・Transformer・生成AI。 これらすべてが将棋AIで 実装され、闘い、進化している 様を、本章で総まとめします。 将棋AIは、抽象的な機械学習概念を具体的に観察できる 最高の実例集です。
この章の全体像
3世代の進化
将棋AIの50年史は、機械学習・DLの進化と完全にパラレル。 人力時代 → Bonanza革命 → ディープラーニング2系統。
2大潮流が共存
NNUE型(CPU + α-β + 浅いMLP)と DL型(GPU + MCTS + 深いCNN)が並走。
すべての概念が実装されている
第1〜6章で学んだ概念が、すべて 実在する将棋AIで具体的に動いている。
💡 核心: これまでの章で学んだ概念は、すべて 将棋AIで「実装され、闘い、進化している」。 抽象的な機械学習論ではなく、具体的に 勝率・レーティング という形で現実の指標として現れる。 それゆえ将棋AIは、機械学習を学ぶうえで最高の 実例集 になります。
1. 将棋AIの3世代
将棋AIの歴史は、第1章〜第6章 で見たAIの歴史と完全に並走しています。
🏔️ 歴史背景:1.1 第1世代(〜2005年)— 人力で全部設計(クリックで展開)
評価関数を 人間が手で設計 していた時代。
- 駒の点数(歩=100、飛車=1000など)を 人間(プロ棋士の感覚)が決定
- 玉の囲い、駒の利きなど、特徴量も人手で考案
- 各特徴の重みも試行錯誤で調整(職人芸)
探索アルゴリズムは α-β法(ミニマックスの効率版)が標準。
対応:第1章「統計学的アプローチ」 + 古典α-β探索
🏔️ 歴史背景:1.2 第2世代(2005年〜)— Bonanzaメソッドの革命(クリックで展開)
2005年、Bonanza(保木邦仁氏)が革命を起こしました。
「プロ棋士の指し手を最善とするように、評価関数の重みを自動学習する」というアイデア。 これにより:
- 駒の点数すら、データから自動的に決まるようになった
- 数千万のパラメータを機械が最適化
- 「評価関数作りは職人技」の時代が終わった
これは 第1章 の 古典機械学習革命そのもの。 ただし特徴量の枠組み(KPP、KKPTなど)は依然として人間が設計していた。
対応:第1章「機械学習」+ 第4章「学習の仕組み」
1.3 第3世代(2018年〜)— ディープラーニング2系統
ディープラーニングが将棋AIに導入されたのは、2017年の AlphaZero(DeepMind)と、2018年のNNUE(那須悠氏)。 異なる方向性の 2大潮流 が並走することになります。
| 系統 | 代表エンジン | 探索 | 評価 | ハード |
|---|---|---|---|---|
| NNUE型 | やねうら王、水匠、Háo | α-β | 浅いMLP(4層) | CPU |
| DL型 | dlshogi、ふかうら王、AlphaZero | MCTS | 深いCNN+ResNet | GPU |
両方とも 第2章「ディープラーニング」に該当しますが、 浅い vs 深い の対比そのものが、将棋AIで実装されています。
2. NNUE / dlshogi / やねうら王 — 3つの実装を深掘り
将棋AIには 3つの主要コンポーネントがあり、それぞれが本サイトの「詳細ページ」で網羅的に解説されています:
NNUE — 浅いMLP評価関数
那須悠氏発明の 効率的差分更新ニューラルネット。HalfKP特徴、ClippedReLU、量子化、3つの工夫など。 「銀×金 の位置関係は表現できる?」「誰が特徴を作った?」「自分玉と相手玉の関係は?」などの設計トレードオフも詳述。
🔎 詳細dlshogi — 深いCNN評価関数
山岡忠夫氏が開発する AlphaZero型。9×9×100テンソルを深いCNN+ResNetで処理し、Policy/Value 2ヘッドでMCTSと連携。 強化学習による自己対局で人間データなしに強くなる仕組み、NNUEとの対比など徹底解説。
🔎 詳細やねうら王 — 探索基盤
日本の将棋AIの 探索エンジンのデファクトスタンダード。α-β木探索、LMR、Null Move Pruning、置換表、並列化。 「探索 vs 評価関数」分業エコシステムの土台を作ったOSS。NNUE評価関数と組み合わせて世界トップクラスへ。
💡 3つの関係を1行で: 「やねうら王(探索の達人)+ NNUE評価関数(評価の達人)」がNNUE型エンジンの実体。 対するdlshogiは深いCNN+MCTSという別パラダイム。両者は哲学が真逆だが補完的に共存している。
3. 探索部 vs 評価関数 — 役割分担と α-β探索
将棋AIを理解するうえで 最も基本的で重要な区別 が「探索部」と「評価関数」の役割分担です。 この章では 疑似コード で両者を分解し、特に α-β探索 を深く掘り下げます。
3.1 探索部と評価関数 — 役割の違い
人間の将棋にたとえる
| 人間の能力 | 将棋AIの対応 | 役割 |
|---|---|---|
| 「読み」(5手先・10手先を考える) | 探索部 | 「もし▲7六歩なら、相手は△8四歩、その後私は…」を機械的に展開 |
| 「大局観」(局面を見て即座に判断) | 評価関数 | 「この局面、なんとなく先手の方が指しやすそう」を数値化 |
3.2 疑似コード:完全な将棋AIの骨組み
実際の将棋AIエンジンの基本構造を、JavaScriptで100行ほどに圧縮した疑似コードで見てみます。 探索部と評価関数の境界線 がはっきり分かるはずです:
// ============================================
// 将棋AIエンジンの骨格
// ============================================
// 【探索部】指し手を選ぶ最上位関数(やねうら王の役割)
function bestMove(position, maxDepth) {
let bestScore = -Infinity;
let bestMov = null;
for (const move of generateLegalMoves(position)) {
const nextPos = applyMove(position, move);
// 相手番として読みを進める(符号反転=negamax)
const score = -alphaBeta(nextPos, maxDepth - 1, -Infinity, Infinity);
if (score > bestScore) {
bestScore = score;
bestMov = move;
}
}
return { move: bestMov, score: bestScore };
}
// 【探索部】α-β木探索(やねうら王の核心)
function alphaBeta(position, depth, alpha, beta) {
// ★ 葉(depth=0 or 詰み)→ 評価関数を呼ぶ
if (depth === 0 || isGameOver(position)) {
return evaluate(position); // ←ここがNNUE/dlshogi等の差し替えポイント
}
let maxScore = -Infinity;
for (const move of generateLegalMoves(position)) {
const nextPos = applyMove(position, move);
const score = -alphaBeta(nextPos, depth - 1, -beta, -alpha);
if (score > maxScore) maxScore = score;
if (maxScore > alpha) alpha = maxScore;
// ★ α-β枝刈り:これ以上読んでも意味がないので打ち切り
if (alpha >= beta) break;
}
return maxScore;
}
// 【評価関数】1局面 → 1つの数値(NNUE/dlshogi/水匠/Háo/氷彗が担当)
function evaluate(position) {
// ここの中身が各エンジンで違う:
// - NNUE系:HalfKP特徴抽出 → 浅いMLP → スカラー出力
// - dlshogi系:9×9×100テンソル → 深いCNN+ResNet → Value head
return nnueEvaluate(position); // ←水匠/Háo/氷彗ファイルでここの中身が変わる
}
📝 各行を丁寧にコメント付きで読み解く
上のコードを 1行ずつコメントで詳細に説明した拡張版 です。「何のためにこの行が必要か」「なぜこの書き方か」まで分かります:
// ════════════════════════════════════════════════════════════════════
// 将棋AIエンジンの骨格 — 各行に丁寧なコメント付き
// ════════════════════════════════════════════════════════════════════
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【探索部 ①】最上位:指し手を1つ選んで返す関数
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 引数:
// position : 現在の局面(盤面情報)
// maxDepth : 何手先まで読むか(例: 8 なら 8手先まで)
// 戻り値:
// { move: 最善手, score: その評価値 }
function bestMove(position, maxDepth) {
// 「これまで見つかった最善のスコア」を最低値で初期化
// どの手でも、これより悪いことはない、というスタート地点
let bestScore = -Infinity;
// 「これまで見つかった最善の手」をまだ未定
let bestMov = null;
// この局面で指せる全ての合法手を1つずつ試す
// (将棋では平均で約80通りの合法手がある)
for (const move of generateLegalMoves(position)) {
// 「もしこの手を指したら」の盤面を作る(仮想的に1手進める)
const nextPos = applyMove(position, move);
// 相手番として再帰的に探索する
// ★ ポイント1: 符号反転 (-alphaBeta) しているのは「相手の評価値」を
// 「自分の評価値」に変換するため。これを negamax 形式という。
// ★ ポイント2: depth を 1 減らして「残りの読みの深さ」を渡す
// ★ ポイント3: 初回は α=-Infinity, β=+Infinity(制限なし)でスタート
const score = -alphaBeta(nextPos, maxDepth - 1, -Infinity, Infinity);
// この手のスコアが今までの最善より良ければ更新
if (score > bestScore) {
bestScore = score; // 最高記録を更新
bestMov = move; // この手を「最善手」として記録
}
}
// 全部の手を試したあと、最も評価値が高かった手を返す
return { move: bestMov, score: bestScore };
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【探索部 ②】α-β 木探索の本体(やねうら王の核心)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 引数:
// position : 現在の局面
// depth : あと何手読むか(0 になったら葉ノード = 評価関数を呼ぶ)
// alpha : 「自分が今のところ保証できる最低スコア」
// beta : 「相手が許してくれる最高スコア」
// 戻り値:
// この局面の評価値(自分から見たスコア)
function alphaBeta(position, depth, alpha, beta) {
// ★ 葉ノードに到達 → 評価関数を呼んで終わり
// depth が 0 になった = 「ここまで読みました」の終端
// isGameOver = 詰み・千日手・宣言勝ちなど対局終了の判定
if (depth === 0 || isGameOver(position)) {
return evaluate(position);
// ↑ ここが NNUE / dlshogi の差し替えポイント!
// 評価関数を入れ替えるだけで別のエンジンになる
}
// 現在の局面から見て「最大のスコア」を探す
// (葉に到達しなければ、子ノードを全部見て一番良い手を選ぶ)
let maxScore = -Infinity;
// この局面で指せる全ての合法手を試す
for (const move of generateLegalMoves(position)) {
// 1手進めた次の局面を作る
const nextPos = applyMove(position, move);
// 再帰的に深く読む(negamax 形式:符号反転 + α/β を入れ替えて渡す)
// ★ -beta, -alpha と引数の順序が逆になっているのは negamax の流儀
// 「相手から見た α・β」は「自分から見たβ・α」を符号反転したもの
const score = -alphaBeta(nextPos, depth - 1, -beta, -alpha);
// この手のスコアが、これまでの最大より良ければ更新
if (score > maxScore) maxScore = score;
// α(自分の保証ライン)を更新
// 「少なくとも maxScore は取れる」と確定したので、α もそれに引き上げ
if (maxScore > alpha) alpha = maxScore;
// ★ ★ ★ α-β 枝刈り(プルーニング) ★ ★ ★
// alpha >= beta になったら、これ以上この局面の他の手を読む意味がない
// 理由:「相手は絶対に β より良くはさせない」ので、自分が α を超える手を
// 見つけた時点で、「相手はこの枝を選ばない」と確定する。
// 残りの手は読まなくても結論は変わらない。
if (alpha >= beta) break;
}
// 全合法手を見終わったあと、最大スコアを返す
return maxScore;
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【評価関数】1つの局面を見て、1つの数値で評価する
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 引数:
// position : 局面
// 戻り値:
// 評価値(スカラー)。正なら手番側が有利、負なら相手有利
// 例: +120 = 先手やや有利、 -500 = 後手大優勢
function evaluate(position) {
// ★ ここの中身は各エンジンで違う!
// ──────────────────────────────────────────────
// ・NNUE 系(水匠 / Háo / tanuki- / 氷彗):
// 盤面 → HalfKP特徴抽出(41,024次元の疎ベクトル)
// → 浅いMLP(4層)でスカラーに変換
// → 評価値(int16)を返す
// ──────────────────────────────────────────────
// ・dlshogi 系:
// 盤面 → 9×9×100 テンソル(駒種ごとのバイナリマップ)
// → 深いCNN + ResNet(20〜40層)
// → Value head(スカラー出力)
// ──────────────────────────────────────────────
return nnueEvaluate(position);
// ↑ ここを差し替えるだけで「水匠を使うAI」「Háo を使うAI」
// 「氷彗を使うAI」のように、別のエンジンが完成する
// これが「探索部はやねうら王、評価関数は別の人が育てる」
// という分業エコシステムの正体
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 補助関数(実装は省略、概念だけ示す)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// generateLegalMoves(position):
// 現局面で指せる全ての合法手を返す
// 将棋では「打ち歩詰め」「自分の玉が王手放置」など複雑なルールがある
function generateLegalMoves(position) { /* ... */ }
// applyMove(position, move):
// 局面に1手指して、新しい局面を返す
// 実装上はビットボードなど効率的なデータ構造で高速化されている
function applyMove(position, move) { /* ... */ }
// isGameOver(position):
// 対局終了判定(詰み、千日手、宣言勝ち、入玉勝ちなど)
function isGameOver(position) { /* ... */ }
// nnueEvaluate(position):
// NNUE評価関数本体(実装は nnue.html 詳細ページ参照)
function nnueEvaluate(position) { /* ... */ }
🔑 重要な3つの概念を再確認
| 概念 | 意味 | どの行にある? |
|---|---|---|
| negamax 形式 | 「相手の評価値」と「自分の評価値」を 符号反転だけ で扱う仕組み。Max/Min を分けず1つの関数で書ける | score = -alphaBeta(...) の - |
| α/β の入れ替え | 再帰呼び出しで -beta, -alpha と入れ替えるのは「相手視点に切り替える」ため |
alphaBeta(nextPos, depth-1, -beta, -alpha) |
| α-β 枝刈り | alpha >= beta なら「相手は絶対この枝を選ばない」ので残り探索を打ち切り |
if (alpha >= beta) break; |
この疑似コードからわかる3つのこと
- ① 探索部と評価関数は完全に分離している:
alphaBeta()とevaluate()は別の関数。インターフェース(引数と戻り値)が固定なので、差し替え自由 - ② 評価関数だけ差し替えれば、別のエンジンになる:
nnueEvaluate()を「水匠」「Háo」「氷彗」のファイルに変えるだけで、別のAIが完成。これが分業エコシステムの正体 - ③ 評価関数は「葉ノード」でしか呼ばれない:探索の途中ではなく、読みの末端で1回ずつ呼ばれる。だから秒間数百万回呼ばれる → 評価関数の高速性が重要
💭 「葉ノード」「読みの末端」って何? — 具体的なイメージで理解する
「葉ノード」「読みの末端」という言葉、いきなり出てくるとピンとこないですよね。木のたとえで1つずつほぐしてみます。
🌳 まず「探索木」というイメージ
将棋AIが 「3手先まで読む」 という時、頭の中で展開している構造を 木(ツリー) として描けます:
🎯 「葉ノード」「末端」とは何か
- 葉(leaf, リーフ) = 木の 「これ以上分岐しないノード」。木の絵で言えば、一番下のセル(緑のボックス)
- 読みの末端 = まさに同じ意味。「ここで読みを打ち切る」と決めた局面
- 具体的には
depth === 0になった時点。これが探索木の葉
🤔 なぜ「葉ノード」だけで評価関数を呼ぶのか
内部ノード(途中の節)で評価関数を呼ばない理由は、「評価関数は局面を見ただけで判断するから精度が低い」 ため。
例で考える:
- 「現在の局面」だけ評価関数に通すと → 「先手 +50(やや有利)」と出た
- でも実は次の1手で 飛車をタダ取りされる罠 がある!
- そこで「3手読んでから評価」してみると → 「先手 -800(飛車タダ取りで大劣勢)」と判明
- つまり 深く読んでから評価する方が正確。だから探索の末端まで深掘りしてから評価関数を呼ぶ
🔢 「葉ノードの数」が秒間数百万になる理由
たとえば 8手読みの探索木では:
| 深さ | 葉ノードの数(理論値) | α-β枝刈り後(実用値) |
|---|---|---|
| 3手読み | 80³ ≒ 50万 | 約 5,000 |
| 5手読み | 80⁵ ≒ 33億 | 約 60万 |
| 8手読み | 80⁸ ≒ 1700兆 | 約 1億局面 |
実戦では 1秒で1〜10億局面 を読みたい → 評価関数は秒間数百万回〜数千万回呼ばれる。 だから NNUE のような「1回 1マイクロ秒で評価できる超高速な評価関数」が必要なわけです。
💡 コードの中で「葉ノード」を見つける
上の疑似コードを見直すと、葉ノード判定は2行目 にあります:
function alphaBeta(position, depth, alpha, beta) {
// ★ ここが「葉ノード判定」
// depth === 0 → 「これ以上読まないと決めた末端」
// isGameOver → 「対局が終わった(詰みなど)」
if (depth === 0 || isGameOver(position)) {
return evaluate(position); // ★ ← 葉ノードでのみ評価関数を呼ぶ!
}
// ↓ ここから先は内部ノードの処理(さらに深く読む)
let maxScore = -Infinity;
for (const move of generateLegalMoves(position)) {
// ...
}
}
💡 1行まとめ: 「葉ノード」= 探索木の一番下=これ以上分岐しないノード=読みの末端。 深く読んでから評価するほうが精度が高いので、探索の末端まで掘り下げてから評価関数を1回ずつ呼ぶ。 8手読みなら葉ノードは数億個 → 評価関数は秒間数百万回呼ばれる → 評価関数の高速性が決定的に重要。
3.3 α-β探索を深く知る
上の疑似コードに出てきた alphaBeta() 関数。これが将棋AIの「読み」の中核 です。なぜ「α-β」と呼ばれるのか、どう動くのか、なぜ強いのか — 順番に紐解いていきます。
3.3.1 まず Minimax(α-βの土台)
α-β探索の前提となるのが Minimax アルゴリズム。 将棋のような 「2人完全情報ゲーム」 の最善手を求める古典的な探索手法です。
Minimax の考え方
- 自分の番では 「評価値が最大になる手」 を選ぶ
- 相手の番では 相手は「評価値が最小になる手(=自分にとって最悪の手)」 を選ぶ、と仮定
- これを再帰的に深い深さまで適用
「自分はMaximize、相手はMinimize」というのが Mini-max の語源。 探索木の各ノードで 「最大化する番」と「最小化する番」が交互に切り替わる 構造です。
3.3.2 Minimax の弱点:計算量爆発
将棋では1局面で平均 約80通りの合法手 があります。Minimax で n手先まで全部読むと:
| 読みの深さ | 探索する局面数 | 所要時間(仮) |
|---|---|---|
| 3手先 | 80³ ≒ 51万 | 0.5秒 |
| 5手先 | 80⁵ ≒ 33億 | 1時間 |
| 10手先 | 80¹⁰ ≒ 10兆 | 事実上不可能 |
| 40手先(実戦で必要) | 80⁴⁰ ≒ 天文学的 | 宇宙の年齢でも終わらない |
これでは 絶対に間に合わない。そこで α-β枝刈り が生まれました。
3.3.3 α-β枝刈り — 「読まなくていい枝」を見抜く
α-β法の核心は:「相手が絶対に選ばない手の先は、これ以上読んでも意味がない」 と気づいて打ち切ること。
💭「?」が +14 になる可能性は? — もっと丁寧に理解する
ここがα-β枝刈りの最も大事なポイント。「?」が+14だったらどうなる?大逆転しない? という疑問を、ステップごとに丁寧に解きほぐします。
📚 まず思い出す:Max と Min の役割
| ノード | 誰の番? | 選ぶ基準 |
|---|---|---|
| Max(赤、根) | 自分の番 | 子ノードの値のうち 最大(最も自分に有利) を選ぶ |
| Min(青、相手の番) | 相手の番 | 子ノードの値のうち 最小(最も自分に不利=相手に有利) を選ぶ |
🎮 インタラクティブデモ:?の値を変えて結果を確認!
「?」のところに どんな値(-100〜+100)を入れても、最終結果は変わらない ことを実際に動かして確認できます:
🤔 「?」が +14 だったら? — 計算を追ってみる
上のスライダーで 「?= +14」 にしてみると:
右Min の計算:
Min(+5, +14) = ?
Min は「最小値を選ぶ」のがルール。
+5 と +14 のうち、小さいのは +5。
⇒ 右Min = +5
つまり「?= +14」と分かっても、右Min の値は +5 のまま変わらない。
なぜなら相手(Min)は +14 なんて自分に不利な選択肢は 絶対に選ばないから。
「?」が どんな値であっても、Min は「小さい方」を選ぶので:
| 「?」の値 | Min(+5, ?) | 右Minの値 |
|---|---|---|
| +14 | min(+5, +14) | +5 |
| +100 | min(+5, +100) | +5 |
| +5 | min(+5, +5) | +5 |
| 0 | min(+5, 0) | 0(+5より小さい!) |
| -50 | min(+5, -50) | -50(さらに小さい!) |
✅ 大事な性質:右Min は「+5 以下」になる(上限のみ保証)
上の表をよく見ると、右Min は 場合によって違う値 になることが分かります。 でも 1つだけ確実なこと があります:
✅ 右Min は 必ず +5 以下 になる。
(+5 ちょうどか、それより小さい値。+5 を超えることは絶対にない)
なぜ「+5 以下」なのか?
Min は 子ノードの中から最小値を選ぶルール。右Min には 子の1つに +5 があるので:
- 「?」が +5 より大きいとき(例: ?=+14):Min は +5 と +14 のうち 小さい方の +5 を選ぶ → 右Min = +5
- 「?」が +5 ちょうどのとき:Min は +5 を選ぶ → 右Min = +5
- 「?」が +5 より小さいとき(例: ?=-50):Min は もっと小さい ?の方 を選ぶ → 右Min = -50
どのケースでも 「+5 を超えない」 ことは共通。これが「右Min ≤ +5」(+5 以下)の意味です。
日常的な言葉で言うと
数学記号を使わない言い方:
「もし右Minを計算したとしても、絶対に +5 より大きくなることはない。同じか、もっと小さくなる」
= 「右Min の最高記録は +5」
= 「右Min の天井(上限)は +5」
これがα-β枝刈りで重要な性質。「+5 を超えないこと」さえ分かれば、Max(左の +8)と比べて結論が出るので、「?」の具体値は知らなくていい。
🤔 でも、それでもMaxの結論は変わらない?
ここがα-β枝刈りの巧妙なところ。「右Minが +5 より小さくなるなら、その先がさらに不利になる」 → でも左にすでに +8 があるので、Maxは関係なく左を選ぶ:
| 右Minの値(仮) | Max(+8, 右Min) | Maxが選ぶのは? |
|---|---|---|
| +5(?が +14 のとき) | max(+8, +5) | +8 ← 左 |
| 0(?が 0 のとき) | max(+8, 0) | +8 ← 左 |
| -50(?が -50 のとき) | max(+8, -50) | +8 ← 左 |
| -100(?が -100 のとき) | max(+8, -100) | +8 ← 左 |
右Minがどんな値でも、+5以下 → +8 より小さい。Maxは左の +8 を選ぶ。 だから「?」を読まなくても結論は変わらない。
🎯 Maxはどう判断するか?
最後に根(Max)の判断。Maxは 「大きい方」 を選びます:
根Max の計算:
Max(+8, 右Min)
右Min は 最大でも +5(?がどんな値でも)。
Max は +8 と「+5以下の何か」を比べる。
+8 の方が必ず大きい。
⇒ 根Max = +8 で確定!「?」が +14 でも +100 でも結果は同じ。
💡 だから「?」を読まなくていい
「?」がいくらだろうと、自分(Max)は左の枝(+8)を選ぶ。「?」を計算する時間は完全に無駄。 これがα-β枝刈りが 「読まずに打ち切れる」 理由です。
🤯 直感的なたとえ:人間の意思決定
たとえ話:レストラン選びの判断
- レストランA:友達の評価は「ラーメンが 4点、餃子が 6点」 → 友達が「あの店でいうとラーメンの4点が一番低い、これより悪いものは食べたくないから4点扱い」と言う
- レストランB:「カレーが 2点、?はまだ食べてない」 → カレーが2点なので、最悪 2点が確定(?がいくら高くても、友達は2点と言う)
- あなた(Max)は 「より良い体験」を選びたい:4点 vs ≤2点 → 迷わず A を選ぶ
- 「Bの?を食べに行く必要はない」 — 友達は最悪のカレー(2点)を勧めてくるので、もう試さなくていい
α-β枝刈りはこの「残りを試さなくても結論が決まる」状況を、ゲーム木の中で自動検出する技術。 将棋AIは 毎秒数百万回 このような判断をしている、というわけです。
💡 1行まとめ: 「?」がどんな値でも、Min は「+5 と ?の小さい方」を選ぶので、右Min は +5 以下(上限が +5、もっと小さくなることもある)。 Maxは +8(左)と「+5以下の何か」(右)を比べて 必ず +8 を選ぶ。 だから「?」を計算する必要がない=枝刈りで時間節約できる。
3.3.4 「α」と「β」の意味
| 記号 | 意味 | 常識的に言うと |
|---|---|---|
| α(アルファ) | 「Max側が今のところ保証できる最低評価値」 | 「少なくとも +α は取れる」 |
| β(ベータ) | 「Min側が許容できる最高評価値」 | 「相手は +β より良くはさせない」 |
| α ≥ β になったら | 「もう読んでも結果が逆転しない」 | 枝刈り発動! |
3.3.5 α-β枝刈りの威力
α-β の効果は 探索する局面数の劇的削減:
| 深さ | Minimax(枝刈りなし) | α-β(理想的な順序) | 削減率 |
|---|---|---|---|
| 5手 | 33億 | 約 18万 | 約 18,000倍速 |
| 10手 | 10¹³ | 約 10⁶〜10⁷ | 約 百万倍速 |
| 20手 | 事実上不可能 | 数億局面で可能 | — |
理論的には α-β は Minimax の $\sqrt{N}$ 倍 速くなります(N は同じ深さで Minimax が読む局面数)。 つまり同じ時間で 2倍の深さ を読める。これだけで「3手読み→6手読み」のような 桁違いの強さ差が生まれます。
3.3.6 α-β がさらに強くなる「補助技」
実際のやねうら王には、α-β を もっと効率化する補助技 が大量に実装されています:
- Move Ordering(手の並べ替え):「良さそうな手」から先に読むと枝刈りが効きやすい。駒を取る手・王手などを優先
- Iterative Deepening(反復深化):「3手→5手→7手」と段階的に深く。前の結果で Move Ordering を最適化
- Transposition Table(置換表):同じ局面が出てきたら計算結果をキャッシュ。手順違いで合流する将棋では特に重要
- Null Move Pruning:「相手にパスさせても自分が良い」なら、その先は深く読まなくていい
- LMR (Late Move Reductions):「Move Ordering で後ろの方の手」は浅く読む
- Futility Pruning:「明らかにダメな枝」を早めに打ち切る
- Aspiration Window:「次の探索の α・β を予測値の周囲に絞る」
これら全部の詳細は やねうら王 詳細ページ で解説しています。
3.4 探索 vs 評価関数の分業がもたらしたもの
この明確な分業構造(探索 vs 評価)が、将棋AI界の 3つのブレイクスルー をもたらしました:
- ① 開発者の分業:探索アルゴリズムの専門家と、機械学習の専門家が独立して進化を続けられる
- ② エンジン間の競争:「やねうら王 + 水匠」「やねうら王 + Háo」「やねうら王 + tanuki-」のように、同じ探索部の上で評価関数だけ競う環境
- ③ クロスパラダイム蒸留:dlshogi(深いCNN+MCTS)の知識を NNUE(浅いMLP+α-β)の評価関数に取り込む知識蒸留が可能。NNUEの序盤評価ページ参照
💡 1行まとめ: 探索部(やねうら王)と評価関数(水匠/Háo/dlshogi)は別の関数で完全に分離している。 α-β枝刈りは「相手が選ばない枝の先は読まない」というシンプルな発想だが、これが 「数千倍の高速化」 をもたらし、CPU での秒間数百万局面評価を実現する核心技術。
4. これまでの章の概念が、将棋AIで全部実装されている
ここがこの章のメインテーブル。抽象的だった機械学習の概念が、すべて実在する将棋AIに実装されていることが見えます。
| サイトで学んだ概念 | 将棋AIでの実例 | 関連章 |
|---|---|---|
| 機械学習 | Bonanzaメソッド(2005) | 第1章 |
| 教師あり学習 | NNUE評価関数の学習(局面 → 評価値) | 第1章 |
| 強化学習 | AlphaZero、dlshogi の自己対局 | 第2章 補足 |
| ディープラーニング | NNUE(浅い)+ dlshogi(深い) | 第2章 |
| MLP(多層パーセプトロン) | NNUEの内部構造(HalfKP_256x2-32-32) | 第3章 |
| 活性化関数(ClippedReLU) | NNUEで標準採用、整数演算で高速化 | 第3章 |
| 全結合層 | NNUEの各層 | 第3章 |
| 損失関数 | NNUE学習のMSE + 交差エントロピー混合 | 第4章 |
| 勾配降下法 / Adam | nnue-pytorchでの学習 | 第4章 |
| 誤差逆伝播法 | nnue-pytorchの内部 | 第4章 |
| 量子化 | NNUEのint8/int16化(CPU高速化のため) | 第4章 |
| CNN(畳み込み層) | dlshogi の評価ネット第1層〜 | 第5章 |
| ResNet(残差接続) | dlshogi の中間層(10〜40ブロック) | 第5章 |
| α-β探索 | やねうら王の探索部 | 古典AI |
| MCTS(モンテカルロ木探索) | dlshogi、AlphaZeroの探索部 | 第5章 |
| Transformer / Attention | (将来候補) NNUE評価関数の改良として研究中 | 第5章 |
| 生成AI(LLM) | (将来候補) 棋譜の自然言語解説 | 第6章 |
💡 感じてほしいこと: サイトの第1章〜第6章で学んだ概念が、すべて将棋AIに実装されている。 抽象的だった機械学習論が、レーティング・勝率という具体的な指標として観測できる。 これが将棋AIを「機械学習を学ぶ最高の実例」と呼ぶ理由です。
5. NNUE と dlshogi — 教師あり vs 強化学習の対比
📊 補足図解:第2章「直交する2軸」を将棋AIに当てはめると(クリックで展開)
第2章 補足「直交する2軸」 で見たマトリックスを、将棋AIに当てはめると:
| 古典機械学習 | ディープラーニング | |
|---|---|---|
| 教師あり | Bonanza(KPP特徴) | NNUE(やねうら王 + 水匠) |
| 強化学習 | — | AlphaZero / dlshogi |
| 教師なし | — | (将棋AIでは主流ではない) |
将棋AIでは 教師ありとと強化学習の両方が現役で使われています。LLM(ChatGPT)が3象限を旅するのとは違い、将棋AIは「2つの象限が並走している」構図。
5.1 💭 「教師あり」と「強化学習」を将棋で具体的に — どう違う?
表だけ見ても「教師ありBonanza・NNUE と、強化学習AlphaZero/dlshogi の違いって何?」とピンとこないですよね。 「何を教える?どうやって学ぶ?」 を具体的に並べて見ます。
📊 一言で違いをまとめると
📘 教師あり学習:「お手本」を真似する学び方
学校の ドリル学習 をイメージしてください:
例:算数の問題集
- 問題:「3 + 5 = ?」
- 正解(教師ラベル):「8」
- 生徒(モデル):問題を見て答えを予測 → 「7」と答えたら間違い、「8」と答えたら正解
- 間違えるたびに「正解はこっち」と教えられる → 徐々に正解できるようになる
将棋AIでの「教師あり学習」
- Bonanza(2005年):プロ棋士の 5万局以上の棋譜 を集めて「プロが指した手が正解」として学習
- 具体的には「この局面でプロが▲7六歩を指した」 → モデルも ▲7六歩 を高く評価するように重みを調整
- 使う特徴量:KPP(玉×駒×駒 の3駒関係)
- NNUE(2018年〜、水匠/Háo/氷彗):すでに強いAI同士の 自己対局棋譜(数億局面) を生成して、その「探索評価値」と「最終勝敗」を正解として学習
- 具体的には:強いAIが「この局面は +120」と評価 → NNUEも +120 と予測するように重みを調整
- 「お手本(既存の強いAI)に追いつくこと」が目標
💡 教師ありの特徴:
・「正解(ラベル)」が必要。プロ棋譜や既存AIの評価値を使う
・お手本を超えるのは難しい(蒸留の限界)
・学習が速い・効率的
・現在最強の NNUE系の評価関数(水匠/Háo/氷彗) はみんなこれ
🎮 強化学習:「対局して勝敗から学ぶ」学び方
スポーツの自主練習 をイメージしてください:
例:野球のバッティング練習
- 誰も「こうやって打て」と教えない
- とりあえずスイングしてみる → 当たれば気持ちいい(報酬+1)、空振れば悔しい(報酬-1)
- 「当たった時のフォーム」を覚えていく
- 何千スイングもやるうちに、どんどん打てるようになる
将棋AIでの「強化学習」
- AlphaZero(2017年、DeepMind):
- ルールだけ教えて、棋譜は一切見せない
- 自分のコピーと 何百万局も対局(自己対局)
- 勝った側の手 → 「これは良い手だった」と学習
- 負けた側の手 → 「これは悪い手だった」と学習
- これを繰り返すと 誰の助けもなしに世界最強になる
- dlshogi(山岡忠夫氏):AlphaZero と同じ手法で将棋専用に開発した日本版
- 「人類の棋譜知識を使わない」設計
- 初期はランダムな手しか指せないが、自己対局を繰り返して強くなる
💡 強化学習の特徴:
・「正解」は不要。勝ち負けという「最終結果」だけが教師
・人間の棋譜が一切要らない(人類の知識を超える可能性)
・学習に莫大な計算資源が必要(GPU で何日も)
・代表例:AlphaZero / dlshogi / AobaZero
⚖️ 2つを並べて比較
| 教師あり学習 (Bonanza / NNUE) | 強化学習 (AlphaZero / dlshogi) | |
|---|---|---|
| 使うデータ | 📚 プロ棋譜 or 強いAIの棋譜 | 🎮 自分同士の対局(自己対局) |
| 教師信号 | 「正解の手」「正解の評価値」 | 「最終の勝敗(+1/0/-1)」だけ |
| 人間の知識 | 必須(棋譜の収集が必要) | 不要(ルールだけでよい) |
| 学習にかかる時間 | 数時間〜数日(CPU/GPU) | 数日〜数週間(大量GPU) |
| 強さの上限 | お手本に近い強さ(理論上) | 無限(自己改善) |
| 計算量 | 少なめ(CPUで実用化可能) | 非常に多い(GPU必須) |
| 代表ソフト | 水匠、Háo、tanuki-、氷彗 | dlshogi、ふかうら王、AobaZero |
🔄 「両方が並走している」とはどういうこと?
将棋AI界の面白いところは、2つの学習スタイルが同時に世界トップを争っている こと:
- 2024年・2025年の世界選手権で連覇したのは NNUE型「お前、CSA会員にならねーか?」(教師あり学習)
- 一方で dlshogi系(強化学習)も僅差で追従、終盤の精度では上回ることも
- NNUEがdlshogiの棋譜を「知識蒸留」で取り込むという、両者を組み合わせた手法も2025年に実現
画像認識や自然言語の世界では 「強化学習 → 教師あり微調整」 のように一方向の流れが多いのですが、将棋AIでは 「両方が永続的に共存」 しているのが珍しい構図です。
💡 1行まとめ: 教師あり = お手本を真似(Bonanza/NNUE)。強化学習 = 対局して勝敗から学ぶ(AlphaZero/dlshogi)。 両者は哲学が違うが、将棋AI界では 並走して相互に切磋琢磨 している。
6. なぜ将棋AIが機械学習を学ぶ最高の実例なのか
📚 詳細:将棋AIが最高の実例である6つの理由(クリックで展開)
📊 結果が定量化される
棋力は レーティング という単一の数値で観測可能。 「この改良で棋力 +R30」のように、客観的に比較できる。
🌐 すべて公開
やねうら王、dlshogi、水匠(過去版)、nnue-pytorch、互角局面集… ソースコードもデータも全公開。 自分で動かして検証できる。
🎯 多様な技術が共存
α-β、MCTS、CNN、MLP、教師あり、強化学習、量子化、差分更新… 機械学習のあらゆる技術が1つのドメインに集約されている。
🔄 進化の歴史が見える
1974年の誕生から2024年までの50年史が、AIの進化と完全パラレル。 機械学習の歴史を将棋AIで追体験できる。
👥 個人でも参加可能
巨大企業しか作れないLLMと違い、将棋AIは 個人開発者の改良で世界記録を更新できる余地がある。
🇯🇵 日本発の貢献
NNUEは 将棋発の発明で、チェス(Stockfish)に輸出された。 日本の研究者が世界標準技術を作った稀有な例。
まとめ
- 将棋AIの50年史は、機械学習の歴史と完全に並走している
- 第1世代(人力)→ 第2世代(Bonanzaメソッド)→ 第3世代(NNUE/dlshogi)
- 現代は NNUE型(CPU・浅い)と DL型(GPU・深い)の2大潮流
- これまでサイトで学んだ概念は すべて将棋AIで実装され、闘い、進化している
- NNUE は 教師あり×DL、dlshogi は 強化学習×DL。第2章の直交軸で位置づけ可能
- 将棋AIは 機械学習を学ぶ最高の実例集。レーティングという定量指標、全公開のエコシステム、個人参加可能性、すべてが揃っている
もっと深く知るには
将棋AIの歴史と未来を、開発者本人(やねうらお氏・たややん氏)の言葉で詳しく学びたい人は次の章へ:
実際に動かしてみたい人は、別途まっしー版のセットアップガイドがあります:やねうら王 V9.00 + Háo(macOS Apple Silicon対応)。