オリジナル: [AlphaCodiumによる最先端のコード生成 - プロンプトエンジニアリングからフローエンジニアリングへ]
タル・リドニック著
読み流す
コード生成の課題は、通常の自然言語処理の課題とは異なる。ターゲットとなるプログラミング言語の構文規則に厳密に従うこと、ノーマルケースとバウンダリーケースを識別すること、問題仕様の多くの詳細に注意を払うこと、コードに固有のその他の問題や要件に対処することなどが含まれる。その結果、自然言語生成の分野で一般的に使用されている最適化技術の多くは、コード生成タスクには適用できない可能性がある。
本研究では、次のような新しいコード生成法を提案する。 アルファコディウム -- テストに基づく、段階的な、コードに焦点を当てた、反復的な処理プロセス。このアプローチは、ラージ・ランゲージ・モデル(LLM)のコード問題への対処能力を大幅に向上させる。
AlphaCodiumを、Codeforcesのようなプラットフォームからの競技プログラミングトピックを含むCodeContestsという難しいコード生成データセットでテストしました。私たちのアプローチは、これらのテストで一貫して大幅な性能向上を達成しています。
例えば、検証データセットでは、GPT-4の精度(pass@5)は、AlphaCodiumプロセスを使用した後、よく設計された1つの直接キューで19%から44%に向上しました。AlphaCodiumは、AlphaCodeのような先行研究を上回るだけでなく、必要な計算リソースも大幅に少なくなりました。AlphaCodium。
私たちは、この研究で開発された原則とベストプラクティスの多くが、コード生成におけるさまざまなタスクに一般的に適用できると信じている。私たちの最新のオープンソース・プロジェクト [アルファコディウムCodeContestsのための私たちのAlphaCodiumソリューションは、完全なデータセット評価とベンチマークスクリプトとともに、]で共有されています。
CodeContestsデータセットの解析
[コードコンテストは、Google Deepmindが提供する難易度の高いプログラミングデータセットです。このデータセットは、以下のようなデータから作成されています。コードフォースなどの競技用プログラミング・プラットフォームは、大規模な言語モデル(GPTや ディープシーク) 複雑なプログラミング問題を解決する能力
本研究では、全く新しいモデルを開発することではなく、すでにコーディングタスクを処理できる様々な大規模言語モデルに適用可能なプログラミングプロセスを作成することに焦点を当てた。そのため、107問と165問のプログラミング問題からなるCodeContestsの検証セットとテストセットに焦点を当てる。図1は、データセットの典型的な問題の例である:
それぞれの問題には、問題の説明と、モデルの入力として直接使用できる、公開されているテストデータが含まれている。課題は、どのような正当な入力に対しても正しい答えを与える手続きを書くことである。さらに、提出されたプログラムの正しさを評価するための、一般には公開されていないテストセットがある。
なぜCodeContestsは、大規模言語モデルのプログラミング能力をテストするのに理想的なデータセットなのか? 第一に、他のプログラミングコンテストのデータセットとは異なり、CodeContestsには評価の正確性を保証するための大量のプライベートテストデータ(問題ごとに約200のテストケース)が含まれています。CodeContestsの問題記述は、一般的に複雑かつ詳細で、解答に影響を与えるニュアンスに満ちています(典型的な例を図1に示します)。このデザインは現実世界の問題の複雑さをシミュレートし、モデルに複数の要因を考慮させる。ヒューマンエバールとは対照的である。典型的なHumanEvalのプログラミング問題を付録1に示す。
図2は、図1の問題をモデルがどのように深く分析するかを示している。問題を深く分析することで、問題はより明確になり、より構造化される。このことは、プログラミングの過程で問題を深く理解することの重要性を強調している。
提案された方法論
コード生成の複雑な課題に対処する際、シングルプロンプトによる最適化も、連続的な思考プロンプトも、CodeContestにおける大規模言語モデル(LLM)の問題解決効率を大幅に改善しないことがわかりました。これは、モデルがしばしば問題を完全に理解するのに苦労し、その結果、不正確なコードや新しいテストケースに対処できないコードを繰り返し生成するためです。一般的な自然言語処理に適用できるアプローチは、コード生成タスクには理想的でないかもしれません。このようなタスクには、生成されたコードを繰り返し実行し、既知の例と照らし合わせて検証するなど、大きな可能性が隠されている。一般的な自然言語処理におけるキューの最適化技術とは対照的に、コード生成とテストに特化したCodeContest問題を解決することができる。ワークフローより効果的である。そのプロセスは次のようなものだ。反復つまり、生成されたコードが入出力テストに合格するように、継続的に実行し、微調整するのだ。このコード固有のプロセスの重要な側面は2つある:
(a)反復プロセスをサポートするために、前処理段階で追加データを生成する。例えば、オープン・テスト・ケースに対する自己反省や推論などである。図3に、レースプログラミング問題を解決するために設計したプロセスを示す:
図3のプロセスは、大きく2つの段階に分けられる:
- 前処理 の段階では、自然言語を使って問題を推論する。
- コードの反復 フェーズでは、さまざまなテストのコードを生成、実行、修正する複数の反復セッションを含む。
表1では、これらのさまざまな段階について詳しく説明する:
ステージ名 | ミッション・ステートメント |
問題の考察 | 問題の目的、インプット、アウトプット、ルール、制約、その他の重要な詳細を簡潔な箇条書きの形で要約する。 |
未解決テストケースの論理分析 | 各テストケースの入力が、どのように特定の出力につながるかを記述する。 |
可能な解決策を構想する | 可能性のある解決策を2-3提案し、それを平易な言葉で説明する。 |
ソリューション評価 | 様々な可能性のある解決策を評価し、その正しさ、単純さ、堅牢さを考慮して、最良のものを選択する。(最も効率的な選択肢に限定する必要はない)。 |
補足的なAI検査 | 元のオープンなテストケースではカバーされなかった状況や側面をカバーしようとする6~8種類の入出力テストで問題を補足する。 |
初期コードプログラム | この段階の目標は、問題に対する最初の解答コードを作成することである。このコードができるだけ正解に近いものであることが重要であり、そうであればこの後の修正プロセスで成功する可能性が高くなる。 操作手順は以下の通り: - 可能性のあるシナリオを選び、それに適したコードを書き、選択した公開テストケースとAIテストで試す。 - テストに合格するか、最大試行回数に達するまで、このプロセスを繰り返す。 - テストに合格した最初のコード、または出力が正解に最も近いコードが、以降のステップのベースコードとして使用される。 |
未解決テストケースの反復最適化 | ベースとなるコードを出発点として、オープンなテストケースで1つずつ実行し、最適化する。テストケースで問題があれば、エラーメッセージをもとに修正する。 |
AIテストのための反復最適化 | AIが生成したテストの反復最適化を継続する。テスト・アンカー」(テスト内の特定の要素を修正し、より正確なデバッグとコード改善を行う手法)を適用する。 |
表1 アルファコジウム相の特性。
提案されたプロセスを探求する中で、私たちはいくつかの深い直感と洞察を得た。
まず蓄積された知識簡単な仕事から始め、徐々に複雑な問題に挑戦していく。例えば、プロセスの最初のステップである「自己反省」では、次のような、より難しいステップで使える知識を学ぶ。可能な解決策を生み出す.プロセスの前処理段階は、プロセスの最も困難で重要な部分であるコード反復の燃料となる結果を生み出す。
次ページ追加のAIテストの生成は、ソリューションコードのフルセットを生成するよりも簡単である。 -- このプロセスは、有用な入出力テストのペアを生成するために問題を完全に解くことなく、問題の理解と基本的な総当り解法や論理的推論に大きく依存する。これは、どのような入出力テスト・ペアにも正しく対応できる完全なアルゴリズム解を考え出す必要のある、完全で正しい解コードを書くこととは異なる。その結果、図4に示すように、より多くのAIテストを作成し、コード作成フェーズの最適化に利用することができる。また、大きな入力の処理、エッジケースなど、元の公開テストケースでカバーされていない部分に焦点を当てるようモデルに要求することで、これらの追加テストの有効性をさらに高めます。
最後に複数のステップを1つのラージ言語モデル(LLM)呼び出しにまとめることができる。 -- 図3に示すプロセスは概念的なデモンストレーションであり、プロセスの主なステッ プを強調している。実際には、出力を構造化することによって(次のセクションを参照)、複数の段階を1つの大きな言語モデル呼び出しにまとめ、リソースを節約したり、特定のタスクを同時に処理する際のモデルのパフォーマンスを向上させたりすることができる。
直接的なヒントだけに基づいてコードの問題を解くと、モデルはしばしば苦戦する。一般に公開されているテストケースを反復することで、解は安定し改善されますが、一般に公開されているテストケースは十分に包括的でないため、「盲点」が残ります。前処理フェーズと公開テストとAIが生成したテストの反復を含む、AlphaCodiumの完全なプロセスを使用すると、ソリューションの品質をさらに向上させ、問題解決の成功率を大幅に高めることができます。
コードの設計コンセプト
このセクションでは、コード生成の問題を解決する際に有用と思われる設計コンセプト、テクニック、ベストプラクティスを紹介します。図3で紹介するAlphaCodiumプロセスは、これらの設計概念を幅広く利用しています:
YAML構造化出力: 私たちが提案するプロセスの重要な部分は、構造化された出力を使用することです。モデルに、特定のPydanticクラスに相当するYAML形式の出力を生成することを要求します。例を挙げよう:
...
あなたの目標は、可能な解決策を考え出すことだ。
各プログラムにおいて、問題の目的、規則、制約が十分に考慮されていることを確認する。
出力は、以下の Pydantic 定義に従い、$PossibleSolutions タイプに対応する YAML オブジェクトでなければならない:
クラス Solution(BaseModel).
name: str = Field(description="ソリューションの名前")
content: str = Field(description=解決策の説明")
why_it_works: str = Field(description="この解決策がうまくいく理由。問題のルールとゴールに対して具体的に詳述する必要がある")
complexity: str = Field(description="ソリューションの複雑さ")
クラス PossibleSolutions(BaseModel).
possible_solutions: List[Solution] = Field(max_items=3, description="問題に対する可能な解決策のリスト。各解決が問題のルールと目標を完全に考慮し、最新のコンピュータで妥当な実行時間(多数の入力を持つ問題制約の場合は3秒以内)を持つことを確認してください")
表2 構造化された出力プロンプトの例(可能な解決策の生成フェーズ)。
構造化されたアウトプットは、「キュー・エンジニアリング」の複雑さやハッキングの必要性を減らし、代わりに複雑なタスクをわかりやすくコードのような方法で提示する。また、論理的で組織化された思考プロセスを反映した、複数の段階を含む複雑な答えを得ることも可能になる。
新バージョンのGPTは[ ]をサポートしていますがJSONスタイルしかし、特にコード生成タスクでは、付録に詳述されているように、YAML出力がより適切であると考えている。
箇条書き分析 - 大規模言語モデル(LLM)に問題の分析を依頼する場合、通常、箇条書きのフォーマットで出力を求めることで、より良い結果が得られる。箇条書きは問題の深い理解を促し、モデルに出力を論理的な意味領域に分割させるため、結果の質が向上します。例えば、箇条書きの自己反省問題の場合(図2を参照)、それぞれの箇条書きは、問題の異なる部分(一般的な説明、ゴールとルール、入力構造、出力構造)の意味的理解を表しています。
ビッグ・ランゲージ・モデルはモジュラー・コードの生成に優れている - ラージ・ランゲージ・モデル(LLM)に個々の関数の長いブロックを書かせると、しばしば問題にぶつかる。コードにエラーやロジックの穴があることが多いのだ。さらに悪いことに、このような大規模でモノリシックなコードの塊は、それを修正するための後続の反復作業に支障をきたす可能性がある。エラー情報が提供されても、モデルが問題を特定し修正するのは難しい。しかし、モデルに「_生成されたコードを複数の小さなサブ機能モジュールに分割し、それらに意味のある名前をつける_」と明示的に指示すれば、生成されたコードのエラーは少なくなり、反復修正フェーズの成功率も高くなる。
柔軟な意思決定と二重の検証の重要性 - 大規模な言語モデルは、思慮深く合理的な推論や、重大で非定型的な決定を下す能力を必要とするコード・タスクに苦戦することが多い。例えば、ある問題に対して追加のテストを生成する場合、モデルによって生成されたテストにはエラーが含まれていることが多い。この問題に対処するために、二重検証のプロセスを導入する。このプロセスでは、最初の出力を生成した後、モデルに同じ出力を再度生成させ、必要に応じて修正します。例えば、モデル自身が生成したAIテストを入力として受け取った後、モデルはこれらのテストを再生成し、(もしあれば)時間内にエラーを修正する必要がある。私たちは、この二重の検証ステップが、モデルに批判的に考え、推論する動機付けを与えるだけでなく、"このテストは正しいですか?"といった直接的なイエス/ノー質問をするよりも効果的であることを発見した。のようなイエス/ノー質問よりも効果的である。
意思決定を遅らせる、直接的な質問を避ける、探求のためのスペースを与える - モデルに直接複雑な質問をすると、間違った答えや非現実的な答えが返ってくることが多い。そこで私たちは、カルパシーが下のツイートで説明しているようなアプローチを取り、少しずつデータを蓄積し、単純なタスクから複雑なタスクへと徐々に移行していった:
- 最も単純なタスク、つまり問題についての自己反省と、オープンなテストケースについての推論から始める。
- その後、追加のAIテストと問題解決の可能性の生成に移る。
- 上記のタスクに対するモデルの答えを得た後に初めて、コードを生成して修正を実行するという実際の反復プロセスに移る。
もうひとつの例として、アルゴリズムによる解決策をひとつだけ選ぶのではなく、複数の解決策を評価してランク付けし、上位にランクされたものを優先して最初のコードを記述する。モデルは失敗する可能性があるため、不可逆的な決定は避け、その代わりに探索の余地を残し、さまざまな可能性のある解決策を試すコードの反復を行う。
アンカー技術のテスト - 2回検証したにもかかわらず、AIが生成したテストの中には間違っているものもある。テストが失敗したとき、それがコードの問題なのかテスト自体のエラーなのか、どうやって見分けるのだろうか?何が間違っているのか」をモデルに直接問い合わせると、非現実的な答えが返ってくることが多く、コードが誤って修正されてしまうこともある。この課題に対処するために、私たちは「テスト・アンカー」と呼ばれるアプローチを導入しました:
- まず正しいことが分かっている、一般に公開されているテストを反復する。このステップが完了すると、合格したテストはすべてベンチマークテスト(アンカーテスト)として指定される。
- そして、AIが生成したテストをひとつずつチェックしていく。
- テストに合格したものは、アンカーテストリストに追加される。
- テストが不合格の場合、デフォルトではコードが正しくないとされ、コードの修正が試みられる。重要なのは、修正されたコードも既存のアンカー・テストをすべてパスしなければならないということだ。
このように、アンカーテストは、私たちがコードを修正する際に、誤って修正されることを防ぐ役割を果たす。さらに、アンカー・ポイント・テストのもうひとつの改良点は、AIが生成したテストを難易度順に並べ替えることだ。これにより、アンカーテストは反復プロセスの初期段階でより容易に利用できるようになり、より複雑なAIテストを扱うとき、特に不正確な出力をする可能性が高いAIテストを扱うときに、さらなる安全装置を提供することになった。この戦略は、特に複雑で要求の厳しいAIテストを扱う場合に、テストプロセスの安定性と信頼性を効果的に高める。
結局
ダイレクトチップとアルファコジウムの比較
図5では、AlphaCodiumの結果を、よく設計された1つの直接ヒンティング法の結果と比較しています。評価基準はpass@k(問題解決の成功率)、すなわち各問題に対してkを使用して生成された解の割合です。
AlphaCodiumのアプローチは、CodeContestsでプログラミング問題を解く際の大規模言語モデル(LLM)のパフォーマンスを有意かつ一貫して向上させることがわかります。この結論は、検証セットとテストセットの両方で、オープンソースモデル(DeepSeekなど)とクローズドソースモデル(GPTなど)の両方に当てはまります。
他の研究との比較:
表3に、AlphaCodiumの結果を文献の他の方法と比較して示します。
モデリング | データセット | 方法論 | スコア |
GPT-3.5 | 検証セット | アルファコディウム (パス@5) | 25% |
GPT-3.5 | 検証セット | コードチェーン (パス@5) | 17% |
GPT-3.5 | テストセット | アルファコディウム (パス@5) | 17% |
GPT-3.5 | テストセット | コードチェーン (パス@5) | 14% |
GPT-4 | 検証セット | アルファコディウム (パス@5) | 44% |
ディープマインドの微調整 | 検証セット | アルファコード (パス@10@1K) | 17% |
ディープマインドの微調整 | アルファコード (パス@10@100K) | 24% | |
GPT-4 | テストセット | アルファコディウム (パス@5) | 29% |
ディープマインドの微調整 | テストセット | アルファコード (パス@10@1K) | 16% |
ディープマインドの微調整 | テストセット | アルファコード (パス@10@100K) | 28% |
ジェミニ・プロ | AlphaCode2:AlphaCode2の比較結果は、既存のCodeContestsのバージョンでは報告されていません。曰く AlphaCode2のテクニカルレポート研究者たちは、AlphaCodeの結果とAlphaCode2の結果を未発表のデータセットで比較し、大規模言語モデル(LLM)の呼び出し回数が大幅に減少することを発見した(@100)の場合、AlphaCode2はAlphaCodeに匹敵する性能を発揮する。 29%、パス@10. |
表3:AlphaCodiumと他の文献の研究成果との比較
この図は、AlphaCodiumアプローチが、特に大規模な言語モデルを使用してプログラミングの課題を解決する場合、さまざまなモデルや評価基準の下で優れた性能を示していることを示しています。これらの比較結果は、AlphaCodiumの技術的な革新性を示すだけでなく、実世界のアプリケーションにおけるその有効性と適用可能性も強調しています。
全体として、AlphaCodiumは、インテリジェントプログラミングの分野、特に複雑なプログラミング問題を処理する大規模言語モデルの能力を強化する分野において、その顕著な可能性を示しています。これらの知見は、将来の研究開発に重要な洞察を提供し、大規模言語モデルのさらなる開発と最適化のための貴重な参考資料を提供します。
図6:効率の比較。 これは、Large Language Model(LLM)呼び出し回数に対するAlphaCodiumの精度を他のソリューションと比較したものです。AlphaCodeと比較すると、AlphaCodiumは、同様の精度を達成するために必要なLLMコールが数千倍少なくなっています。
AlphaCodiumを同じGPT-3.5モデルと「5トライ合格率」基準で比較すると、次のようになる。コードチェーンと比較した場合、アルファコディウムのパフォーマンスが良いことは明らかです。と比較した場合アルファコードAlphaCode]の方法を比較する場合、AlphaCodeが異なるコード生成戦略を採用していることに注意することが重要です。AlphaCodeは、コーディング問題を解くために特定のモデルを最適化し、多数のコーディングシナリオを生成し、それらを分類し、最終的に主要な分類から提出するシナリオの数を選択します。AlphaCodeは、網羅的戦略に似た、より多くのLLMコールを使用する特別に最適化されたモデルを採用しています。それにもかかわらず、AlphaCodiumは上位の結果という点でより良い成績を収めました。
また、AlphaCodeもCodeChainも、完全なエンド・ツー・エンドの評価スクリプトを含む再現可能なソリューションを提供していないことも特筆に値する。結果を評価する際には、複数ソリューションのトピックへの対応、フォールトトレランスメカニズム、タイムアウトの問題など、考慮しなければならない詳細がたくさんある。我々の比較は、彼らの論文で報告されたデータに基づいているが、将来の比較の信頼性と再現性のために、再現可能なコードと評価スクリプトの完全なセットを提供する。
計算強度の比較:AlphaCodeとAlphaCode2
AlphaCodiumのプロセスでは、各問題を解くのに約15~20回の大規模言語モデル(LLM)への呼び出しが必要で、これは5回の試行で約100回のLLMへの呼び出しが必要であることを意味する。
また、AlphaCodeは問題ごとに何回大きな言語モデルを呼び出す必要があるのかを明確に報告していません。試行ごとに1回呼び出されると仮定すると(これはまだ不明で、実際にはもっと多いかもしれません)、10万の解からフィルタリングされた10回の試行のそれぞれについて、大きな言語モデルを100万回呼び出す必要があり、AlphaCodiumより4桁多くなります。しかし、私たちが見た結果から、図3が明確に示すように、AlphaCodiumははるかに優れた性能を発揮します。
最近発表されたアルファコード2(...テクニカル・レポートこの研究では、Gemini-Proと呼ばれるプログラミング問題用に微調整されたモデルを評価した。この研究では、CodeContestsのベンチマークも検討されたが、未発表の更新版が使用された。AlphaCode2のレポートによると、AlphaCode2はわずか100サンプル程度で、AlphaCodeが数百万サンプルで達成するレベルの性能を達成し、AlphaCodeの10,000倍以上のサンプル効率を実現している。その結果、AlphaCode2もAlphaCodiumも、大規模な言語モデルの呼び出し回数という点で、AlphaCodeよりはるかに効率的です。
しかし、AlphaCode2は、特にCodeContests大会のために設計された精巧なシステムを採用している。微調整AlphaCodiumモデルは最新のベースモデルに基づいていますが、AlphaCodiumは修正されていない汎用モデルを使用しています。それでも、AlphaCodiumは追加データや高価なトレーニングフェーズなしでモデルの性能を向上させます。
付記
1) コード問題の手動評価の例:
/*
数値の集合において、それらの間の距離が特定の数値の閾値より小さい2つの数値があるかどうかをチェックする。 >>>
has_close_elements({1.0, 2.0, 3.0}, 0.5) false >> >>のようになる。
has_close_elements({1.0, 2.8, 3.0, 4.0, 5.0, 2.0}, 0.3) true
*/
#includeを含む。
#include<ベクトル
1TP5をインクルードする。
名前空間 std;
bool has_close_elements(vector numbers, float threshold){.
表4.この問題は比較的直感的で単純なもので、モデルが推論するような細かさや繊細さはあまりない。
2) YAML出力がJSON出力よりもコード生成タスクに適している理由
新バージョンのGPTには[ ]が付いているがネイティブサポート]が、コード生成のためにはYAML出力がより適切であると考えている。なぜなら、生成されたコードはしばしばシングルクォート、ダブルクォート、特殊文字を含むからです。JSONフォーマットでは、JSON出力は二重引用符で囲まれる必要があるため、LLMがこれらの文字を正しく配置することは困難です。一方、YAML 出力は [ブロック・スカラーの採用]スタイルでは、インデントルールに従うだけで、適切にインデントされたテキストもしくはコードは合法です。加えて、YAML出力はトークンが少ないので、コストが低く、推論時間が速く、モデルがフォーカスする重要でないトークンが少ないので品質が向上します。以下はJSONとYAMLの出力の比較の例です( [https://platform.openai.com/tokenizerが生成される):
インポート json
インポート yaml
s1 = 'print("double quote string")'
s2 = "print('シングルクォート文字列')"
s3 = 'print("""triple quote string""")'
s4 = f"{s1}n{s2}n{s3}"
# キーが変数名、値が文字列の辞書を作る
data = {'s1': s1, 's2': s2, 's3': s3, 's4': s4}.
# 辞書をJSON形式の文字列に変換する
json_data = json.dumps(データ, indent=2)
print(json_data)
# ブロックスカラー形式で辞書をYAML形式の文字列に変換する
yaml_data = yaml.dump(data, indent=2, default_style='|')
print(yaml_data)
出力。
表5.
JSON出力:
図7 JSON出力を使用したトークン・カウントの例。
YAML出力のサンプルを以下に示す:
図8 YAML出力を使ったトークンカウントの例
明らかに、適切なインデントだけを維持するコードを生成することは、より簡潔で明確であるだけでなく、エラーを減らすのに効果的である。