1996年、Pentium 上の現代チェスエンジンは Kasparov に勝てたのか?
IBM は数百万ドルをかけてディープブルーを作り、1996 年に Kasparov を破った。30 年後、200 MHz の Pentium Pro で現代の Stockfish を動かすと、棋力は約 3300 Elo になり、ほぼ確実に勝てる。
日本語
コピー

1996年2月10日、コンピュータプログラム(IBM の Deep Blue)がチェスの対局で当時の世界王者 Garry Kasparov を初めて破った。Deep Blue はその試合に最終的には敗れたが、1年後の再戦では3.5対2.5で勝利し、雪辱を果たした。
そのために IBM は数百万ドルを投じ、この目的のためだけの専用コンピュータを作り上げた。Deep Blue 本体(勝利したアップグレード版)は約120 MHz で動作する30基の P2SC プロセッサで駆動され、さらに重要なことに、指し手生成や局面評価といったチェス専用の演算を実行する480基のカスタム VLSI チェスコプロセッサを搭載していた。完成当時、Deep Blue は世界第259位のスーパーコンピュータであり、毎秒2億以上の局面を解析できた。
だが、Kasparov を倒すのに本当に Deep Blue が必要だったのだろうか。1996年当時の市販デスクトップ機で、もっと賢いチェスエンジンを動かすだけでは足りなかったのだろうか。
答えは、Deep Blue を作らなくても Kasparov には楽に勝てる、というものだ。市販の普通のハードウェアだけで済み、(ほぼ間違いなく)しかも勝率は低くない。そう言い切れるのは、この文を書いている今まさに、私の隣に200 MHz の Intel Pentium Pro(発売はちょうど31年前、1995年11月1日)が置かれ、64 MB のメモリを積んでカスタム移植版のStockfishを動かしているからだ。クラシカルタイムコントロールでの推定 Elo は3300 ± 87——人間の棋士はおろか、Elo が2800をわずかに下回る Kasparov をも大きく上回る。しかも話はこれで終わらない。Realtek RTL8139C のネットワークカードでこのマシンをインターネットにつないであるので、原文のページで対局できる!
Pentium Pro のディスプレイ、リアルタイムの映像(VGA テキスト画面で、毎秒1回更新される)
え、何だって?!どうやったんだ??
棋力を上げる道は 3 つある。より多くの手を読むか、より良い手を読むか、手をより良く読むかだ。人間が後者2つに頼っているのはよく知られている。チェスのグランドマスターがクラシカル対局で読む手の数はアマチュアと大差ないが、最も重要な手だけを選んで読み、しかもより深く読む。Stockfishのようなチェスエンジンは、人間の頭脳ではなくシリコンの上で動くため、前者の道では我々を完全に圧倒し、毎秒数百万の局面を解析する。一方、現代のエンジンはマイクロ最適化の余地がそれほど残っておらず、与えられた CPU で毎秒扱える局面数をそう簡単には増やせない。だからチェス AI の進歩の多くも、人間が強くなる道筋に沿っている。より良い手の選択方法と、より良い局面の分析方法を探すことだ。
チェスの強さは Elo レーティングで測る。200ポイントの差は、強い側が4局中3局を勝つことを意味する。差が広がればこの比率で積み上がり、400ポイントで期待スコア90%、1000ポイントで99.7%になる。1996年の一般的なハードウェアで動かせる最強のチェスエンジンのレーティングはおよそ2300、Deep Blue は2700だった。それに対して現代の Stockfish は3700に近い。
そこで疑問が湧く。現代のチェスエンジンの強さのうち、どれだけが現代のデスクトップ機の異常な速さによるもので、どれだけが単に我々がチェスエンジンをうまく書けるようになっただけなのか。答えは、Elo の向上の大部分(合計+1335のうち+720)は、より良いハードウェアではなく、より良いプログラミングによるものだ。
これを確かめるために2つの実験をした。1つ目はCraftyを使う。1996年当時の競争力のあるエンジンで、ソースコードは今では公開されている。私の Pentium Pro 上で、1996年にコンパイルされた Crafty 11.13 は、1手1秒で Elo 1999 ± 90、1手10秒で2383 ± 77だった。現代のハードウェア(Ryzen 7)に移すと、同じ1手1秒でこのエンジンの Elo は2614 ± 97まで大きく跳ね上がる。だがこのエンジンに、より良いチェスエンジンの設計に関する我々の知識を少しずつ注ぎ込んでいく——fail-soft、LMR、correction history といった現代の探索アルゴリズム、より良い静止探索の手法、そしてニューラルネットワーク評価(NNUE)を加える——と、Pentium Pro 上で1手1秒なら2718 ± 34、1手10秒なら2974 ± 74まで上がる。
2つ目の実験はさらに踏み込む。Crafty を作り替えるのではなく、今日最強のチェスエンジンである Stockfish をそのまま1996年のハードウェアで動かし、どうなるか見るのだ。これにはいくらか作業が要る。主にコードを書き換えて32 ビット演算を使わせ(PPro は32 ビットマシンだ)、64 MB を超えるメモリを使わせないようにする。この素朴な移植版は1手1秒で Elo およそ2496 ± 64(1手10秒で2940 ± 76)だった。だがまだできる!現代の Stockfish は現代の CPU 向けに設計されている。アルゴリズムに一連の調整を施し、Pentium 向けにチューニングすると、1手1秒で2846 ± 35、1手10秒で3109 ± 79、1手30秒で3180 ± 80まで上がる。
要約すると、上の内容を互いに 100 局対局させればよい。実際にやってみたところ、1996 年の Pentium Pro 上で動く現代のチェスエンジンは、現代のハードウェアで動く 1996 年当時の Crafty に対して、78 勝 17 引き分け 5 敗だった。
以下、詳細を述べる。
技術的詳細:ハードウェアと OS
正直に言って、ハードウェアについて語ることはほとんどない。中古のデスクトップを買った(商品ページには「レトロ」と書かれていた。自分も年を取ったものだ)。構成は当時の標準的な部品ばかりだ。200 MHz の Intel Pentium Pro を Intel VS440FX マザーボードに載せ、64 MB、66 MHz の SIMM メモリを積んでいる。OS は1.44 MB の3.5 インチフロッピーから起動し、Realtek RTL8139C 経由でネットワークにつながる。1 MB の Trio64V+ グラフィックスカードも入っていて、VGA でモニタに出力し、入力は PS/2 キーボードから取る。ただしこの2つはほとんど使わず、シリアルポート経由で手元の現代のデスクトップと通信させている。
このハードウェアの価格にピンとこない読者もいるだろう。200 MHz の Pentium Pro は 1995 年 11 月の発売時に 1,325 ドルで、16 MB の SIMM 4 本だけでさらに 2,000 ドルほどかかった。周辺機器を合わせれば、当時は4,000〜5,000 ドルといったところだ。つまり良いワークステーションではあるが、決してスーパーコンピュータではない。とはいえハードウェアの値落ちの速さと性能の指数関数的な向上を考えれば、同じマシンは1997年、つまり第2回の対局が開かれた頃には1,000 ドル程度にしかならなかったはずだ(何しろほぼあらゆる面で優れた Pentium MMX が当時400 ドルだったのだから、誰が Pentium Pro を買うだろうか)。
チェスエンジンとインターネットの間をつなぐインターフェースとして、私は「OS」を自分で書いた。唯一の仕事はエンジンを動かし、そのままネットワークカードにつなぐことだ。(本稿で「私が書いた」とあるのは、実際には「LLM に書かせた」という意味である。ここのコードは Fable 5.1、Opus 5.5、GPT-6 を組み合わせて実装した。ただしこの記事自体は人間が書いている。)設計目標は可能な限りコンパクトにすることだった。この OS(実のところ hypervisor に近い何かだ)は起動可能なフロッピー1枚に収まり、唯一の仕事は Pentium Pro を32 ビット保護モードで起動し、ネットワークカードを初期化し、その後の指示を待つことだ。あとは任意の「ユーザー空間」のクライアントプログラムをメモリに送り込めば、それが起動してプログラムを実行する。私が書いたチェスプログラムは自前実装の HTTP サーバを立ち上げ、局面(FEN 文字列)と最大実行時間を伴う HTTP リクエストを待つ。リクエストを受け取るたびに、時間切れまでエンジンを走らせて応答を返す。
技術的詳細:ソフトウェア
前述のとおり、私(繰り返すが、言語モデル)は実際に2つのエンジンを改修した。強いほうは Stockfish をベースに、30年前のプロセッサ向けに実行効率を最適化したものだ。クラシカルタイムコントロールでは推定レーティング約 33001で、Kasparov の2800を大きく上回る。したがって Stockfish-1996 は10局中9局ほどのスコアで勝つと予想すべきだろう。やや弱いほうは Crafty 11.13 のソースコードを出発点に、この30年で学んだより良いチェスエンジンの書き方に関する知見をすべて注ぎ込み、現代の水準まで引き上げた。
現代の技法で Crafty 11.13(1996)を強化する
私(正確には私の LLM)が最初に手を入れたエンジンは、1996年公開の Crafty 11.13 だ。このエンジンには LLM が最も手間をかけており、この30年で蓄積されたアイデアを1つずつ移植し直した。以下ではレーティングの伸びがどこから来たのかを、1手1秒と1手10秒の2条件で評価して分解する。
1秒と10秒で伸び幅が食い違うことがある。その一部は明らかにノイズだ——数百局しか回しておらず、誤差範囲が相対的に大きい——が、かなりのシグナルも含まれている。1996年のコンピュータはずっと遅く、1手1秒では探索深さがごく浅いため、評価関数がどれだけ正確かよりもどれだけ速く動くかのほうが重要になる。探索深さが増せば、戦術的なミスをしなくなった時点で、局面評価のほうがはるかに重要になる。
| 1 秒/手 | 10 秒/手 | 変更内容 |
|---|---|---|
| 1999 ± 90 | 2383 ± 77 | Crafty 11.13。1996年12月公開、出荷時のまま。最初に書かれた alpha-beta エンジンで、独自の評価関数を備え、探索アルゴリズムは90年代の標準的な手法。 |
| 2063 ± 73 (+64 ± 116) | 2323 ± 75 (−60 ± 107) | 最初の改善は主にマイクロ最適化。64K エントリの 2 つの参照テーブルをbsf/bsr命令の呼び出しに置き換え、スライディングピースの利き判定も旧来の rotated-bitboard 関数呼び出しから移行した。合わせてエンジンは15%速くなったが、アルゴリズムは変わっていない。 |
| 2022 ± 73 (−41 ± 103) | 2420 ± 76 (+97 ± 106) | 次の改善は探索アルゴリズムが対象。fail-soft(切り捨てずに実際のスコアを返す)、futility pruning、late-move pruning(葉ノード付近で静かな手を省く)、late move reduction(後ろの手を1層浅く探索する)、そして counter-move と history table による手の並べ替えを導入した。 |
| 2224 ± 72 (+202 ± 103) | 2520 ± 74 (+100 ± 106) | 続いて探索と評価関数を調整。まず SPSA で数千局の自己対局に基づいて探索定数をすべて調整した。次に評価項ごとに中盤と終盤の値を設定し(残り駒数で混合)、評価の重みをすべて再フィッティングした(Texel tuning)。最後に評価関数へ mobility 項を加え、駒が利いている安全なマスを評価するようにした。 |
| 2192 ± 72 (−32 ± 102) | 2565 ± 74 (+45 ± 104) | ここから評価関数を書き換え、ニューラルネットワーク評価に置き換えた。小さなネットワークを1,100万の自己対局局面で訓練し、ラベルはそれ自身の探索が与えた。この段階自体の効果は小さいが、次の段階への布石になった…… |
| 2420 ± 82 (+228 ± 109) | 2712 ± 74 (+147 ± 104) | 自己対局の代わりに強い教師を使い、出来たばかりの NNUE を再生成した。原理的にはこのエンジン自身を教師にできたが、実時間を節約するため Stockfish を使った。これで実時間が約 4,000 コア年(1996年当時なら十分に可能だった——あいにく手元にはデスクトップが1台しかなく、無理だが)から、現代のデスクトップで現代のエンジンを数日動かす程度に短縮された。 |
| 2630 ± 82 (+210 ± 116) | 2810 ± 75 (+98 ± 105) | 評価関数がずっと強くなり、探索はそれを本気で頼れるようになった。reverse futility pruning を加え、評価がすでに勝勢を示していれば早期に打ち切る。評価器の性能改善も行った(評価キャッシュを追加し、アキュムレータを null move と共有)。これによりネットワークを6倍に広げられた。Crafty にあった一部の特殊処理など、コードの整理も進めた——評価関数が弱い頃には有効だったが、NNUE があればもう要らない。 |
| 2720 ± 82 (+90 ± 116) | 2938 ± 74 (+128 ± 105) | 新しい評価関数に合わせ、パラメータを再び SPSA で調整した。ついでにコードのバグもいくつか直した。おかしな話だが。最後に NNUE へ手を加えた。盤上の駒数に応じて使い分ける複数の出力ヘッドを追加し、隠れユニットを増やし、自己対局を増やして訓練データを倍にした。 |
Stockfish 17 を Pentium Pro に移植する
2つ目のエンジンは、前述のとおり逆の結果になった。私が(正確には私の LLM が)Stockfish を 1996 年のハードウェアで動くように移植し、探索深さが浅い環境に合わせてパラメータを調整した。したがって、ここでの伸びは小さめだ。掘り起こせる大きなアルゴリズム上の優位がもう残っていないからである。
| 1 秒/手 | 10 秒/手 | 変化 |
|---|---|---|
| 2496 ± 64 | 2940 ± 76 | Stockfish 17 をこのマシンに押し込む。最初の素朴な移植では、Stockfish 17 を 1996 年のマシン向けに書き換えた。シングルコア、SIMD なし、64 ビットレジスタなし、C++ 標準ライブラリなし。マルチスレッド、エンドゲームテーブルベース、71 MB の NNUE を外し、より小さなものに置き換えた。ビットボードは 32 ビット整数のペアに書き換え、小さな NNUE の評価は純粋な整数演算で行う。 |
| 2590 ± 67 (+94 ± 93) | 2961 ± 74 (+21 ± 106) | アキュムレータの更新を高速化。2つ目の修正で NNUE の動作が改善し、更新の追随が速まり、評価器の性能が上がった。 |
| 2752 ± 68 (+162 ± 95) | 3006 ± 74 (+45 ± 105) | 評価関数を軽くし、PeSTO を併用し、コンパイラフラグを変更。続いて NNUE を再度いじり、規模を縮めてチューニングし、Pentium Pro 上での動作を速めて評価時間を3分の1に短縮した。いくつかの最適化も加わり、このラウンドは 1 秒/手で最も効果が出た——生の速度が最もものを言う場面である——10 秒/手では効果がずっと小さかった。 |
| 2780 ± 67 (+28 ± 95) | 3070 ± 72 (+64 ± 103) | NNUE を on-policy で微調整。基本的に前の作業の繰り返しだが、Stockfish 向けに、Stockfish 自身で数百万の局面を採点し、NNUE の重みを導出し直した。 |
| 2784 ± 65 (+4 ± 93) | 3070 ± 72 (+0 ± 101) | SPSA で探索を再チューニングし、NNUE の改善を踏まえて PeSTO を削除。オリジナルの Stockfish は毎秒数百万ノードを前提としているため、遅い CPU では SPSA でもう一ラウンド再調整する必要がある。これらの変更により、PeSTO のラウンドも不要になった。 |
| 2819 ± 65 (+35 ± 92) | 3074 ± 72 (+4 ± 101) | 修正履歴を追加し、他のパラメータと NNUE を同時にチューニング。次のラウンドでは Stockfish の非ポーン修正履歴を復活させ、パラメータを(同じく SPSA で)同時最適化し、NNUE を再フィッティングした。 |
| 2846 ± 35 (+27 ± 74) | 3109 ± 79 (+35 ± 107) | 最後のステップはコードを変えず、コンパイラを替え、リンク時最適化をいくつか加え、32 バイトのコードアラインメントを施しただけ。 |
では、これで Kasparov に勝てるのか?
可能性は圧倒的に高いと思うが、実際のところはおそらく予想より厄介だ。というのも、この記事全体を通して少し目くらましをしている。問題は Elo レーティングが相対的なものであることで、私はずっと自分のエンジンの Elo を、Computer Chess Rating Lists(CCRL)にある強さが既知の各種 Stockfish エンジンと比較してきた。だが人間はエンジンとあまり対局しないので、FIDE の Elo と CCRL のスコアの間には小さなずれがあるかもしれない。チェスプレイヤーの FIDE Elo がオンラインの Elo にそのまま換算できないのと同じだ。幸い、私のエンジンは Elo 3200–3300 で動いており、Kasparov のレーティングは 2800 を少し下回る。この余裕なら、ずれを吸収するには十分だろう。
とはいえ、もし 2700+ のスーパー GM をご存じで、1996 年のハードウェアで動く 2026 年のチェスエンジンに勝ってみたいという方がいれば、喜んで挑戦を受けて立つ!
結論
人間が何かを初めてやるとき、効率的にできることはほとんどない。規模を広げるだけで明らかに実現できる道が見えれば、私たちはそれに従う。そして後になって、目の前の問題をよりよく理解する時間ができて初めて、もっと賢いやり方で、はるかに高い効率で同じ成果に到達できたはずだと気づく。
これをやったのは主に遊びのためだ。「手持ちのハードウェアで Kasparov に勝てるか」は面白い問いに聞こえたから。ただ、「AI」のアルゴリズムの進歩の速さについて、少しだけ洞察を与えられたらとも思っている。1997 年のチェスエンジンはすでにかなり進んでいた。なにしろ Alan Turing が半世紀近く前に最初のチェスプログラムの作成を手伝っている。だから当時は、残されたアイデアはもう少ないのかもしれない、と思えても無理はなかった。後から見れば、それが間違いだと分かるのは簡単だ。
そこから浮かぶ問いがある。現代の「AI」——つまり言語モデル——には、まだどれだけのものが取り残されているのか。今後数年のうちにソフトウェアから得られる進歩は、ハードウェアの規模拡大による進歩を上回るのか。このおもちゃの実験では結論は出せないのは明らかだが、ある種の未来を示してはいる。(LLM——「AI」——を使って、こうした風変わりな研究の問いへの答えを速めることについてのメタな教訓も、たぶんここにはある。)
(あと、ええと、数週間後にはこのマシンでチェスエンジンを動かさなくなる。その Pentium Pro で何か面白いプロジェクトができるよ、というアイデアがあれば、ぜひ教えてほしい!)
Footnotes
-
クラシカルタイムコントロールの対局を1台で走らせたのでは、この数字を出すにはまったく足りない。だから短いタイムコントロールから外挿した。1手30秒で測った値は 3180 ± 80 で、1秒から10秒、10秒から30秒と、時間を3倍にするごとに Elo が +70 伸びた。クラシカルタイムコントロールなら1手あたりおよそ6分(相手の手番中の思考時間を含む)になるので、これに当てはめると Elo は 3350 になるはずだ。伸びは頭打ちになることを考え、控えめに見て Elo 3300 とした。 ↩