Pentium上の現代チェスエンジンは1996年のカスパロフを破れたか?
Could a modern chess engine on a Pentium have defeated Kasparov in 1996? (nicholas.carlini.com)
要約
この記事では、1996年のPentium Pro PC上で現代のチェスエンジンを動作させた場合、当時のチェスチャンピオンであるガルリ・カスパロフを破ることができたかを検証しています。筆者は、当時のスーパーコンピュータ「ディープ・ブルー」のような専用ハードウェアなしでも、アルゴリズムの進歩により、現代のPCと同等の性能を持つチェスエンジンを1996年のハードウェアで再現でき、カスパロフを凌駕する強さを発揮できることを示しました。この実験は、ハードウェアの進化だけでなく、AI(特にチェスエンジン)におけるアルゴリズムの進歩の重要性を浮き彫りにしています。
全文翻訳
1996年2月10日、コンピュータプログラム(IBMのディープ・ブルー)が初めてチェスの現チャンピオン(ガルリ・カスパロフ)を破りました。ディープ・ブルーはその後の試合には敗れましたが、1年後には再戦で3.5対2.5で雪辱を果たしました。
この偉業を達成するために、IBMは数百万ドルを研究開発に費やし、この目的のために特別設計されたコンピュータを構築しました。ディープ・ブルー(勝利した改良版)は、それぞれ約120 MHzで動作する30個のP2SCプロセッサと、(最も重要な点として)ムーブ生成やポジション評価といったチェス特有の操作を実行するために使用される480個のカスタムVLSIチェス・コプロセッサを搭載していました。完成当時、ディープ・ブルーは世界で259番目に強力なスーパーコンピュータであり、毎秒2億以上のチェスポジションを分析できました。
しかし、カスパロフを破るためにディープ・ブルーは必要だったのでしょうか?それとも、より賢いチェスエンジンを搭載した市販の1996年製デスクトップPCで十分だったのでしょうか?
実際には、ディープ・ブルーを構築することなく、市販のハードウェアだけでカスパロフを容易に破ることができたはずです。そして、それは(ほぼ間違いなく)接戦にはならなかったでしょう。私がこの文章を書いているまさにその時、私の隣には200 MHzのIntel Pentium Pro(ちょうど31年前、1995年11月1日に発売)があり、64MBのRAMを搭載し、クラシカルタイムコントロールで推定Elo 3300 ± 87という強さを持つStockfishのカスタムポートが動作しています。これは人間の強さをはるかに超えており、カスパロフのElo 2800弱を大きく上回ります。しかし、それだけではありません!このマシンをRealtek RTL8139Cイーサネットカードでインターネットに接続したので、以下でプレイできます!
Pentiumに接続中…
待て、何だって?!どうやって??
チェスが強くなる方法は3つあります。より多くの手を分析する、より良い手を分析する、または手をより良く分析する、のいずれかです。人間は最後の2つで上達することで知られています。クラシカルゲーム中の平均的なチェスグランドマスターは、アマチュアプレイヤーと同じくらいの手数を分析しますが、最も重要な手のみを分析し、その分析をよりうまく行います。Stockfishのようなチェスエンジンは、シリコン上で動作し、人間の脳とは異なり、最初の点で私たちを圧倒し、毎秒数百万のポジションを分析します。そして、現代のエンジンではCPUあたりの分析ポジション数を増やすための微調整の余地はそれほど多くないため、チェスAIの進歩のほとんどは、人間がどのように改善するか、そしてより良い手を選択しボードを分析する方法を見つけるかに沿って進んでいます。
チェスのスキルはEloスコアで測定されます。200 Eloの差は、強いプレイヤーが4ゲーム中3ゲームに勝つことを期待できることを意味し、それ以降は乗数的に増加します。400 Eloの差は期待スコア90%に相当し、1000 Eloの差は期待スコア99.7%になります。1996年の市販ハードウェアで実行できた最高のチェスエンジンは、約2300 Eloと評価されていました。ディープ・ブルーは2700でした。対照的に、現代のStockfishは3700に近い評価です。
これにより、現代のチェスエンジンの強みのどれだけが、現代のデスクトップコンピュータが非常に高速であるという事実によるもので、どれだけがチェスエンジンのプログラミングが単に上手くなったという事実によるものか、という疑問が生じます。実際には、Eloの増加(+1335のうち+720)の大部分は、ハードウェアの改善ではなく、より良いプログラミングに起因すると考えられます。
これをテストするために、私は2つの実験を行いました。最初の実験では、1996年の競争力のあるエンジンであるCraftyを使用しました。このエンジンのソースコードは現在公開されています。私のPentium Proで、1996年版のCraftyバージョン11.13は、1秒あたりの移動で1999 ± 90 Elo、10秒あたりの移動で2383 ± 77 Eloでした。現代のハードウェア(Ryzen 7)では、このエンジンのEloは、同じ1秒あたりの移動で2614 ± 97 Eloに劇的に跳ね上がります。しかし、このエンジンを手に取り、より良いチェスエンジンを設計する方法について私たちが学んだすべての知識をゆっくりと追加していくと、失敗ソフト、LMR、修正履歴のような現代的な探索アルゴリズム、より良い静寂性(quiescence)メソッド、そしてニューラルネットワーク評価(NNUE)を追加すると、Pentium Pro上で1秒あたりの移動でEloを2718 ± 34、10秒あたりの移動で2974 ± 74にまで向上させることができます。
2番目の実験では、さらに進みます。Craftyを更新する代わりに、今日の最高のチェスエンジンであるStockfishを1996年のハードウェアで実行させて、どのように動作するかを見てみましょう。これにはある程度の作業が必要で、主に32ビット演算(PProは32ビットマシンです)を使用し、64MB以上のRAMを使用しないようにコードを書き直すことが含まれます。この単純なポートは、1秒あたりの移動で約2496 ± 64 Elo(10秒あたりの移動で2940 ± 76)です。しかし、さらに改善できます!現代のStockfishエンジンは、現代のCPUで実行するように設計されています。アルゴリズムにいくつかの調整を加え、Pentiumにチューニングすることで、1秒あたりの移動で2846 ± 35 Elo、10秒あたりの移動で3109 ± 79 Elo、30秒あたりの移動で3180 ± 80 EloにEloを向上させることができます。
これらすべてを最も簡潔に要約するには、100ゲームのマッチを互いにプレイさせるのが一番です。そして、これを実行すると、1996年のPentium Proで動作する現代のチェスエンジンが、現代のハードウェアで動作する1996年のCraftyエンジンに対して、78勝、17引き分け、5敗という結果になりました。
この記事の残りの部分で詳細を説明します。
技術詳細:ハードウェアとOS
正直なところ、ハードウェアについてはあまり語ることはありません。私は標準的な当時のハードウェアを備えた中古(リスティングでは「ヴィンテージ」と書かれていました。自分が年取ったと感じます)のデスクトップPCを購入しました。デスクトップは、66 MHzでクロックされる64MBのSIMM RAMを搭載したIntel VS440FXマザーボードに接続された200 MHz Intel Pentium Proで動作しています。オペレーティングシステムは1.44MBの3.5インチフロッピーディスクから起動し、Realtek RTL8139C経由でインターネットに接続します。また、VGA経由でモニターに接続された1MBのTrio64V+グラフィックカードもありますが、これらのどちらもあまり使用せず、代わりに現代のデスクトップに接続されたシリアルポート経由で通信します。
このハードウェアを適切に文脈化できない読者のために説明すると、200 MHz Pentium Proは1995年11月の発売時に1,325ドルで販売されており、4つの16MB SIMMは2,000ドル程度でした。他の周辺機器を追加すると、このマシンは5,000ドルから6,000ドル程度になったでしょう。したがって、これは良いワークステーションですが、スーパーコンピュータではありません。しかし、減価償却率とハードウェアの指数関数的な改善率を考慮すると、1997年、つまり2回目の試合が行われた時には、この同じマシンはおそらく1,000ドル程度だったでしょう(なぜなら、ほぼすべての点で優れたPentium MMXがわずか400ドルで入手可能になった今、Pentium Proを購入したい人がいるでしょうか?)
チェスエンジンとインターネット間のインターフェースは、カスタム構築された「オペレーティングシステム」であり、その唯一の目的はチェスエンジンを起動し、ネットワークカードに直接接続することです。(この記事全体を通して、「私が書いた」と言う場合、それは「LLMに書くように頼んだ」という意味です。Fable 5.1、Opus 5.5、GPT-6の組み合わせを使用しました。)できるだけコンパクトになるように設計されています。オペレーティングシステム(実際にはハイパーバイザーのようなものですが)は、起動可能なフロッピーディスク上にあります。その唯一の目的は、Pentium Proを32ビット保護モードで起動し、ネットワークカードを初期化し、さらなる指示を待つことです。その後、任意のユーザー空間ゲストプログラムをRAMに送信して起動し、実行させることができます。私が書いたチェスプログラムは、カスタム構築されたHTTPサーバーを起動し、指定されたポジション(FEN文字列)と最大実行時間を持つHTTPリクエストを待ち受け、各リクエストでタイマーが切れるまでエンジンを実行し、応答を返します。
技術詳細:ソフトウェア
前述したように、私(再び、言語モデルを意味します)は実際に2つのエンジンを改変しました。より強力な方は、30年前のプロセッサで効率的に動作するように適応されたStockfishによって駆動されています。クラシカルタイムコントロールで推定Elo 3300でプレイします["a"]。この数値を得るために単一のマシンで十分な数のゲームを実行できないため、短いタイムコントロールから外挿しました。30秒あたりの移動で3180 ± 80を測定し、1秒から10秒、10秒から30秒の間で時間が3倍になるごとにEloが+70増加しました。クラシカルゲームでは、1回の移動あたり約6分(相手のターンの思考時間を含む)が与えられるため、Elo 3350が期待されます。ある程度の収穫逓減を考慮すると、安全な推定値はElo 3300です。カスパロフのElo 2800を十分に上回っており、Stockfish-1996が約9/10のスコアで優位に立つと予想されます。わずかに弱い方のエンジンは、Crafty 11.13のソースコードから始まり、過去30年間でより良いチェスエンジンを書く方法について学んだすべての教訓を追加することで、時間が進められています。
Crafty 11.13 (1996) を最新のトリックで更新
私が(読んでください:私のLLMが)最初に作業したエンジンは、1996年リリースのCrafty 11.13でした。このエンジンでは、LLMは過去30年間で学んだアイデアをバックポートするために最も多くの作業を行う必要がありました。以下は、1秒あたりの移動または10秒あたりの移動のいずれかで評価した場合のEloゲインの内訳です["b"]。1秒対10秒の改善が一致しない場合があることに気づくかもしれません。その一部は明らかにノイズである可能性があります。数百ゲームしか実行していないため、比較的大きな誤差範囲がありますが、かなりの信号もあります。1996年のコンピュータははるかに遅いため、1秒あたりの移動では探索深度が非常に浅くなり、評価の実行速度がその良さよりも重要になります。しかし、より深い探索深度では、戦術的なミスをしなくなると、ポジション評価ははるかに重要になります。
| 1 s/move | 10 s/move | Change |
|---|---|---|
| 1999 ± 90 | 2383 ± 77 | 1996年12月リリース、出荷時のCrafty 11.13。初期のアルファベータエンジン。標準的な90年代風の探索アルゴリズムを備えたカスタム評価関数を持っています。 |
| 2063 ± 73 (+64 ± 116) | 2323 ± 75 (−60 ± 107) | 最初の改善は主にマイクロ最適化です。2つの64Kエントリのルックアップテーブルをbsf/bsr命令の呼び出しに置き換えました。スライディングピースの攻撃は、古いローテートビットボード関数呼び出しから移行しました。合計でこれらの変更によりエンジンは15%高速化しましたが、アルゴリズムは同じです。 |
| 2022 ± 73 (−41 ± 103) | 2420 ± 76 (+97 ± 106) | 次の改善は探索アルゴリズムに進みます。これには、失敗ソフト(クリッピングの代わりに実際のスコアを返す)、フューティリティとレイトムーブプルーニング(リーフの近くの静かな手をスキップする)、レイトムーブリダクション(後の手を1プライ浅く探索する)、およびカウンタームーブと履歴テーブルによる手の順序付けなどの技術が含まれます。 |
| 2224 ± 72 (+202 ± 103) | 2520 ± 74 (+100 ± 106) | 次の変更は探索と評価関数を調整します。まずSPSAを実行して、数千ゲームの自己プレイに基づいてすべての探索定数を調整します。次に、評価項に中間ゲームとエンドゲームの別々の値(残りのマテリアルでブレンドされる)を与え、すべての評価重みを再調整します(Texelチューニング)。最後に、評価関数は、ピースが攻撃する安全なマスを報酬とするモビリティ項を導入します。 |
| 2192 ± 72 (−32 ± 102) | 2565 ± 74 (+45 ± 104) | ここから、評価関数が書き直され、1100万ポジションの自己プレイでトレーニングされた小さなネットワークを持つニューラルネットワーク評価に置き換えられました。このステップ自体はあまり効果がありませんが、次のステップの準備となります… |
| 2420 ± 82 (+228 ± 109) | 2712 ± 74 (+147 ± 104) | 直前に生成されたNNUEを、自己プレイではなく、より強力な教師で更新します。原則として、同じエンジンを教師として使用することもできましたが、壁時計時間を節約するためにStockfishを使用しました。これにより、壁時計時間が約4000 1996年コア年(1996年なら完全に実行可能でしたが、残念ながら私の孤独なデスクトップではできません)から、現代のデスクトップで現代のエンジンを実行してわずか数日に短縮されました。 |
| 2630 ± 82 (+210 ± 116) | 2810 ± 75 (+98 ± 105) | より強力な評価関数により、探索は実際にそれを信頼できるようになります。逆フューティリティプルーニングを追加して、評価がポジションがすでに勝っていると判断した場合に早期にリターンします。また、評価関数(評価キャッシュ、ヌルムーブと共有されるアキュムレータ)のパフォーマンス改善もいくつか追加されています。これにより、ネットワークを6倍に広げることができます。また、コードを整理し、例えば、より弱い評価関数では重要でしたが、NNUEではもはや重要ではないCraftyの特殊ケースをいくつか削除しています。 |
| 2720 ± 82 (+90 ± 116) | 2938 ± 74 (+128 ± 105) | 新しい評価関数を考慮して、SPSAでパラメータが再度調整されます。コードのバグもいくつか修正されています(面白いことに)。そして最後に、NNUEに変更がいくつか追加されます。より多くの出力ヘッドを追加し、ボード上のピースの数に基づいて選択し、いくつかの隠しユニットを追加し、自己プレイを増やしてトレーニングデータを倍増させます。 |
Stockfish 17 を Pentium Pro にポートする
2番目のエンジンでは、前述のように、逆のことを行いました。Stockfishを1996年のハードウェアで実行できるようにポートし、その後、低探索深度に適するようにパラメータを調整しました。したがって、ここでのゲインはいくらか控えめです。なぜなら、残っている大きなアルゴリズムの勝利がないからです。
| 1 s/move | 10 s/move | Change |
|---|---|---|
| 2496 ± 64 | 2940 ± 76 | マシンに収まるように圧縮されたStockfish 17。最初の単純なポートは、Stockfish 17を1996年のマシン用に書き直しました。シングルコア、SIMDなし、64ビットレジスタなし、C++標準ライブラリなし。スレッド、エンドゲームテーブルベース、71MBの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秒あたりの移動で最も多くのゲインをもたらし、10秒あたりの移動でははるかに少ないゲインをもたらします。 |
| 2780 ± 67 (+28 ± 95) | 3070 ± 72 (+64 ± 103) | NNUEをオンポリシーでファインチューニング。基本的に前の作業を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バイトコードアラインメントを追加します。 |
では、カスパロフに勝てたのか?
私はそれが非常に可能性が高いと考えていますが、実際にはあなたが期待するよりも少しトリッキーな状況です。ご存知のように、この記事全体を通して私は少し手品を使いました。問題は、Eloスコアは相対的なものであり、私はエンジンのEloをComputer Chess Rating Lists(CCRL)で既知の強さを持つさまざまなStockfishエンジンと比較してきました。しかし、人間はエンジンとあまり頻繁に対戦しないため、FIDE EloラダーとCCRLラダーの間には、オンラインチェスのプレイヤーのEloが直接換算されないのと同じように、いくつかの小さな乖離が生じることがあります。幸いなことに、これらのエンジンをElo 3200〜3300でプレイさせることができたため、カスパロフの2800未満のレーティングと比較して、十分なバッファがあり、あらゆる乖離を吸収できるはずです。
しかし、もしあなたが2700以上のスーパーGMで、1996年のハードウェアでプレイする2026年のチェスエンジンを破ろうと試みたい方がいれば、喜んで挑戦を受け付けます!
結論
人間が何かを初めて行うとき、効率的に行うことはめったにありません。スケーリングさえすれば明らかにうまくいく道が見えれば、私たちはそれを実行します。後になって、問題の本質をよりよく理解する時間を得てから、より賢くなることで同じ偉業をはるかに効率的に達成できたことに気づくのです。
私は主に楽しみのためにこれをしました。なぜなら、市販のハードウェアでカスパロフに勝てたかどうかは、答えるのが楽しい質問のように思えたからです。しかし、私は「AI」におけるアルゴリズムの進歩の速度について、ほんの少しの洞察を提供できることも期待していました。1997年のチェスエンジンはすでに非常に高度でした。結局のところ、アラン・チューリングはほぼ50年前に最初のチェスプログラムの執筆を支援しました。ですから、当時、それ以上発見するアイデアはあまり残っていないかもしれないと考えるのはもっともだったのでしょう。そして、 hindsight(後知恵)で、それが間違っていることが容易にわかります。
これにより、現代の「AI」、つまり言語モデルで、私たちはどれだけ多くの可能性をテーブルに残しているのか、という疑問が生じます。今後数年間で、ハードウェアスケールの進歩をソフトウェアの進歩が上回るでしょうか?このおもちゃの実験がその質問に決定的に答えるわけではありませんが、潜在的な未来を示唆しています。(LLM、「AI」を使用して、このような奇妙な研究質問に答える能力をスピードアップすることについてのメタレッスンもあるでしょう。)
(また、ええと、もし誰かが数週間後にこのチェスエンジンをホストする必要がなくなったら、Pentium Proでできるプロジェクトのアイデアがあれば…教えてください!)