mcpField
R
run-experiment

run-experiment

github.com/a-green-hand-jackクラウド・DevOps41 回インストール
リポジトリ

run-experiment について

機械学習研究者向けの実験投入スキルです。ローカル、SLURM、RunAI/Kubernetes 環境向けに再現可能なジョブスクリプトを作成し、投入コマンドを提示します。

主な機能

  1. 01ローカル、SLURM、RunAI 環境に対応
  2. 02環境別ジョブスクリプトの生成
  3. 03投入コマンドと Git コミットハッシュの記録
  4. 04スクリプトの構文・書式チェック
  5. 05SLURM ジョブアレイに対応

活用シーン

  1. 01HPC クラスターへの学習ジョブ投入
  2. 02ローカル実験用スクリプトの生成
  3. 03ハイパーパラメータ探索用の SLURM ジョブアレイ設定
  4. 04再現可能な実験実行設定の記録

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/a-green-hand-jack/ml-research-skills --skill run-experiment

インストール後、Claude Code で/run-experimentを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

environments.yaml
templates/
local_run.sh
runai_job.sh
slurm_job.sh

詳細

実験を実行する

ML 実験をコンピューティング環境(ローカルマシン、SLURM HPC(Ibex、UW など)、RunAI/Kubernetes(EPFL))に送信します。

コードと一緒にコミットされる再現可能なジョブスクリプトを jobs/ に生成し、実行する正確な送信コマンドを提示します。

起動したジョブを計画済みの実験、エビデンス項目、ワークツリー、またはプロジェクトアクションに関連付ける場合は、このスキルを research-project-memory と併用してください。 生成したジョブスクリプトを起動前にチェックする場合は、このスキルをプロジェクトのツールチェーンゲートと併用してください。利用できる場合は shellcheck と shfmt を使いますが、スクリプトのドラフトを生成するためにユーザーへインストールを要求しないでください。

用語:

  • local:エージェントが実行されているマシン。通常はユーザーの Mac です
  • Git remote:コードの同期に使用する GitHub/GitLab のリモート。たとえば origin です
  • server:quest、ibex-vscode、epfl-haas などの SSH/HPC/RunAI 実行環境です

SLURM または RunAI で起動する場合は、Git リモートを指す場合を除き、「リモート実行」ではなく「サーバー実行」と呼んでください。

スキルのディレクトリ構成

<installed-skill-dir>/
├── SKILL.md
├── environments.yaml        # Environment profiles (extend for new clusters)
└── templates/
    ├── slurm_job.sh         # SLURM template (Ibex, UW, any SLURM cluster)
    ├── runai_job.sh         # RunAI/Kubernetes template (EPFL)
    └── local_run.sh         # Local tmux/nohup template

実行手順

1. 環境レジストリを読む

<installed-skill-dir> を、この SKILL.md が格納されているディレクトリとして特定し、<installed-skill-dir>/environments.yaml を読み込みます。

利用可能な環境を、それぞれ一行の説明とともにユーザーに提示します。

2. 実験の詳細を尋ねる

ユーザーに1つのメッセージで次の項目を尋ねます。

  1. 環境:どのコンピューティング環境を使いますか?(environments.yaml にある選択肢と「その他」を表示)
  2. スクリプト/コマンド:実行するコマンドは何ですか?(例:uv run python train.py --lr 1e-3)
  3. ジョブ名:短い識別子(例:baseline-cifar10、ablation-no-attn)。デフォルト:スクリプトのベース名+日付。
  4. GPU 数:GPU は何個必要ですか?(デフォルトは環境プロファイルの値、CPU のみの場合は 0)
  5. ウォールタイム/時間制限:(SLURM のみ)どのくらいの時間が必要ですか?(デフォルトは環境プロファイルの値)
  6. Conda 環境または venv:Conda 環境の名前、または .venv のパス(該当する場合)
  7. 出力ディレクトリ:チェックポイント/結果の保存先(デフォルト:outputs/<job-name>/)
  8. 特記事項:追加の環境変数、アレイジョブ、特定の GPU タイプ、PVC マウント(RunAI)など

引数として --env、--script、--name、または --gpus が渡されている場合は、該当する回答にあらかじめ入力します。

