はじめに
こんにちは、私は機械知能研究室に所属し、CV分野の研究をしています
機械知能研究室ではロボットの視覚機能や自律的に行動するための知能システムについての研究に取り組んでいます (ホームページは下記のリンクから)
少し前に、Antigravity SDKが登場しました。
軽く調べて思ったことは、、、コードを書くAIを操作するコードを書くってこと!?と思いました。
このAntigravity SDKを研究に活かせないか考えました。
そこで、「テーマを与えたら自動で研究をしてくれる"ミニ研究者"」が作れるのではないか?と思ったので試してみました!!
実装、実行、改善、を繰り返し、目標の結果を出すまで全自動でやってくれるミニ研究者のようなパイプラインを作成してみました。
Antigracity SDKについて理解したいという方は、@torifukukaiou(Awesome YAMAUCHI)さんの記事が参考になるのでぜひご覧ください。
0.前提・パイプラインの概要
下記の任務をAntigravity SDKで完全自動化します。
全自動化する研究の流れ
- 目的を伝える
- コードの実装
- 実行、結果から改善を考えて実装を更新(目標の結果が出るまで複数回ループ)
- 結果をまとめる
1.Antigracity SDKを用いたシステム
Antigracity SDKはpythonのコードベースでgemini APIを使用できます。
従って、pythonのコードで目的の自動研究者システムを作成します。
パイプラインの実態は下記です。
今回のパイプラインの実装は、GUIのGeminiとAntigravity IDEで作成しました。
- APIキーの取り扱いや従量課金の設定は慎重に設定しましょう
- APIの無料枠と有料枠では、モデルの学習に使用されるなどの違いがあるので注意。
work_space/
├── run_researcher.py # 【監督】AIへ指示を出し、Dockerでの実行と評価ループを回すメインスクリプト
├── setup_assets.py # 【準備】ネットワーク通信が必要な処理(事前学習済みの重みやデータセット)を事前に取得しておくためのスクリプト
├── Dockerfile # 【環境】ループ処理を安全に実行するための隔離環境(Sandbox)の設計図
├── checkpoints/ # 【共有領域】事前学習モデルの重みファイル(.pth)が保存されるフォルダ(DockerへRead-Onlyマウント)
├── data/ # 【共有領域】データセットが入るフォルダ(DockerへRead-Onlyマウント)
└── venv/ # 【仮想環境】
パイプラインの概要
run_researcher.pyがメインスクリプトです。
これを実行すると、Antigracity SDKを用いて、ミニ研究者がtrain.pyという改善を繰り返すファイルを作成してくれます。
複数回の試行錯誤で更新するファイルはこのtrain.pyのみです。
毎回更新したtrain.pyを実行して、目的(最高精度の達成)を目指します。
実行手順
- venvを作成
- setup_assets.py(事前準備)でネットワークが必要なデータセットやモデルの重みをdata, checkpointsに作成
- Dockerfileからコンテナ作成
- メインスクリプト(run_researcher.py)を実行
特長
- ホスト環境(教授の部屋)と、実行ループ環境(研究室)で分ける
- 実際に試行錯誤してファイルを更新する場所はDockerのコンテナ内
- Dockerを使用することで、安全に、ミニ研究者に思う存分暴れてもらいます。
- ネットワークが必要なデータセットやモデルの重みはDockerの外からマウント。
メインスクリプト(run_researcher.py)の内容
Phase 1: 初回ベースラインコードを生成してもらう
init_promptとsystem_instructionの2つのプロンプトをAPIでgeminiに投げて、train.pyを作成してもらう
init_prompt
print("\n=== [Phase 1] 研究テーマの解釈 & 初回ベースラインコード生成 ===")
init_prompt = f"""
【研究テーマ】
ResNet-18の事前学習済みモデル(ImageNet重み)を活用し、CIFAR-100データセットに対するテスト識別精度(Test Accuracy)を最大化するファインチューニング手法、データ拡張、ハイパーパラメータ、正則化技法を探求せよ。
(最大探求回数は5回とします。)
【制約条件】
- 必ず事前学習済みモデル(ImageNet等)をロードしてベースに使用すること(学習時間短縮のため)。
- 実行環境は完全オフライン(ネットワーク遮断)です。`weights=DEFAULT` による自動ダウンロード機能はエラーになるため絶対に使わないでください。
- ResNet-18の事前学習済み重み(.pthファイル)は `/root/.cache/torch/hub/checkpoints` ディレクトリ内に配置されています。
- `torchvision.models.resnet18()` でモデルを初期化した後、`torch.load()` と `model.load_state_dict()` を使って、上記のディレクトリにあるローカルの重みファイルを明示的にロードするコードを書いてください。
- CIFAR-100のデータセットは既に `/workspace/data` に展開済みです。
- 1回の試行におけるエポック数は「最大30エポック」までとする。
- 単なるパラメータ調整だけでなく、Mixup, CutMix, Label Smoothing, Cosine Annealing, SAM, データ拡張の組み合わせ等のPyTorchコードレベルの工夫を積極的に試みること。
- 最終的にどのような試行錯誤をしたのかをまとめてレポートを作成していただきます。
- スクリプト実行の末尾で、必ず標準出力に以下のJSONフォーマットで1行出力すること:
__RESULT_JSON__:{"primary_metric_name": "test_acc", "primary_metric_value": <float>, "epochs_trained": <int>, "final_loss": <float>}
上記の目標を達成するための最初のベースラインとなるPyTorchコード `train.py` を作成してください。
仮説理由の説明と、```python ... ``` コードブロックを提示してください。
"""
system_instruction
あなたは最高峰のAI/MLリサーチャー兼PyTorchエキスパートエンジニアです。
与えられた研究目標と制約条件を達成するため、自律的に仮説立案、PyTorchコード作成、実験結果の分析、コード改善を行います。
【重要制約・出力規約】
- データセットは `./data` に存在し、事前学習重みは `torchvision.models` からロード可能です。
- 単体でそのまま実行可能な完結したPyTorchスクリプト (`train.py`) にしてください。
- スクリプトの最終行付近で、必ず以下のフォーマットで評価結果を標準出力 (print) してください:
print(f"__RESULT_JSON__:{json.dumps({'primary_metric_name': 'test_acc', 'primary_metric_value': round(best_acc, 2), 'epochs_trained': epochs, 'final_loss': round(final_loss, 4)})}")
2つのプロンプトをgeminiに投げて、train.pyを作成
llm_response = get_llm_response(init_prompt, system_instruction, phase_name="Phase 1: Initial Baseline Code Generation")
返答のtrain.pyを実際に更新する
code = extract_python_code(llm_response)
with open(train.py, "w", encoding="utf-8") as f:
f.write(code)
print(f"✅ 初回 `{TARGET_SCRIPT}` を生成・保存しました。")
Phase 2 & 3: 実験 & 自律改善ループ (Dockerサンドボックス内)
最大試行回数(今回は5回)まで下記を繰り返す。
-
train.pyを実行
-
結果をAPIで送り、改善コードを取得
-
改善コードを更新
for iteration in range(1, MAX_ITERATIONS + 1): print(f"\n" + "="*25 + f" 試行ターン {iteration} /{MAX_ITERATIONS} " + "="*25) # 🐳 Dockerコンテナでオフライン実行 res = run_experiment_in_docker(TARGET_SCRIPT) # 失敗時の処理(省略) # 成功時のメトリクス評価 history.append({ "iteration": iteration, "success": True, "metric_name": metric_name, "metric_value": metric_val, "loss": loss, "epochs": epochs, "elapsed_sec": elapsed, "code_snapshot": code }) # 次のターンに向けた改善提案 & 早期終了判定 if iteration < MAX_ITERATIONS: print(f"\n💡 結果分析および次回のコード改善案を生成中...") improve_prompt = f""" 研究目標: {RESEARCH_GOAL} これまでの実験結果履歴: {json.dumps([{k: v for k, v in h.items() if k != 'code_snapshot'} for h in history], indent=2)} 【分析と指示】: 1. 前回の実験結果({metric_name} = {metric_val})を考察してください。 2. 研究目標に対して十分な成果が得られたか、あるいはこれ以上の大きな改善が見込めない(収束した)場合は `is_goal_reached: true` と判定してください。 3. まだ改善の余地がある場合は、新たな改善仮説(手法・コード改修)を立案し、修正した最新の `{TARGET_SCRIPT}` 全系を ```python ... ``` ブロックで提示してください。 回答には、必ず最後に以下の判定JSONブロックを含めてください: ```json {{ "is_goal_reached": false, "reason": "判断理由の簡潔な説明" }} ``` """ llm_response = get_llm_response(improve_prompt, system_instruction, phase_name=f"Iteration {iteration}: Hypothesis & Improvement Code Generation") eval_json = extract_json_block(llm_response) if eval_json and eval_json.get("is_goal_reached"): print(f"\n🎉 エージェントが『目標達成 / 改善の収束』と判断しました。: {eval_json.get('reason')}") print("早期終了します。") break code = extract_python_code(llm_response) with open(TARGET_SCRIPT, "w", encoding="utf-8") as f: f.write(code) print(f"✅ `{TARGET_SCRIPT}` を新バージョンに更新しました。")
Phase 4: レポート生成
最後に、結果のレポートを作成してもらいます。
print("\n=== [Phase 4] 全試行完了: 最終研究レポート生成中 ===")
summary_prompt = f"""
研究テーマ:
{RESEARCH_GOAL}
全試行の実験結果データ:
{json.dumps([{k: v for k, v in h.items() if k != 'code_snapshot'} for h in history], indent=2)}
上記の実験データを基に、以下の構成でMarkdown形式の学術風研究レポートを作成してください:
1. 研究概要とアプローチの要約
2. 各試行(Iteration)における仮説・コード変更点・評価メトリクスの比較表
3. 最高成績を達成したアプローチの勝因分析
4. 結論および今後の展望
"""
final_report = get_llm_response(summary_prompt, phase_name="Phase 4: Final Research Report Generation")
with open(REPORT_FILE, "w", encoding="utf-8") as f:
f.write(final_report)
print(f"\n📄 レポートを '{REPORT_FILE}' に保存しました。")
print(f"📄 全対話プロンプト&応答ログを '{LLM_LOG_FILE}' に保存しました。")
実行結果(レポートの内容を要約)
最終的に出力されたレポートの内容を一部抜粋、要約して下記に記載します。
1. 研究概要とアプローチの要約
本研究の目的は、ImageNetで事前学習されたResNet-18モデルを活用し、完全オフライン環境下においてCIFAR-100データセットに...
(省略)
2. 各試行(Iteration)における仮説・コード変更点・評価メトリクス
全5回の実験における設計意図、コード変更内容、および得られた結果を以下にまとめる。
試行結果の比較一覧
| Iteration | 手法・主要変更点 | Epochs | 訓練時間 (s) | Final Loss | Test Acc (%) |
|---|---|---|---|---|---|
| 1 | ベースライン (アップサンプリング 224x224, SGD + CosineAnnealing, Standard Aug) | 30 | 265.9 | 1.5490 | 76.47 |
| 2 | 低解像度入力対応 (32x32直接入力, 第1Conv/MaxPoolの置換, 学習率固定) | 30 | 259.7 | 1.5130 | 59.28 |
| 3 | SAM (Sharpness-Aware Minimization) + 強力なデータ拡張 (AutoAugment) | 30 | 3544.6 | 1.5403 | 68.59 |
| 4 | 解像度調整 (112x112) + CutMix/Mixup + Label Smoothing (0.1) | 30 | 1126.8 | 1.5298 | 76.50 |
| 5 | 過度の正則化複合検証 (SAM + CutMix + 高ドロップアウト + 重み減衰強化) | 30 | 2159.3 | 1.7634 | 70.29 |
各試行の詳細分析
-
Iteration 1 (ベースライン: 76.47%)
- 仮説: ImageNet重みの受容野を活かすため、CIFAR-100の画像を224×224にバイキュービック補間し、標準的なSGD(モーメンタム0.9、Cosine Annealing)で最終FC層および全バックボーンを微調整することで、強力なベースラインが得られる。
-
結果: 30エポックと短期間ながら76.47%という極めて良好な精度を達成した。
.
省
略
.
-
Iteration 4 (解像度最適化 + Mixup/CutMix + Label Smoothing: 76.50%)
- 仮説: 解像度を計算量と特徴保存のバランスが良い112×112に設定し、CutMix/Mixupによるデータ正則化とLabel Smoothing($\alpha=0.1$)を導入することで過信(over-confidence)を抑制し、最高精度を更新する。
- 結果: 汎化性能が向上し、テスト精度 76.50%(最高値)を達成。Final Lossも1.5298と安定した収束を見せた。
-
Iteration 5 (複合的正則化の検証: 70.29%)
- 仮説: Iteration 4のデータ拡張にSAMと強い重み減衰を組み合わせることで、さらなる汎化性能の向上を狙う。
- 結果: 正則化の効きすぎ(under-fitting気味)となり、損失の収束(1.7634)が遅れ、精度は70.29%に後退した。
--
この後も、3. 最高成績を達成したアプローチの勝因分析と4. 結論および今後の展望が記載されていました。
まとめ
5回の繰り返し探索をしてもらったが、結果として4回目が最も良い結果となった。
徐々に改善していっているとは言い難い結果であると思っています。
理由は、APIで使用するgeminiは前回までの履歴が無く、APIで投げるたびにスクラッチの状態であるからというのが影響していると思います。(今回は前回までの履歴をプロンプトに混ぜることで対応したが、プロンプトだけでは不十分だった可能性がある)
今回一連のパイプランの実行(最大試行回数5回)で使用したAPI料金:約33円(曖昧な記憶なので参考程度に)
今回は簡易的な実装であったが、文献調査などのネットワークの情報を参照するとより本格的な研究になると感じました。
Aintigavity IDEとの違いは、パイプラインをコードベースで実行できることであり、いくつかの実行を繰り返したり、パイプラインが決まっている長い実行などはSDKを使用する方が向いていると思いました。
参考にしたサイト
