第7章

将棋AIで全部確認 — 学んだ概念の集大成

これまで学んできた 機械学習・ニューラルネット・学習アルゴリズム・CNN・Transformer・生成AI。 これらすべてが将棋AIで 実装され、闘い、進化している 様を、本章で総まとめします。 将棋AIは、抽象的な機械学習概念を具体的に観察できる 最高の実例集です。

この章の全体像

1

3世代の進化

将棋AIの50年史は、機械学習・DLの進化と完全にパラレル。 人力時代 → Bonanza革命 → ディープラーニング2系統。

2

2大潮流が共存

NNUE型(CPU + α-β + 浅いMLP)と DL型(GPU + MCTS + 深いCNN)が並走。

3

すべての概念が実装されている

第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つの工夫など。 「銀×金 の位置関係は表現できる?」「誰が特徴を作った?」「自分玉と相手玉の関係は?」などの設計トレードオフも詳述。

🧠 浅いMLP ⚡ CPU高速 🔧 差分更新
🔎 詳細

dlshogi — 深いCNN評価関数

山岡忠夫氏が開発する AlphaZero型。9×9×100テンソルを深いCNN+ResNetで処理し、Policy/Value 2ヘッドでMCTSと連携。 強化学習による自己対局で人間データなしに強くなる仕組み、NNUEとの対比など徹底解説。

🧠 深いCNN 🎯 MCTS 🔄 強化学習
🔎 詳細

やねうら王 — 探索基盤

日本の将棋AIの 探索エンジンのデファクトスタンダード。α-β木探索、LMR、Null Move Pruning、置換表、並列化。 「探索 vs 評価関数」分業エコシステムの土台を作ったOSS。NNUE評価関数と組み合わせて世界トップクラスへ。

🌲 α-β探索 ⚙️ 高速化技 🔗 分業基盤

💡 3つの関係を1行で「やねうら王(探索の達人)+ NNUE評価関数(評価の達人)」がNNUE型エンジンの実体。 対するdlshogiは深いCNN+MCTSという別パラダイム。両者は哲学が真逆だが補完的に共存している。

3. 探索部 vs 評価関数 — 役割分担と α-β探索

将棋AIを理解するうえで 最も基本的で重要な区別 が「探索部」と「評価関数」の役割分担です。 この章では 疑似コード で両者を分解し、特に α-β探索 を深く掘り下げます。

3.1 探索部と評価関数 — 役割の違い

将棋AI = 探索部 + 評価関数の2層構造 🌳 探索部(やねうら王) 「先を読む達人」 役割: • ある局面から派生する 全ての指し手を展開 • 何手も先まで「読み」を進める • 最善手の系列を見つける • α-β枝刈りで無駄を省く 入力/出力: 入力:局面 出力:最善手 + 評価値 人間でいうと「読み」の能力 📊 評価関数(水匠/dlshogi等) 「形勢判断の達人」 役割: • ある局面を見て 「どちらがどれくらい有利か」 を数値で返す • 先を読まない(瞬時の判断) • HalfKP + 浅いMLPなど 入力/出力: 入力:局面 出力:評価値(例:+120) 人間でいうと「大局観」の能力

人間の将棋にたとえる

人間の能力将棋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つのこと

💭 「葉ノード」「読みの末端」って何? — 具体的なイメージで理解する

「葉ノード」「読みの末端」という言葉、いきなり出てくるとピンとこないですよね。木のたとえで1つずつほぐしてみます。

🌳 まず「探索木」というイメージ

将棋AIが 「3手先まで読む」 という時、頭の中で展開している構造を 木(ツリー) として描けます:

「3手先まで読む」探索木の例 現在 局面 ↑ 根(root)= スタート地点 depth = 3 ▲7六 ▲2六 ▲5六 ↑ 1手目 depth = 2 △8四 △3四 △8四 △6四 △5四 △3四 ↑ 2手目 depth = 1 +5 +8 +3 -2 +7 +1 +12 +4 -5 +9 +2 +6 ↑ 葉ノード depth = 0 📌 各ノードの役割: 🔴 根(root):今の局面。ここから探索スタート 🟡 内部ノード:1手・2手目の局面。指せる手の数だけ枝分かれ 🟢 葉(leaf):これ以上読まない=末端。ここで初めて評価関数を呼ぶ → 数値で評価
🎯 「葉ノード」「末端」とは何か
🤔 なぜ「葉ノード」だけで評価関数を呼ぶのか

内部ノード(途中の節)で評価関数を呼ばない理由は、「評価関数は局面を見ただけで判断するから精度が低い」 ため。