3. プロジェクトのルートを特定する
git rev-parse --show-toplevel 2>/dev/null || pwd

短い Git コミットハッシュも取得します。

git rev-parse --short HEAD 2>/dev/null || echo "no-git"
4. ジョブスクリプトを生成する

環境の種類に応じて処理します。

type: slurm(ibex、uw、または任意の SLURM クラスター)

<installed-skill-dir>/templates/slurm_job.sh から SLURM テンプレートを読み込みます。

すべての {PLACEHOLDER} 変数に値を入力します。

プレースホルダー値
{PROJECT}プロジェクトのディレクトリ名
{ENV_NAME}環境キー(例:ibex)
{ENV_DISPLAY}プロファイルに記載された表示名
{DATE}今日の日付 YYYY-MM-DD
{COMMIT}短い Git SHA
{JOB_NAME}ユーザー指定のジョブ名
{SCRIPT_NAME}生成するスクリプトのファイル名
{PARTITION}環境プロファイルのデフォルト値(またはユーザー指定値)
{CPUS}プロファイルの cpus_per_task(またはユーザー指定値)
{GPUS}ユーザー指定の GPU 数
{MEM}プロファイルのデフォルト値(またはユーザー指定値)
{WALLTIME}ユーザー指定値またはプロファイルのデフォルト値
{LOG_DIR}outputs/logs/<job-name>
{OUTPUT_DIR}outputs/<job-name>
{PROJECT_ROOT}プロジェクトルートの絶対パス
{CONDA_ENV}ユーザー指定の環境名
{RUN_COMMAND}ユーザー指定のコマンド
{SCRATCH}環境プロファイルに記載されたスクラッチパス

環境プロファイルの common_modules に基づいて、該当する module load 行のコメントを解除します。 ユーザーの回答に基づいて、conda activate または source .venv/activate の行のコメントを解除します。 環境プロファイルにスクラッチパスがある場合は、TMPDIR ブロックのコメントを解除します。

出力パス:jobs/<job-name>.sh

type: runai (runai プロファイル)

<installed-skill-dir>/templates/runai_job.sh から RunAI テンプレートを読み込みます。

プレースホルダーに値を設定します。

プレースホルダー値
{PROJECT}プロジェクトディレクトリ名
{DATE}今日の日付
{COMMIT}git の短縮 SHA
{JOB_NAME}ユーザー指定のジョブ名
{SCRIPT_NAME}生成されたスクリプトのファイル名
{IMAGE}環境プロファイルの default_image から取得(ユーザーに確認)
{RUNAI_PROJECT}環境プロファイルの project から取得
{GPUS}GPU 数
{CPUS}プロファイルのデフォルト値から取得した CPU 数
{MEM}プロファイルのデフォルト値から取得したメモリ
{PVC_FLAGS}プロファイルの pvc_mounts から生成:マウントごとに --pvc claim:path \
{RUN_COMMAND}ユーザー指定のコマンド

出力パス:jobs/<job-name>-runai.sh

type: local

<installed-skill-dir>/templates/local_run.sh からローカル用テンプレートを読み込みます。

同様にプレースホルダーに値を設定します。適切に conda/venv の有効化をコメント解除します。

出力パス:jobs/<job-name>-local.sh

type: other / unknown

ユーザーが environments.yaml にない環境を指定した場合:

  1. 次のように尋ねます:「どのスケジューラーを使用していますか?(slurm / runai / other)」
  2. SLURM 互換の場合:ユーザーが提供した情報を使って SLURM テンプレートを使用します。
  3. まったく新しい環境の場合:最小限の汎用ラッパーを生成し、何を入力すべきか説明します。
  4. 次のように提案します:「今後使えるよう、この環境を environments.yaml に追加しますか?」
5. ジョブスクリプトを作成してプレビューする

プレビューまたは送信の前に、ジョブスクリプト用ディレクトリ、ログディレクトリ、出力ディレクトリを作成します:

mkdir -p <project-root>/jobs
mkdir -p <project-root>/outputs/logs/<job-name>
mkdir -p <output-dir>

値を設定したスクリプトを jobs/<job-name>.sh(または -runai.sh/-local.sh)に書き込みます。

