- コードを書いている際にLLMへ「より良いコードを書く」と繰り返し依頼すると、実際にコードが改善されるかを実験した内容
- 元の事例は、ChatGPTのDALL-E画像生成機能で「もっと〜のように作ってほしい」というミームから着想を得た
単純反復プロンプト実験
- Claude 3.5 SonnetにPythonコーディングプロンプトを与え、シンプルだが最適化できる問題を解くよう依頼した。
- ベース実装
- 1から100,000の間の乱数100万個のうち、桁和が30の数の最小値と最大値の差を求める問題
- シンプル実装では657msを要した(Pythonの
str変換方式を使用)
- Iteration #1
- Claudeに「より良いコードを書く」を依頼してコードを改善させた
- ClaudeはPythonクラス形式にリファクタリングし、オブジェクト指向にして、すべての数値に対するdigit sumを事前計算した
- 2.7倍速くなった
- Iteration #2
- Claudeはマルチスレッドとベクトル化されたnumpy演算を使用してコードをさらに最適化した
- 5.1倍速くなった
- Iteration #3
- コードが逆に複雑になり、文字列変換方式への回帰が起きた
- 4.1倍速くなった
- Iteration #4
- numba Pythonライブラリを使用してJITコンパイラを呼び出し、Pythonのasyncioで並列化を実装した
- 最大で100倍の速度向上
- 「コードが宇宙レベルに変わる」という表現ではなく、過剰にエンジニアリングされた「エンタープライズ級」なコードになった
プロンプトエンジニアリングの適用
- LLMの出力を最適化するためにはプロンプトエンジニアリングが必要
- Claude 3.5 Sonnetは、明確な指示を与えれば、より良い結果を得ることができるほど強力なプロンプト遵守能力を持っている
- 単に「より良いコードを書く」ではなく、詳細な指針を含むシステムプロンプトを使用
- 初期プロンプト
- 「最適化されたコード」の定義を詳細に提示(アルゴリズム、並列化、不必要なコードの最小化など)
- 最初の実装でNumbaを使ってdigit sumを最適化し、59倍速くなった
- Iteration #1
- Claudeは並列化を追加したが、異常なビットシフト演算(16進数向け)を導入してバグが発生した
- パフォーマンスは9.1倍に逆に悪化した
- Iteration #2
- ClaudeはSIMD演算を使って性能を改善しようとしたが、依然として誤ったビットシフト演算を使用した
- 最初の実装より65倍速く実行された
- Iteration #3
- Claudeはハッシュテーブルを使用して性能を最適化した
- 最初の実装より100倍速く実行された
- Iteration #3
- Claudeは誤ったビットシフト演算を修正し、性能をわずかに低下させた
- 最初の実装より95倍速く実行された
結論
- 「より良いコード」という曖昧なプロンプトだけでも段階的な改善が可能
- プロンプトエンジニアリングで望む方向(数値計算、JIT、並列化など)を明確に示せば、より高度に進化したコードが得られる
- 自動化された最適化アイデアは新しいツール(numbaなど)を発見するきっかけになるが、依然としてエンジニアがバグ検証と選択的な利用を行う必要がある
- 実際の運用システムでLLMが提案したすべてのコードをそのまま使うには、ドメイン別の制約と検証の必要性が大きい
- この実験はPythonコードを前提としているが、Rustなど他言語との連携方法(PyO3など)でもLLM最適化のアイデアを適用する余地が大きい
1件のコメント
Hacker Newsの意見
コード最適化では、数値が最小値より小さいか最大値より大きいかを先にテストするのが効果的だ。これは合計値を計算する前に実施することで、速度を5.5倍向上させることができる。Numbaを使わずにnumpyでこの作業を行うことができる
GPTなどのLLMは、最初は中程度の結果を返すことが多い。特定の工夫でより良い結果を得られるとされている
LLMは状況ごとのシミュレーションエンジンで、テキスト予測を通じて現実世界のモデルをシミュレーションする。正確なテキスト予測には、現実世界を正確に表すモデルが必要だ
LLMは初心者向けのコーディングに偏る傾向があり、パッケージを明示し、シンプルなコードを要求するのが効果的だ
Android/Kotlinでは、ChatGPTは非効率で、有効でないまたは使用が中止されたメソッドを頻繁に呼び出す
コーディングセッションを始めるときは「コーディング」ではなく「オープンな計画」から始めることが重要だ。LLMの前提を明確にし、コードを書く前に計画を修正する必要がある
DebianでPostgreSQLを完全に削除して再インストールする方法が説明されている。データディレクトリを保持し、既存のデータベースを維持できる
コード最適化は早い段階で行うとよくない場合があり、必要なときにだけ最適化するのが良い
「より良いコードを書く」を繰り返し求めることは、性能を低下させる可能性がある。これは解決策を機能しなくさせることもある
LiveCodeでの計算はPythonより速く、繰り返し処理で合計を計算する方法が説明されている