例で考える

🔢 「葉ノードの数」が秒間数百万になる理由

たとえば 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 α-β枝刈り — 「読まなくていい枝」を見抜く

α-β法の核心は:「相手が絶対に選ばない手の先は、これ以上読んでも意味がない」 と気づいて打ち切ること。

α-β枝刈り:相手が選ばない手の先は読まない Max Min Min +8 +12 +8 +5 ✂️ 枝刈り! 読まない ≤+5 💡 何が起きているか: ① 左の枝を読んだ結果、自分は「+8」を保証できることが分かった(α = 8) ② 右の枝の最初の手で「+5」が出た → 相手はこの枝で必ず +5 以下にできる ③ もう右の枝は 最良でも +5。左の +8 より悪い → これ以上読む意味がない! ④ 残りの「?」は読まずに打ち切り。これが α-β 枝刈り

💭「?」が +14 になる可能性は? — もっと丁寧に理解する

ここがα-β枝刈りの最も大事なポイント。「?」が+14だったらどうなる?大逆転しない? という疑問を、ステップごとに丁寧に解きほぐします。

📚 まず思い出す:Max と Min の役割
ノード誰の番?選ぶ基準
Max(赤、根) 自分の番 子ノードの値のうち 最大(最も自分に有利) を選ぶ
Min(青、相手の番) 相手の番 子ノードの値のうち 最小(最も自分に不利=相手に有利) を選ぶ
🎮 インタラクティブデモ:?の値を変えて結果を確認!

「?」のところに どんな値(-100〜+100)を入れても、最終結果は変わらない ことを実際に動かして確認できます:

インタラクティブ・デモ
「?」の値を動かしても結果は変わらないことを体感
スライダーで「?」を変えてみる Max =? Min =+8 Min =? +8 +12 +5 +14 ↑ スライダーで動かせる 📊 計算過程: 左Min = min(+8, +12) = +8 右Min = min(+5, +14) = +5 Max(根) = max(+8, +5) = +8 ← 最終的に左の枝を選ぶ ✓ 「?」がどんな値でも結果は変わらない!
-100(最悪) 0 +100(最高)
🤔 「?」が +14 だったら? — 計算を追ってみる

上のスライダーで 「?= +14」 にしてみると:

右Min の計算:
  Min(+5, +14) = ?

  Min は「最小値を選ぶ」のがルール。
  +5 と +14 のうち、小さいのは +5。
  ⇒ 右Min = +5

つまり「?= +14」と分かっても、右Min の値は +5 のまま変わらない。
なぜなら相手(Min)は +14 なんて自分に不利な選択肢は 絶対に選ばないから。

「?」が どんな値であっても、Min は「小さい方」を選ぶので:

「?」の値Min(+5, ?)右Minの値
+14min(+5, +14)+5
+100min(+5, +100)+5
+5min(+5, +5)+5
0min(+5, 0)0(+5より小さい!)
-50min(+5, -50)-50(さらに小さい!)
✅ 大事な性質:右Min は「+5 以下」になる(上限のみ保証)

上の表をよく見ると、右Min は 場合によって違う値 になることが分かります。 でも 1つだけ確実なこと があります:

✅ 右Min は 必ず +5 以下 になる。
(+5 ちょうどか、それより小さい値。+5 を超えることは絶対にない)

なぜ「+5 以下」なのか?

Min は 子ノードの中から最小値を選ぶルール。右Min には 子の1つに +5 があるので:

どのケースでも 「+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)を選ぶ。「?」を計算する時間は完全に無駄。 これがα-β枝刈りが 「読まずに打ち切れる」 理由です。

🤯 直感的なたとえ:人間の意思決定

たとえ話:レストラン選びの判断

α-β枝刈りはこの「残りを試さなくても結論が決まる」状況を、ゲーム木の中で自動検出する技術。 将棋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 α-β がさらに強くなる「補助技」

実際のやねうら王には、α-β を もっと効率化する補助技 が大量に実装されています:

これら全部の詳細は やねうら王 詳細ページ で解説しています。

3.4 探索 vs 評価関数の分業がもたらしたもの

この明確な分業構造(探索 vs 評価)が、将棋AI界の 3つのブレイクスルー をもたらしました:

💡 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 の違いって何?」とピンとこないですよね。 「何を教える?どうやって学ぶ?」 を具体的に並べて見ます。

📊 一言で違いをまとめると