生成したスクリプト全体をユーザーに表示し、確認してもらいます。

5.1 生成したシェルスクリプトのチェックゲートを実行する

ジョブスクリプトを書き込んだ後、起動を提案する前に、ツールが利用可能な場合は変更を加えないシェルチェックゲートを実行します:

command -v shellcheck >/dev/null && shellcheck jobs/<job-name>.sh || true
command -v shfmt >/dev/null && shfmt -d jobs/<job-name>.sh || true
bash -n jobs/<job-name>.sh

各ゲートについて、成功、失敗、またはツールがインストールされていないためスキップしたかを報告します。bash -n の失敗は、起動前に解決すべきブロッカーとして扱います。プロジェクトのポリシーで必須とされていない限り、shellcheck と shfmt -d の失敗は警告として扱います。

shfmt -w を通知せずに実行してはいけません。フォーマットが要求されている場合、またはポリシーで必須の場合は、shfmt -w jobs/<job-name>.sh を実行し、送信前に差分を確認します。

6. 送信コマンドを表示して起動するか尋ねる

環境に合わせて、送信に使う正確なコマンドを表示します:

SLURM(Ibex / UW など)
# If you're already on the login node:
sbatch jobs/<job-name>.sh

# If submitting from your local machine to a server (requires ssh access):
scp jobs/<job-name>.sh <ssh-alias>:<project-root>/jobs/
ssh <ssh-alias> "cd <project-root> && mkdir -p outputs/logs/<job-name> <output-dir> jobs && sbatch jobs/<job-name>.sh"

# Monitor:
squeue -u $USER
sacct -j <jobid> --format=JobID,State,Elapsed,AllocGRES
tail -f outputs/logs/<job-name>/slurm-<jobid>.out
RunAI
bash jobs/<job-name>-runai.sh

# Monitor:
runai list
runai logs <job-name> -f
ローカル
# Attached (output in terminal):
bash jobs/<job-name>-local.sh

# Detached in tmux:
tmux new-session -d -s <job-name> "bash jobs/<job-name>-local.sh"
tmux attach -t <job-name>

# Background with nohup:
nohup bash jobs/<job-name>-local.sh &

次のように尋ねます:「送信コマンドを今すぐ実行しますか?」

  • はい、かつローカルの場合:コマンドを直接実行します。
  • はい、かつサーバーの場合:scp + ssh sbatch コマンドを実行します(SSH キー認証が設定済みである必要があります)。
  • いいえの場合:スクリプトは jobs/ に保存済みで、送信できる状態であることをユーザーに伝えます。
7. jobs インデックスへの追加を提案する(任意)

jobs/README.md または jobs/index.md が存在する場合は、1 行のエントリーを追記するか提案します:

| {DATE} | {JOB_NAME} | {ENV_NAME} | {COMMIT} | {RUN_COMMAND_BRIEF} |

リポジトリが init-python-project のコード証拠レイアウトに従っている場合は、次の場所に短い実行ポインターを作成または更新することも提案します:

docs/runs/<DATE>-<job-name>.md

このファイルには、コマンド、設定、コミット、出力パス、想定されるメトリック、監視コマンドを記載します。生ログは記載しないでください。

8. プロジェクトメモリが存在する場合は更新する

リポジトリに memory/ または worktree の .agent/worktree-status.md がある場合は、検証済みの実行ポインターのみを更新します。

  • memory/evidence-board.md:ジョブスクリプトのパス、コミット、コマンド、出力ディレクトリ、ステータスを含め、リンクされた EXP-### を追加または更新します。ステータスは planned、submitted、running のいずれかを、検証済みの場合に限り設定します
  • memory/provenance-board.md:実行ポインターの、予定済みまたは利用可能なプロベナンスのみを追加します。出力を確認するまでは、最終メトリクスを検証済みとしてマークしないでください
  • docs/runs/:コードリポジトリでその規約が使われている場合は、小さな実行ポインターを書き込みます
  • memory/action-board.md:起動アクションを doing にするか、監視アクションを作成します
  • memory/handoff-board.md:別のモジュールが実行出力を利用することが想定される場合に限り、監視/取得/報告のハンドオフを作成します
  • memory/current-status.md:判明している最新のジョブと、次に確認すべき内容を記録します
  • <worktree>/.agent/worktree-status.md:実行を worktree の目的と終了条件に関連付けます

