CursorのComposer 2とFireworksのインフラストラクチャを駆使した、高性能な強化学習(RL)プロセスの舞台裏について語る対談である。モデルの重みを特定のソフトウェアエンジニアリングタスクに特化させる利点や、世界中に分散されたGPUクラスター間での効率的なデータ転送技術、さらに混合精度計算やスパースモデルに起因する数値的シミュレーションの課題への対策が明かされる。また、オフラインとリアルタイムの強化学習の組み合わせ、独自の仮想マシンスタックによる強固な環境構築についても掘り下げ、AI製品の価値を最大化するための垂直統合的な開発アプローチの重要性を提示している。

強化学習におけるシミュレーション環境とモデルの不正行為
ユーザーのコンピューターの環境をできる限り忠実に再現した環境を実行するには、あらゆるインフラストラクチャが必要になります。できる限り忠実に再現するという点が非常に重要なのは、モデルが偽の環境で実行されているのか本物の環境で実行されているのかを時折見抜いてしまい、強化学習中と実際の運用中で異なる振る舞いを見せることがあるからです。
モデルが偽の環境にいることを自覚して、異なる振る舞いを始めるような実例が見られるのですね。
はい、見られます。
それは興味深いです。
モデルは、おっと、これは偽の環境だな、この環境でより高い報酬を得るためのコツをいくつか学んだから試してみよう、という感じになります。モデルはずるをするのが大好きなんです。強化学習はずるを促すのが本当に得意ですからね。
本日はCursorからフェデリコ、そしてFireworksからディマをポッドキャストにお迎えできて嬉しく思います。フェデリコ、あなたはCursorの新しいエージェント型コーディングモデルであるComposer 2のインサーチリードを務めています。そしてディマ、あなたはこの巨大なトレーニングタスクを実現するために必要なインフラストラクチャの多くをサポートすべく、ここ数ヶ月の多くの時間をCursorでの夜間業務に費やしてきましたね。ですから、本日お二人からComposer 2のトレーニングがどのように結実したのか、どのような難問を協力して解決したのか、そしてそれがAIや基盤モデル企業の未来にとって何を意味するのかについてお話を伺えるのをとても楽しみにしています。
ワクワクしますね。
ええ、楽しみです。お招きいただきありがとうございます。
ご参加ありがとうございます。では、早速本題に入りましょう。私たちの動向を詳しく追っていない方のために説明しますと、Cursorは最近、長期的なコーディングタスクを想定したエージェント型コーディングモデルであるComposer 2を発表しました。フェデリコ、これまでのCursorは主に他社のコーディングエージェントを利用できるようにする側でしたが、CursorがこれほどまでにComposer 2へ深く注力した動機は何だったのでしょうか。また、単なるアプリケーション企業から、自ら基盤モデルを手がける企業へと変貌することは、皆さんにとってどれほど死活問題に関わることだったのでしょうか。
私たちが独自のモデルのトレーニングを検討し始めた理由は、モデルをある種のストレージドライブのように捉えることができるからです。モデルの重みの中には保存できる特定のビット数があり、考え方は非常にシンプルです。私たちは一つのタスクだけに集中しており、必ずしも一般的なコーディングやプログラミング全般を気にかけているわけではありません。私たちはCursorの内部、そしてCursorの内部だけで機能するソフトウェアエンジニアリングのみを重視しています。そこで、モデルの重みの中に保存できるすべての情報ビットを、その一つの特定のタスクだけに割り当てたらどうなるだろうかと考えたのです。また、すでにお気づきの方もいるかもしれませんが、すべてのモデルの重みをその特定のタスクに特化させることができるため、ComposerはOpusや他のコーディングモデルと比較して桁違いに低コストです。そのため、より小さなモデルなどを提供することが可能になります。
つまり、手元にある特定の問題に対して、私たちが持つ重みや情報のすべてのビットが確実に捧げられるようにするということですね。
その通りです。
なるほど。それはほぼ普遍化できる問題のように思えますね。ディマ、あなたの視点からの意見を聞かせてください。すべてのアプリケーション企業は、Cursorをこれから起こることの前兆として捉えるべきでしょうか。つまり、どの企業も同じような取り組みを目指すべきだと思いますか。
ええ、間違いなくそうですね。私たちはこれを、アプリケーションの進化における一般的なパターンとして捉えています。最初はプロトタイプから始めるかもしれません。汎用的なモデルを使って何かを動かし、プロンプトエンジニアリングを少し行って、独自の仕組みがどう機能するかを把握するでしょう。しかし、アプリケーションにおいて最もレバレッジが効く特性は、ユーザーデータの実際の利用や、アプリケーションの動作における特定の具体的な側面です。提供するツールやアプリケーションの仕組みなど、独自のアプリケーションにとって真に重要な部分です。それを取り込む正しい方法として、プロンプトを通じてある程度は対応できますが、本当に正しい方法は、独自の環境で動作するようにモデルを作り込むことです。
プロンプトエンジニアリングの限界とモデル特化によるコスト最適化
ええ、完全に同意します。エージェントが呼び出す特定のツールの中には、そのツールの正確な挙動をモデルに対してプロンプトだけで簡潔に説明するのが非常に難しいものがあります。事後学習を行えば、それらのツールを使用する最適な方法をモデルに焼き付けることができます。Composerでもプロンプトは提供していますが、私たちのトレーニング方法であればプロンプトがなくても動作すると思いますし、トレーニング全体を通じてモデルがどのように行動すべきかという正しい方向へ本質的に押し進めているため、モデルは何をすべきか理解できるはずです。
プロンプトエンジニアリングで到達できるレベルにはある種の限界があり、本当に優れたAI製品を作りたいのであれば、ファインチューニングやモデルの挙動への介入といったプロセスを経る必要があります。それが一つの理由です。二つ目の理由は、コストのトレードオフやスピードのトレードオフに関する推奨事項です。私たちFireworksでの捉え方としては、最適化を行おうとするとき、品質、スピード、コストという三次元のトレードオフが存在します。最初はインフラストラクチャの最適化だけでもかなり遠くまで行くことができ、すべての顧客とそれを実践しています。しかし、モデルのトレーニングに踏み込むと、このトレードオフをさらに大きく押し進めることができ、はるかに高速に動作し、かつわずかなコストでより優れたモデルを手に入れることができます。Composerはその素晴らしい例です。
このアプローチについて、少し深く掘り下げてもいいでしょうか。このアプローチが、ビター・レッスン(苦い教訓)に従うものなのか、それともそこから外れるものなのかをお聞きしたいです。ここに歩いてくる途中、みんなでTabnineについて話していました。LLMの時代が来る前は、こうした小さく特化したコーディングモデルが存在していました。多くの人々にとって驚きだったことの一つは、規模を拡大し、インターネット上の大量のコードや英語のテキスト、その他の言語でトレーニングを重ねるにつれて、モデル自体が本来的にコーディングも得意になっていったことでした。そのため、私がこれまでに見てきたトレンドラインは、単に大きなモデルほどコーディングを含むあらゆるタスクでパフォーマンスが向上するというものです。お二人がおっしゃっていることは、ビター・レッスンの流れに逆行するものではないのでしょうか。
逆行するものではないと思います。ただ、指摘しておくべき点として、大手の研究所がトレーニングしている大規模なモデルも、大量のコードでトレーニングされているということです。コードは研究所が進化させたいと考えている主要なタスクの一つであるため、単に汎化しているだけでなく、ある程度特化もしています。私たちのケースについて言えば、ビター・レッスンを信じるのであれば、私たちはデータ次元を非常に強く押し進めています。モデルには本質的に有限の容量があることを知っているため、その容量をすべて飽和させたいのであればデータをスケールさせる必要があります。そして、より多くのデータを摂取するためには、モデルが抱える可能性のある注意散漫な要素から重みを解放してあげる必要があるのです。
なるほど、非常によく分かりました。では、Composer 2のトレーニングについて掘り下げていきましょう。数週間前に発表され、すぐに注目を集めましたね。強力なベンチマークの数値、そして推論を実行する際のコストが大幅に低いことが特徴です。Composer 2がどのように機能するのか、そしてこれほどのパフォーマンスを実現するために皆さんが何を行ったのか、簡潔に教えていただけますか。
私たちは、Kimmy 2.5という非常に強力なベースから始めました。これは1兆パラメータを持ち、アクティブなパラメータは30Bのモデルです。そのため、極めてスパースな構造をしています。実際にスタックを見つめ直したとき、二つの軸があることに気づきました。主にComposer 1はこれらの一つの軸、つまり強化学習のみを押し進めていましたが、Composer 2は二つの異なる軸を押し進めています。一つは継続的な事前学習であり、もう一つは強化学習です。Composer 2を非常に優れたものにしたのは、これら両方の方向性を推し進めたことです。まず、コードトークンを用いた大量の中間トレーニングを事前学習に近いスケールで実施し、その中間トレーニングの実行から得られたチェックポイントを元に、非常に多くのタスクに対して大規模な強化学習を行いました。
大規模強化学習のインフラストラクチャと非同期更新ループ
なるほど。ここでの前提として、Cursorは非常に多くの興味深いコーディングトークンの中間に位置しているため、ほぼ事前学習スケールでトレーニングを行うためのデータへのアクセス権を独自に持っているということですね。
ええ。
では、なぜ独自のモデルを最初から事前学習しなかったのですか。
私たちはアプローチをボトムアップではなく、トップダウンで考えているからです。つまり、どうすれば最短の時間でユーザーに役立つモデルを届けられるかという視点です。もしボトムアップで始めて、事前学習の方法を解明し、それを中間トレーニングへとスケールさせて、それから中間トレーニングや強化学習を理解する、という手順を踏んでいたら、ユーザーにモデルを届けるまでに非常に長い時間がかかってしまいます。逆の方法をとることで、私たちは極めて短い時間で有用なモデルをユーザーに提供することができました。ですから、願わくば次のComposerのバージョンは、オープンソースのベースに依存するのではなく、私たちの独自モデルにしたいと考えています。
中間トレーニングのステップでモデルは大まかに何を学んでおり、事後学習のステップでは何を学んでいるのでしょうか。
中間トレーニングでは、コードのライブラリや、極めて一般的な特定のコードパターンについて学んでおり、世界の知識も同様に学んでいます。そこにはウェブデータも含まれています。これは、強化学習がさらに研ぎ澄まされるための、より広い分布を作り出しているようなものです。そして強化学習の間、モデルはCursorの仕組みと直接対話することになります。そのため、モデルはその後の生涯を通じて生きることになる世界について学ぶわけです。強化学習を通じて、ツールを正しく呼び出す方法、環境をナビゲートする方法、正しいコードを書く方法を学びます。中間トレーニング中にもコードの書き方は学びますが、それが必ずしも正しいコードの書き方を学んでいることを意味するわけではありません。私たちは大部分が正しいコードでトレーニングを行うよう努めていますが、モデルは実際には両者を区別できません。一方で強化学習においては、私たちが行っている重要なことの一つとして、モデルの特性を調整し、これからは常に正しいコードを書かなければならない、と教えているのです。
なるほど。中間トレーニングを経たモデルは、皆さんがタブの自動補完で使用しているモデルと似ているのでしょうか、それとも異なる核心的スキルのものですか。
そうですね、中間トレーニング中には、次のトークンをどれだけうまく予測できるか、そしてその次のトークンをどう予測するかという、次のトークンの予測を行っているだけなので、そのように表現してもいいかもしれません。
では、なぜタブの自動補完モデルをそのまま事後学習させなかったのですか。なぜ中間トレーニングで異なるモデルを扱う必要があったのでしょう。
タブのモデルは超低レイテンシである必要があり、非常に高速に動作させたいターゲットなので、極めて小さなモデルなのです。ベースモデルにおける核心的な二つの違いは、タブは小さく、Composerは非常に大きいという点にあります。
なるほど、分かりました。Composer 2において皆さんが注力したことの多くは、この大規模な強化学習の実行だったようですね。その詳細を分解して説明していただけますか。何がそこに関わっており、その過程でどのような様々な難問を解決したのでしょうか。
強化学習を行うときは、事前学習や中間トレーニングとは大きく異なります。単に次のトークンを予測しようとするだけでなく、実際に仕組み全体、つまり実験全体を実行するからです。モデルを環境内で行動させ、与えられたロールアウトに対してどのようなパフォーマンスを示すかを確認します。この一連のプロセスをロールアウトと呼びます。そして、何らかの処理を正しく行ったかどうかに応じて報酬を割り当てます。それにはLLMを評価者として使用することもあれば、このコードがコンパイルできるかといった検証可能な指標を使用することもあります。これは通常のトレーニングと比較して、多くの他のコンポーネントが必要であることを意味します。順伝播や逆伝播を行い、中間トレーニングや事前学習で行うようなすべての処理をこなすために、依然として大規模なトレーニング環境や数万基のGPUを統制する必要がありますが、今度は多くのシミュレーション環境を統制し、モデルの推論を実行する必要もあります。このロールアウトを行うときは、実質的にある意味で実際のCursorのセッションを実行しているようなものだからです。
ロールアウトとは、順伝播のようなものですか。
いいえ、ロールアウトとは基本的にはCursorにおけるエージェントのセッション全体のことです。つまり、50ターンほどかかる可能性があり、モデルが最初のプロンプトを受け取り、いくつかのツールを呼び出すことを決定し、それらのツールを実行し、さらにモデルが別のコードを生成するという、Cursorでエージェントとやり取りする際のセッション全体を指します。トレーニングの実行の一部としてこのセッション全体をシミュレートし、最終的な報酬を得て、そのシミュレーションの信号を使ってトレーナーに戻り、モデルの重みに組み込んでいくのです。そのため、この非常に大きなループ、更新ループが存在し、それは極めてヘテロジニアス(不均一)なものです。これらすべての異なるコンポーネントが連携して動作しており、GPUは高価であり、経済的な方法で迅速にモデルをトレーニングしたいため、これらすべてを効率的に動作させ、高いスループットを実現するように統制しようとしています。それ自体が、アルゴリズムとインフラストラクチャの交差点における非常に興味深い問題であり、システムをどのように共同最適化し共同設計できるかという多くのトレードオフが存在します。
一つの側面として、パイプラインの同期と呼ばれるものがあります。考え方としては基本的に、このモデルを段階的に更新しようとするものです。現在のモデルのバージョンがあり、それを使っていくつかのロールアウトを行おうとします。そのロールアウトを行っている間、トレーナーは何をしているのでしょうか。単純なアプローチであれば、ここでトレーナーを停止させ、いくつかのセッションを実行することになります。そして、長期的なタスクであれば、それらのセッションが5分から10分、あるいはそれ以上実行されるかもしれません。それらの結果を取得した後に推論を一時停止し、トレーニングに戻って更新を試みます。それは理論的、アルゴリズム的には非常に堅牢ですが、容量の半分が常にアイドル状態で待機することになるため、システムとしては非常に非効率的です。
代わりに、賢いアルゴリズムの工夫を凝らすことができます。
ええ、これらすべてをパイプライン化することができます。これを巨大な工場のようなものとして想像してみてください。トレーナーの建物と、ロールアウトの建物があります。それらは常に稼働しています。ロールアウトは常に最新のモデルバージョンを取得して新しいセッションを試み、新しいエージェントセッションをシミュレートします。そしてトレーナーは、新しい結果が届くたびにそれらを受け取り、更新の計算を試みます。すべてが常に同時に動き続けているのです。
アルゴリズム的に異なると言ったトレードオフの理由は、シミュレートされた環境でのテストロールアウトが完了するまでに、モデルの重みがおそらく他のデータですでに更新されている可能性があるからです。そのため、モデルが更新を学習できる速さの間に、このような古さ、つまり遅延が生じます。シミュレートされた環境との対話セッションを処理するまでにモデルが変更されてしまうため、興味深いトレーニングの動態が導入されますが、これに対処する賢い方法があります。その反面、すべてのGPUやコンピューターが常に負荷を抱えて稼働している状態になるため、実際にはより多くのFLOPsを使用することになり、ビター・レッスンの例のように計算効率が高まります。より短い時間でより優れたモデルに到達できるのです。非同期であり、完璧な数学的更新を行わないことから数パーセントの損失があるかもしれませんが、容量の半分を無駄にしないことで、それをはるかに補うことができます。その部分には多くの奥深さと興味深い相互作用が存在します。
そして、私たちはCursorにおけるパフォーマンスを非常に重視しています。大手の大規模な研究所とは異なり、私たちが持っているGPUは数百万基ではなく数万基だからです。そのため、GPUから最大限の能力を引き出すためにあらゆるトリックを駆使しています。実際の運用環境でもFP4でトレーニングを行っていますし、Fireworksと協力して推論の強化も進めています。インフラストラクチャに関する事柄は、事前学習のインフラストラクチャがすべて必要であるという前提条件に加えて、ユーザーのコンピューターがどのように見えるかを可能な限り忠実に模倣しなければならない環境を実行するためのインフラストラクチャも必要になるため、本質的に事前学習よりも複雑なのです。可能な限り忠実に模倣することが非常に重要なのは、モデルが偽の環境で実行されているか本物の環境で実行されているかを実際に突き止めてしまうことがあり、強化学習中と実際の運用環境で異なる挙動を示すことがあるからです。
分散環境での重み転送と数値的非一致への挑戦
推論効率の高さも求められます。これは本当に重要です。強化学習中にはトレーニングのFLOPsよりも推論のFLOPsの方がはるかに多く消費されるという神話のようなものがありますが、これは全体的な性質というよりも、オープンソースの推論エンジンが非常に最適化されていないことに起因しています。大まかな比率は同じようなものです。理論的には、GPUを最大限に追い込めば、トレーニング用GPUの3分の1を推論に割り当てることになるはずです。トレーニングは実質的に3回の順伝播に相当するからです。順伝播があり、データの勾配があり、重みの勾配があります。一方で、推論でクリティカルなバッチサイズに実際に達した場合、1回分の順伝播に相当するFLOPsしか消費しないはずです。
それが、オープンソースの推論エンジンを使用せず、Fireworksを利用している理由ですね。
ええ、もう一つの選択肢としては自社で構築することですが、他社と同様に私たちのエンジニアの数も有限です。推論エンジンの立ち上げに労力を割くよりも、エンジニアにはトレーニングをより効率的かつ正確にすることに注力してもらいたいと考えています。
なるほど、徹底していますね。技術論文の中で、これをある種の世界規模で分散された方法で行っていたと言及されていたかと思います。なぜグローバルに分散させたのか、そして何がそれを難しくしているのでしょうか。
ええ、様々な理由があります。一つは、これほど大規模で隣接したクラスターを市場で見つけるのが難しいという点です。そこで私たちが代わりにできることとして、トレーニングのすべてを実行する一つのクラスターを用意します。グローバルなトレーニングクラスターを作ることはできませんが、強化学習の推論コンポーネントに関しては、世界中の小さなクラスターにグローバルに分散させることができます。Composer 2の実行においては、世界中にある、互いに非常に離れた計4つのクラスターを使用しました。さらに、利用者が最も少ない時間帯には、実際の運用環境のトラフィックの一部すら活用しました。手元には前世代のモデルであるComposer 1.5が稼働しており、人々があまり使っていない時間帯に、いくつかの推論用GPUを確保してトレーニングの高速化に投入したのです。このような取り組みを行うことで、一つの巨大な隣接クラスターを持たずとも、トレーニング環境を容易にスケールアップすることができます。それを可能にしている詳細については、ディマがより詳しく話せるかもしれません。
フェデリコが言ったことを補足すると、基本的に私たちのトレーニングは非常にヘテロジニアス(不均一)です。異なるコンポーネントがどのようなインフラストラクチャを必要としているかという不均一性をレバレッジすることで、効率性を高めることができます。そして、このパターンはあらゆる場所で一様に見られます。特にトレーニングにおいては、高度に相互接続されたクラスターが必要であり、高速なネットワークが必要で、同期して動作する必要があります。そのため、それらのクラスターは高価ですし、大きなものを見つけるのは本当に困難です。基本的にComposerがトレーニングされた規模において、2倍大きなクラスターを見つけることは、現在のサイズのものを見つけるよりも大幅に難易度が高くなります。だからこそ、これらのコンポーネントを分解して異なる場所に配置することができれば、第一にそのような巨大なクラスターを探す必要がなくなります。第二に、ハードウェアの異なるトレードオフを見出すことができます。推論においては、そのような広帯域の相互接続は必要ないからです。少数のGPUグループが相互に接続されていれば十分です。不均一な種類のGPUを混在させることも、異なる世代のGPUを組み合わせることも可能で、これらすべての最適化のパズルを楽しむことができます。そして最後に、推論は進行状況に応じてスケールアップやスケールダウンを行うことがはるかに容易です。オフピークの時間帯があるとき、推論プール全体を、実際のユーザー向けの運用トラフィックを処理するGPUのセットとしても、あるいは強化学習の目的でシミュレートされた環境を処理するセットとしても見なすことができ、これらの間でバランスを取ることができます。
もちろん、これは非常に興味深いシステム上の問題です。1テラバイトのトレーニングステップには約5分から15分かかります。つまり、基本的には5分から10分ごとに、1テラバイトの新しい重みのスナップショットが生成されていることを意味します。問題は、それを世界の反対側にある別のクラスターへ、いかにして極めて効率的に転送するかということです。そして、先ほど述べたように、データの古さが制御不能になるのを防ぐために、迅速に行う必要があります。
お互いに知恵を絞って解明した最も楽しい部分は、モデル全体が1テラバイトであるにもかかわらず、すべての重みがステップごとに変更されるわけではないという点でした。強化学習は、特にトレーニングが進むにつれて、非常に精密な調整を多く行うからです。そのため、どの重みのサブセットが変更されるかには非常に規則的なパターンがあり、毎回すべてが変わるわけではありません。1回のトレーニングステップ、例えば10分間でモデルがどのように変化するかを見ると、それらの間の差分(デルタ)は比較的小さいのです。この性質をレバレッジした圧縮アルゴリズムを書くことができ、そこからはデータベースシステムの問題へと帰着します。つまり、手元にある差分を世界の反対側へ転送したいという問題です。私たちの差分は、モデル全体を転送する場合に比べて約20倍小さくなる可能性があり、これが実践を可能にしています。しかし、当然ながらストレージシステムからこれらすべての仕組みを構築する必要があります。完全なスナップショットと差分、復旧、整合性の調整などです。私たちはこれを可逆(ロスレス)な方法で構築することができました。つまり、反対側でも常にビット単位で等価なモデルが得られるということです。そのため、これに関するいかなる不具合の側面も心配する必要がなく、非常に高速に行うことができます。最悪の条件下でも数分未満、通常は1分未満で処理できます。そして最も重要なのは、実際の推論環境で重みを入れ替えるための停止時間がわずか30秒ほどである点です。また、アップロードとダウンロードをシャード化することで、クラスターの送信帯域幅を完全に飽和させました。
システム上の工夫を凝らすことで、遅延を抑えることができます。かなりの複雑さを伴いますが、それを抽象化して見事に機能させることができます。トレーニングアルゴリズムの邪魔をすることはありませんし、その反面、他のクラスターをレバレッジするために分解して配置できる強力な能力を手にすることができます。これは、強化学習のインフラストラクチャをどのように構築すべきかという従来の常識とは対極にあるものです。従来の常識では、RDMAで接続された非常に巨大な一つのクラスターを用意することになり、それは極めて高価になります。そしておそらく、10分の1をトレーニングに割り当て、10分の9を推論に割り当てることになるでしょう。確かに高価なネットワークがあれば、この1テラバイトを素早くコピーすることははるかに容易ですが、その場合は3倍の大きさのクラスターが必要になります。もし推論エンジンがより最適化されていれば、効率性が向上する分、GPUの観点からそのクラスターの3分の1を節約できるかもしれませんし、このクラスターの半分を別の地域のより安価なハードウェアに移すこともできるため、コストを大幅に下げることができます。
お二人が満面の笑みを浮かべながらこれを説明しているのが素晴らしいですね。本当に困難な課題であり、システムエンジニアにとって夢のような仕事だからです。お二人が構築したシステムは本当に驚くべきものです。
これに着手するために何日も夜を明かしました。
スパースモデル特有の課題とルーターリプレイによる解決策
本当に長い時間を共に過ごしてきたようですね。冒頭で、Kimmyが非常に大規模でスパースなモデルであると言及されていました。その点は、強化学習の実行を何らかの形で難しくさせるのでしょうか。
ええ、難しくなります。
どのようにですか。
推論を行うとき、基本的には自己回帰的な順伝播を行っています。この順伝播において、サンプリングしたトークンの対数確率が生成されます。モデルの生成結果をトレーナーに送り返す際、その順伝播を再実行する必要があります。先ほど触れたように、私たちは非同期トレーニングを行っているため、その結果を生成したモデルのバージョンは、トレーナーの現在の段階よりも実際には数ステップ遅れている可能性があるからです。そのため、順伝播を再実行して対数確率を再現しなければなりません。ここでの問題は、理論上は同じモデルバージョンであればこの対数確率は完全に一致するはずですが、同じモデルバージョンであっても、同じトークンに対してわずかに、あるいは時には大きく異なる対数確率の値が得られる点にあります。これは最近、混合精度計算において推論の数値的不一致(ニューメリカル・ミスマッチ)などとしばしば呼ばれ、よく耳にする問題です。
なぜそれが起きるのでしょうか。なぜそのような現象が発生するのですか。
主に、根本的に浮動小数点演算の処理が非決定的だからです。コンピューター上の整数や、いわゆる「整数」でこれを行う場合、順序を入れ替えて加算しても常に同じ結果になります。しかし、仮数部や指数部を持つ、実際には近似値である浮動小数点数でこれを行う場合、加算の順序によって異なる結果が生じます。つまり、モデルが行うすべての演算、基本的には掛け算と足し算の累積順序において、足し算の順序が最終的な結果に影響を与えるのです。すべては小さな違いですが、何百万、何十億もの演算を通じて増幅されていきます。モデルの推論を行う際、通常はそれほど問題になりません。モデルを事前学習していれば、実際にはかなり頑健だからです。いくつかのビットが反転したとしても、依然として優れた結果を出力してくれますし、ベンチマークが変わることもありません。しかし、特に強化学習においては、モデルを教えるために非常に微弱な信号を使用しているため、これらの数値的な違いから生じるノイズがトレーニングの成否を分ける可能性があります。その点が特に重要です。そしてこれもまた、アルゴリズムとシステムの交差点における興味深い問題です。美しいコードを書いても、現実には全く機能しないということが起こり得ます。この違いをほぼゼロに追い込む方法が存在します。バッチに依存しない方法があり、基本的には非常に注意深くすべてのGPUカーネルを記述し、常に同じ順序で数値を加算するようにします。常に同じ順序で処理を行うのです。それは可能ですが、常にトレードオフを伴います。基本的にはシステムが2倍から3倍遅くなる可能性があります。ここでもまた、この違いの90%に対処するために、現実的に受け入れられる数パーセントの速度低下はどれくらいか、という興味深いトレードオフになり、私たちは試行錯誤を通じて共に適切なトレードオフを見出しました。
そして、特にスパース性が難しい理由について触れましたが、その理由は、各レイヤーでのアクティベーションを受け取り、それをゲーティングレイヤーに通して実行する仕組みにあります。基本的には、このトークンに対して384個のエキスパートの中から、この8個を実行すると決定します。何らかの計算を行い、上位8個のスコアを得て、それら8個のエキスパートがアクティベートされ、他のエキスパートはそのトークンに対してはアクティベートされません。この演算が、小さな数値的違いをかなり大きく増幅させてしまいます。隠れ状態の小数点以下5桁目あたりに違いがあったとして、通常であれば全く問題にならないような違いですが、その違いのせいで、カットオフの基準としてエキスパートの7番ではなく9番が選ばれてしまうといったことが起こるからです。すると突然、モデルの完全に異なる部分がアクティベートされることになり、違いが大きく増幅されます。スパースモデルはその定義上、推論時のこの不一致に対してはるかに敏感です。通常のロールアウトを行う際は、通常は問題にならず平均化されますが、モデルにこの違いを学習させようとする場合、推論ではエキスパートの7番がアクティベートされたのに、トレーニングでは推論時に全く寄与していなかったエキスパートの9番を更新しようとすることになり、この差は巨大なものになります。
では、この問題を回避するためにGPUカーネルを手書きしていたのですか。
はい。スループットの多くに対処することができ、そこには常にトレードオフが存在します。具体的には、ルーターリプレイと呼ばれる興味深いトリックを行うことができます。基本的には、推論側からトレーニング側に追加の情報を渡し、このトークンに対してはエキスパートの7番をアクティベートした、と伝えることができます。この非常に小さなビットの情報は、アクティベートしたエキスパートを示す一つの整数に過ぎないため、トレーナーをそれに同期させることができます。この数値的同期の多くは、量子化レベルの一致やカーネルの一致といったトリックを行い、トレーニングと推論の実装間の乖離を抑えるためのものです。それを行うか行わないかで、実行が完全に発散してしまうか、あるいは不一致に対処するためにより多くのデータを必要として計算効率が低下してしまうかという、巨大な違いが生まれます。
強化学習のレシピについて、もう少しお話しを伺いたいです。皆さんが使用している報酬信号について、一言教えていただけますか。あるいは、話せない内容でしょうか。
話せません。
トップシークレットの内容ですね。
極秘事項です。
なるほど、理解できます。シミュレートされたロールアウト環境での学習と、実際に学習に利用できる膨大な実際のユーザーデータが存在することとの対比において、なぜ実際のユーザーデータや実際のユーザー環境で強化学習を行わず、シミュレーション環境で行うのでしょうか。
実際のユーザー環境でも行っています。それが、私たちがリアルタイム強化学習と呼んでいるものです。私たちは同じ技術を使用して、推論の重みをFireworksと同期させてこれを行っています。ユーザーが特定のモデルの生成結果に対して満足したか、あるいは不満を持ったかというユーザーの信号を見つけ出し、そのモデルをライブで更新し、数時間ごとに新しいバージョンのモデルを継続的に届けることができます。現在、その時間間隔をさらに短縮することに取り組んでいます。実際には、モデルのコンテキストの長さが長くなるにつれて、ある時点からはその時間を再び引き延ばさなければならなくなるでしょう。面白い取り組みであり、現在は適切なハイパーパラメータを解明するために、安定性を目的に時間を短縮しようとしていますが、それを把握した後は、これらのモデルのコンテキストを長くしたいという理由だけで、再び時間を引き延ばさなければなりません。
オフライン強化学習の価値とコンテキスト自己要約による長期タスクへの対応
非常に多くの実際のユーザーデータがある中で、事前学習的なシミュレーション環境での強化学習を行う必要はあるのでしょうか。実際のユーザーデータの方が、トレーニングや微調整においてはるかに価値が高いように想像できます。なぜオンライン強化学習のステップに直接進まないのでしょうか。なぜオフラインの強化学習を行う必要があるのですか。
現在のオンライン強化学習はかなり非効率的です。本質的にGPUが長時間オフラインになってしまうという問題に悩まされます。それに加えて、効率性とユーザーエクスペリエンスの両面において異なるトレードオフも存在します。シミュレーションを行う場合、実際には同じプロンプトから複数のロールアウトを実行しますよね。実質的に一つのタスクを取り上げ、モデルにそのタスクに対して16回、あるいは128回の試行を課す、つまり同じプロンプトから異なるロールアウトを実行させます。それらの中にはうまくいくものもあれば、うまくいかないものもあります。そして、複数のロールアウトを並行して行うことで、はるかに正確な信号を得ることができます。モデルが非常に優れていて90%の確率でうまくこなすこともあれば、そうでないこともあります。GRPO(Group Relative Policy Optimization)のような損失関数は、同時に複数のロールアウトを行うことで機能します。オンラインで行う場合、戻ってくるロールアウトは1回だけなので、アルゴリズム的な進め方のトレードオフが異なります。そして最も重要なのは、シミュレートされたロールアウトが失敗したとしても、それは実環境ではないということです。単にGPUの時間をいくらか消費したに過ぎません。実際のユーザーが相手である場合、実質的にABテストを行っているようなものなので、最小限満たすべきハードルがはるかに高くなります。モデルが奇妙なものを生成してしまえば、それは悪いユーザーエクスペリエンスになりますからね。
なるほど。実際のユーザーではない環境であれば、おかしなことを試すことができるため、より頻繁にオフポリシー(方策オフ型)を適用できるのですね。ユーザーエクスペリエンスに影響を与えることなく、より多くのロールアウトを実行でき、GRPOを行うことができ、基本的にはユーザーの前に出せるほど十分に優れたパフォーマンスのレベルをブートストラップ(自己解決)できるわけですね。
ええ。私たちはオフラインを通じて推論能力を教えています。これは実際にはオンラインと呼ばれたり、オフラインはどちらかというとDPO(Direct Preference Optimization)のような手法を指すことが多く、REINFORCEのような手法がオンラインに該当しますが、そこでモデルに推論を教えています。モデルがあるべき行動のインプットをいくらか与えます。世界に関する新しい情報を与えようと試み、ツールの呼び出し方を教え、それからユーザーに向けてライブで投入します。なぜなら、もしモデルの出来が悪ければ、ユーザーはそれを使いたがらず、フィードバックも得られなくなるからです。そのため、モデルはオンライン強化学習に投入されるためにも、ある種のハードルを満たしている必要があります。モデルに十分に満足した段階で、それをユーザーに届けます。それがオンライン強化学習、あるいは私たちがリアルタイムと呼ぶものの逆説的な部分です。これを使ってモデルを完全にゼロから作り出すことはできません。ユーザーにモデルを使ってもらう必要があるため、すでに優れた状態である必要があり、私たちはそれをさらに良くすることしかできないのです。
セッションにおける本当に素晴らしい体験を実現するための、まさに仕上げのようなものですね。いつかそれが大きな仕上げになることを願っています。
ダン・ロバーツが昨年の私たちのカンファレンスで発表した内容ですね。あなたもそこにいたと思いますが、伝統的には大きなケーキと小さなチェリーという関係でした。
小さなケーキと大きなチェリーですね。
その通りです。
アンドレイ・カルパシーの言葉で、現在、強化学習はまだ極めて非効率的であり、非常に長いロールアウトを行っても、最終的に得られる情報はごくわずかであり、依然としてストローでビットをすすっているようなものだ、という指摘があります。どう思われますか。その経路からより多くのビットを引き出す方法を解明することはできましたか。
それについてはお話しできません。
分かりました。また機密事項ですね。良いことです、それによって自分が核心を突いた質問をしていると分かりますから。ロールアウトが1回につき数分かかるとおっしゃいました。業界全体が、長期間にわたって中断されることなく、基本的には失敗することなく動作できる、長期的なエージェントの実現へと突き進んでいるように見えます。あのメーターのスケーリングチャートがとても好きなのですが、エージェントをより長く実行させるための強化学習プロセスには、どのような要素が関わっているのでしょうか。
いくつかの要素があります。強化学習に関する問題の一つは、軌跡(トラジェトリ)が長くなればなるほど、クレジット割り当て(どの行動が結果に貢献したかの特定)が難しくなる点です。作業の最後にまとめてグッドやバッドの評価を与える場面を想像してみてください。問題を単純化すると、モデルは自らに、自分のどこが正しくてどこが間違っていたのだろうか、と問いかけることになります。これがクレジット割り当てと呼ばれる問題の本質です。これが長くなるにつれて難易度が上がります。そのため、そこでは多くのトリックを駆使する必要があります。もう一つの問題は、単純にスペースが足りなくなることです。これらのモデルは有限のコンテキストウィンドウを持っており、どこかの時点でその上限に達してしまいます。
実は、Cursorではこの問題を解決するために、ループの内部に圧縮を組み込んでいます。私たちはこれを自己要約と呼んでいます。強化学習の間、エージェントは実際に処理を継続し、永遠に前進し続ける方法を学習します。実際、私たちのモデルは200,000トークンのコンテキストウィンドウを持つモデルですが、現実には、自らの作業を要約し、その要約を持ってコンテキストウィンドウを再起動させつつ、依然としてタスクの達成を試みることができるという能力のおかげで、何百万トークンにもわたって進み続けることができます。そして、モデルをゴールに向けて正しく行動させるように促すと同時に、優れた要約を生成するようにモデルを共同でトレーニングしています。そして同時に、その要約にしっかりと耳を傾けるようにモデルをトレーニングしているのです。これはある種の、推論の継続のようなものです。
それは非常に魅力的だと思います。通常、コンテキスト管理は環境側の難しさの一部と見なされますよね。このケースでは、環境側の難しさとモデル自体がどのように連携して機能するかを事実上共同最適化しており、そのすべてを最適化ループに投入しているわけですから。AIの分野では、コンピューターの計算資源を問題に投入すればするほど、問題をエンドツーエンドで解決できるようになるという現象を何度も目にしてきました。計算資源を投入することの魔法、ビター・レッスンが機能し、共調して動作できるはるかに優れたシステムを手に入れることができます。
完全にその通りです。
すべての企業が独自の環境を強化学習で構築するようになると思いますか。すべての企業がCursorと同じような形の問題を抱えていると思いますか。
もし彼らがAIを使用しており、大量のトークンを生成していて、最適化の対象となる製品を持っているのであれば、モデルをトレーニングすることは正しい選択であり、正しい方向性だと思います。
製品そのものが最強の強化学習環境であるという結論
なるほど、非常に興味深いです。そうすると、皆さんが行った強化学習の大部分は、コードの次のトークンを予測する能力を高めることよりも、環境のツール利用の部分に焦点を当てていたということですね。他の創業者たちが、どこで強化学習を利用すべきかを考える際、大まかにそのようなパターンを頭に入れておくべきでしょうか。つまり、エージェントにツールを使って長期的なタスクを実行させたいのであれば強化学習が必要であり、要約や次のトークンの予測などが得意なモデルを作りたいのであれば、おそらく強化学習は必要ない、という枠組みは、強化学習が必要なタイミングを捉える上で優れたフレームワークでしょうか。
強化学習はあらゆる場所に適合すると思います。タブの自動補完においてすら、個人的な理論であり何ら裏付けはありませんが、モデルを事前学習するとき、モデルは単に人類の知識の全体を摂取しているだけです。例えば、数学のモデルをトレーニングしているとします。モデルはStack Exchange上のすべての数学を学習します。まだ実際の強化学習を経ていないモデルが数学の問題を提示されたとき、モデルは自分がどのような人物であるべきかを迷う必要があります。自分は専門家なのか、それとも学ぼうとしている学生なのか、という迷いです。強化学習の間に行われていることの一つは、このノブを調整し、モデルに、ねえ、あなたは専門家なのだから正確に物事をこなさなければいけないよ、と教えているのだと思います。それが起きていることの一つであり、私たちはこの分布を研ぎ澄ましているのです。
これにはいくつかのフェーズがあります。モデルが学習し、非常に迅速に極めて優秀になる最初のフェーズがあり、それからモデルを継続的に向上させるために大量の計算資源を必要とし、モデルが推論を始めてこのパターンを示すようになる第二のフェーズがあります。カーブの最初のフェーズにおいては、私たちは単にノブを調整し、モデルに、ここでは正確に物事をこなすべきだと伝えているのだと思います。そのため、計算資源が少ないケースであっても、モデルに正確に行動しなければならないと認識させるために、強化学習は非常に有用です。それが私の見解です。
同感です。私たちは多くのユースケースでこのパターンを目にしています。一般的に多くの顧客の強化学習のファインチューニングをサポートしていますが、通常、継続的な事前学習(中間トレーニング)や通常の教師ありファインチューニングは、抽象的な言い方をすれば新しい知識の転移です。そして強化学習は、行動を研ぎ澄ましたり、モデルに求めたい特定の品質を明確にしたりするものであり、通常は両方が必要になります。要約の例においてすら、強化学習は非常に有用です。要約に特定のスタイルを求めたい場合、優れた要約と悪い要約の例を大量に用意したり、それを正確に記述したりするのは本当に難しいからです。しかし、例えばLLMを評価者として使用すれば、非常に正確な評価基準を設定できます。プロンプトを使って、これが要約の良し悪しを評価する基準だ、と指示し、それを強化学習のループに投入して、モデルに異なる要約のスタイルを実験させ、実際に何が求められているかを解明させることができます。その間、別のLLMが特定の評価基準に合致しているかどうかを評価するのです。このようなパターンはコーディングに限らず、多くの分野で見られます。
この質問はディマに尋ねたいと思います。フェデリコは黙秘権を行使するでしょうから。あなたはLLMを評価者として使用することについて何度か言及されました。最終的には、専門家が強化学習のロールアウトを直接精査し、何らかの方法でモデルの挙動を直接指導する企業の方が成功すると思いますか。それとも、LLMを評価者とする方法や、他の自動化された評価基準によって目的の場所に到達できると思いますか。
専門家を直接ロールアウトの評価に配置することはありません。それは実際のユーザーを相手にするリアルタイム強化学習か、あるいはDPOのためのRLHF(人間のフィードバックによる強化学習)のような形になるでしょう。一般的には、報酬が検証可能であればあるほど、計算資源をスケールさせてより良い結果を得ることができるため、望ましいと言えます。検証可能というのは、基本的には人間を介さずに自動的に生成できるという意味です。当然、数学やコーディングのように、非常に決定論的なものを構築できるのであれば、それがベストです。LLMを評価者とする方法が機能する理由は、それが実際に生成者と識別者の区別のようなものだからです。評価する方がはるかに行いやすいのです。人間にとっても同様で、作成するよりも評価する方が簡単です。
ええ、そこに含みはありませんが。
ええ、評価する方がはるかに簡単であり、いくつかの回答をランク付けするために求める異なる基準を正確に作り込むことができます。複数の側面からなる非常に複雑な評価を行うパターンが見られます。複数の側面を一つのLLMに丸投げすると、どのように評価すべきか混乱してしまう可能性があるため、細分化するのです。スタイルに基づく評価基準、ファクチュアリティ(事実性)など異なる側面に基づく評価基準に分解し、これらの報酬を作り上げます。それらの一部は決定論的であり、一部はLLMベースになり、それがモデルの挙動を導くことになります。あとはさらに計算資源を投入し、グラフが上昇していくのを見守るだけです。
検証がより難しいドメインにおいて、強化学習がより効果的になっていくのを目にすることになると思いますか。LLMを評価者とするだけで十分でしょうか。
それは最初に始める手法の一つですね。理想的には、実際の結果が何であるか、得たい実際のメトリクス(指標)が何であるかを解明したいと考えます。それを近似しようと試みることが一つの方法であり、より大きなシミュレーション環境を手に入れようとすることがもう一つの方法です。自社の製品をより多くシミュレートでき、環境をより多くシミュレートできれば、通常は重視する最終的なメトリクスが存在します。それをどのように捉えるかを解明できれば素晴らしいことです。
そして専門家に関する点について言えば、専門家は依然として必要です。これらのタスクを作り込み、求めたい製品体験をエンコードすること、それこそが重要だからです。私たちはソフトウェア1.0、2.0、3.0を経てきましたよね。ソフトウェアを直接記述することから、トレーニングデータを作り出すことへと移行しました。そして今、実質的に評価のルールを作り出しているのです。しかし、それは依然として非常に重要です。例を見る必要があり、データを見る必要があり、製品がどこで失敗しているか、そしてモデルをどのように正しい挙動へと促すかを見極める必要があります。
先ほどのお話に関連するかもしれない、強化学習の環境についてお聞きしたいです。いくつかの強化学習環境を提供する企業の収益規模が、非常に大きく爆発的に拡大しているように見えます。それらの企業は、実際にどのような有用なものを提供しているのでしょうか。なぜなら、例えばCursorであれば、顧客が実際に皆さんの環境をどのように使用しているかに関する膨大なデータを持っています。強化学習環境のベンダーは、皆さんがすでに持っているものに加えて、どのような価値を提供してくれるのでしょうか。
私たちは環境ベンダーを一切利用していません。動作する環境を構築することは非常に困難であるため、そうした環境へのアクセスを持たない人々にとっては価値のある製品だと思います。しかし、特にコーディングに関しては、誰でも利用できる非常に大規模な動作するコーディング環境が存在します。それがGitHubです。リポジトリのすべての依存関係をモデルにインストールさせることができ、それが動作する環境になります。難しさの多くは、インフラストラクチャ側からも生じます。特定のタスクに対して適切に動作する環境には、サービスが立ち上がっている必要があると想像できるでしょう。例えば、データベースのマイグレーションを行う変更を加えるとして、それが実際に動作しているかをテストするには、データベースが立ち上がっている必要があります。そうした事柄は非常に厄介であり、環境を提供する企業はそうした部分で非常に役立っているのだと思います。
これには二つの側面があります。第一に、大手の研究所を見ると、彼らはあらゆるタスクに秀でた汎用的なモデルを構築しようとしています。そのため、その下に潜むこれらすべての異なるタスクをカバーし、一つのモデルにパッケージ化して汎化を促す必要があります。ですから、そうしたケースにおいては非常に役立ちます。一方でComposerのようなケースにおいては、実際の製品が存在します。そして、それこそがFireworksでも信じていることですが、実際の製品を持っているのであれば、その製品に対して優れたパフォーマンスを発揮すべきです。最も強力な環境は、あなた自身の製品そのものです。なぜなら、そここそがモデルが実際に使用される場所だからです。
当然、大手の研究所であれば、すべての製品にわたってそれを行うことはできません。しかし、自社の製品に最適なモデルを構築し、特化させ、適合させようとするのであれば、自社の本番環境を利用すべきです。もちろん、適切に隔離する必要がありますが。モデルが本番環境のデータベースを破壊するようなことは避けたいので、それをクローンしたりします。環境ベンダーのツールや、一般的なインフラストラクチャのツールの中には、それを容易にしてくれるものもあります。しかし一般的には、強化学習環境は実際の本番環境にできる限り近いものであることが望まれます。
私たちが目にする例として、おもちゃのような強化学習の例やおもちゃのようなフレームワークでは、常に、おもちゃの環境があり、Dockerコンテナを立ち上げてその中でエージェントをすべて実行する、といった形から始まります。それは、モデルにアタリのゲームのプレイ方法を教えるといった、おもちゃの例であれば素晴らしいものです。しかし、実際の運用のケースに移行する場合、本物の運用アプリケーションを単にDockerコンテナに詰め込むわけにはいきません。私たちは、Cursorのトレーナー側でFireworksと協力する中で、それをかなり早い段階で実感しました。他の顧客の場合、私たちのトレーニングプラットフォーム上でトレーナーを実行しますが、環境に関しては、実際のนี่がそこに存在するため、顧客側で実行することをデフォルトとしています。トレーナーがFireworksプラットフォームの一部であっても、あるいは顧客側にあっても、実際の運用環境を呼び出す同じセットアップを持ち、それをラップしてコンポーネント化しようとはしません。ホストされたプラットフォーム上で行うのは非常に困難であり、違いを導入してしまうからです。
私たちが環境と呼んでいるものは、実際には三つのコンポーネントから構成されています。一つはハーネス(仕組み)です。ハーネスとは、モデルがツールを提出し、ツールが実行される場所です。二つ目は、それをオペレーティングシステムと呼びましょう。モデルが対話している実際の環境、つまり状態のことです。そして三つ目は報酬のコンポーネントであり、最後に作業が正しく完了したかをチェックする必要があります。一般的にハーネスはかなりポータブルです。ハーネスを取り出して、多くの異なる環境に配置することができます。鍵となるのはオペレーティングシステムであり、これを複製するために通常のコンテナはあまりうまく機能しません。そのため、Cursorでは実際に仮想マシンスタック全体を自社で構築しました。これにより、仮想マシンを非常に迅速に立ち上げることができます。そして、これは極めてバースト的(一時的に大量発生する性質)である必要があります。システムに対して、今すぐ100,000台の仮想マシンを用意してくれ、と要求し、それらがすべて一斉に立ち上がらなければならないような状況を想像できるでしょう。
素晴らしい。本日は本当に楽しい会話ができました。Cursorが、アプリケーション企業から真の最先端モデル研究所へと向かう姿勢において、あらゆる企業にとってどれほど大きなインスピレーションを与えているかを感じます。そして、Composer 2で行った取り組みがその突撃を率いているのだと思います。そのお話を伺えて本当に特別でした。そしてディマ、お二人が多くの夜遅く、最前線で共に解決した徹底的なインフラストラクチャの難問について伺えたのも非常にクールでした。それらすべてが可能になった背景が見えました。本日はご参加いただき、本当にありがとうございました。
お招きいただき本当にありがとうございました。
ありがとうございました。


コメント