教師あり vs 強化学習 — 「何を見て学ぶか」が違う 📘 教師あり学習 「お手本を真似する」 何を見て学ぶ? 「正解付きのデータ」 例:プロ棋士の棋譜(10万局) 例:強いAI同士の棋譜(数億局面) 例:「この局面は +120」というラベル 目標: 「お手本通りに予測できる」 → プロが指した手と同じ手を選べる → AIの評価値と同じ値を出せる 代表例: Bonanza(2005、プロ棋譜で学習) NNUE(強いAIの棋譜で学習) 🎮 強化学習 「対局して勝敗から学ぶ」 何を見て学ぶ? 「自分が対局した結果」 例:AI同士の自己対局(何百万局) 例:勝ち=+1、負け=-1 だけが教師 例:プロ棋譜は 一切使わない 目標: 「勝てる手を選べる」 → 勝った側の手は「良い手」 → 負けた側の手は「悪い手」 代表例: AlphaZero(2017、自己対局のみ) dlshogi(日本のAlphaZero型)

📘 教師あり学習:「お手本」を真似する学び方

学校の ドリル学習 をイメージしてください:

例:算数の問題集

将棋AIでの「教師あり学習」

💡 教師ありの特徴: ・「正解(ラベル)」が必要。プロ棋譜や既存AIの評価値を使う
・お手本を超えるのは難しい(蒸留の限界)
・学習が速い・効率的
・現在最強の NNUE系の評価関数(水匠/Háo/氷彗) はみんなこれ

🎮 強化学習:「対局して勝敗から学ぶ」学び方

スポーツの自主練習 をイメージしてください:

例:野球のバッティング練習

将棋AIでの「強化学習」

💡 強化学習の特徴: ・「正解」は不要。勝ち負けという「最終結果」だけが教師
・人間の棋譜が一切要らない(人類の知識を超える可能性)
・学習に莫大な計算資源が必要(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つの学習スタイルが同時に世界トップを争っている こと:

画像認識や自然言語の世界では 「強化学習 → 教師あり微調整」 のように一方向の流れが多いのですが、将棋AIでは 「両方が永続的に共存」 しているのが珍しい構図です。

💡 1行まとめ教師あり = お手本を真似(Bonanza/NNUE)強化学習 = 対局して勝敗から学ぶ(AlphaZero/dlshogi)。 両者は哲学が違うが、将棋AI界では 並走して相互に切磋琢磨 している。

6. なぜ将棋AIが機械学習を学ぶ最高の実例なのか

📚 詳細:将棋AIが最高の実例である6つの理由(クリックで展開)
理由 1

📊 結果が定量化される

棋力は レーティング という単一の数値で観測可能。 「この改良で棋力 +R30」のように、客観的に比較できる。

理由 2

🌐 すべて公開

やねうら王、dlshogi、水匠(過去版)、nnue-pytorch、互角局面集… ソースコードもデータも全公開。 自分で動かして検証できる。

理由 3

🎯 多様な技術が共存

α-β、MCTS、CNN、MLP、教師あり、強化学習、量子化、差分更新… 機械学習のあらゆる技術が1つのドメインに集約されている。

理由 4

🔄 進化の歴史が見える

1974年の誕生から2024年までの50年史が、AIの進化と完全パラレル。 機械学習の歴史を将棋AIで追体験できる。

理由 5

👥 個人でも参加可能

巨大企業しか作れないLLMと違い、将棋AIは 個人開発者の改良で世界記録を更新できる余地がある。

理由 6

🇯🇵 日本発の貢献

NNUEは 将棋発の発明で、チェス(Stockfish)に輸出された。 日本の研究者が世界標準技術を作った稀有な例。

まとめ

  1. 将棋AIの50年史は、機械学習の歴史と完全に並走している
  2. 第1世代(人力)→ 第2世代(Bonanzaメソッド)→ 第3世代(NNUE/dlshogi)
  3. 現代は NNUE型(CPU・浅い)DL型(GPU・深い)の2大潮流
  4. これまでサイトで学んだ概念は すべて将棋AIで実装され、闘い、進化している
  5. NNUE は 教師あり×DL、dlshogi は 強化学習×DL。第2章の直交軸で位置づけ可能
  6. 将棋AIは 機械学習を学ぶ最高の実例集。レーティングという定量指標、全公開のエコシステム、個人参加可能性、すべてが揃っている

もっと深く知るには

将棋AIの歴史と未来を、開発者本人(やねうらお氏・たややん氏)の言葉で詳しく学びたい人は次の章へ:

→ 第8章「CEDEC2024講演で深堀り」へ進む

実際に動かしてみたい人は、別途まっしー版のセットアップガイドがあります:やねうら王 V9.00 + Háo(macOS Apple Silicon対応)。