キューの状態、ジョブの成功、最終メトリクス値は、このセッションで検証されていない限り、永続的な事実として保存しないでください。監視タスクには needs-verification を使用します。


環境リファレンス

すべての環境は environments.yaml で定義されています。現在把握されている環境は次のとおりです。

キー種類クラスター備考
locallocal—現在のマシン、tmux/nohup
ibexslurmKAUST Ibexilogin.ibex.kaust.edu.sa。gpu/batch/himem パーティション
uwslurmUW HPCプレースホルダー — 実際の詳細を environments.yaml に更新してください
runairunaiEPFL RunAIKubernetes。プロジェクト/イメージを environments.yaml に更新してください
新しい環境の追加

<installed-skill-dir>/environments.yaml を編集し、次のブロックを追加します。

my-cluster:
  type: slurm                       # or runai / local
  display_name: "My University HPC"
  login_node: "login.cluster.edu"
  ssh_alias: mycluster
  scheduler: slurm
  partitions:
    gpu:
      name: gpu
      flag: "--partition=gpu"
      gpu_flag: "--gres=gpu:{count}"
      max_gpus_per_job: 4
  defaults:
    partition: gpu
    gpus: 1
    cpus_per_task: 4
    mem: "32G"
    walltime: "12:00:00"
    max_walltime: "48:00:00"
  storage:
    home: "/home/{user}"
    scratch: "/scratch/{user}"
  module_system: lmod
  common_modules:
    - "cuda/12.1"
    - "python/3.11"
  notes: "..."

再現性に関する規約

生成されるすべてのジョブスクリプトには、次の内容が含まれます。

  • ヘッダーと環境変数(GIT_COMMIT)としての Git コミットハッシュ
  • 構造化された出力ディレクトリ:チェックポイント用の outputs/<job-name>/、ログ用の outputs/logs/<job-name>/
  • 再実行時に上書きされない タイムスタンプ付きログファイル
  • ジョブ配列と後続のスクリプトで失敗を検出できるようにする 終了コードの伝播

jobs/ ディレクトリは git にコミットしてください(スクリプトは小さなテキストファイルです)。実際の出力は通常 .gitignore の対象となる outputs/ に保存します。


実行例

/run-experiment                                              # interactive wizard
/run-experiment --env ibex --script train.py --gpus 2
/run-experiment --env local --script eval.py --name eval-baseline
/run-experiment --env runai --gpus 4 --name big-run
/run-experiment --env ibex --script sweep.py --name sweep --gpus 1

よくあるパターン

ジョブ配列(SLURM)— ハイパーパラメーターのスイープ

ユーザーが「N 個の設定をスイープしたい」と言った場合:

  1. スイープ設定または設定ファイル(例:N 個のエントリーを含む configs/sweep.yaml)を尋ねます。
  2. スクリプトに #SBATCH --array=0-{N-1}%{max_concurrent} を追加します。
  3. 実行コマンドに --config configs/sweep.yaml --config-idx $SLURM_ARRAY_TASK_ID を追加します。
  4. 出力ディレクトリ:outputs/<job-name>/$SLURM_ARRAY_TASK_ID/
マルチ GPU(DDP)

GPU が 2 台以上で、環境が SLURM の場合:

  • --ntasks-per-node={GPUS} ディレクティブを追加します
  • コマンドを torchrun --nproc_per_node={GPUS} または srun python -m torch.distributed.launch でラップします
  • 使用する分散ランチャーをユーザーに尋ねます
対話型セッション(デバッグ)

ユーザーが対話形式でデバッグしたい場合(バッチジョブを送信しない場合):

Ibex:

srun --partition=gpu --gres=gpu:1 --cpus-per-task=4 --mem=32G --time=2:00:00 --pty bash

RunAI:

runai submit <name> --image <image> --gpu 1 --interactive --stdin -- bash
runai bash <name>

スクリプトファイルを作成せず、このコマンドを直接生成します。

コメント