anhtld commited on
Commit
f6c1f86
·
verified ·
1 Parent(s): 17a2884

Auto-sync: 2026-06-27 09:54:24 (part 2)

Browse files
scripts/slurm/eval_h16_field_sweep.sbatch ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ #SBATCH --job-name=eval_h16_field
3
+ #SBATCH --account=def-yalda_gpu
4
+ #SBATCH --nodes=1
5
+ #SBATCH --ntasks=1
6
+ #SBATCH --cpus-per-task=4
7
+ #SBATCH --gres=gpu:nvidia_h100_80gb_hbm3_1g.10gb:1
8
+ #SBATCH --mem=32G
9
+ #SBATCH --time=03:00:00
10
+ #SBATCH --output=outputs/hpc/logs/%x_%A_%a.out
11
+ #SBATCH --error=outputs/hpc/logs/%x_%A_%a.err
12
+ #SBATCH --array=0-11
13
+
14
+ set -euo pipefail
15
+
16
+ # Field-guided h=16 rollout sweep.
17
+ # Each job evaluates one seed/config pair by sampling model-generated action chunks,
18
+ # scoring them with DoVLA's learned interventional field, and executing only the best.
19
+
20
+ PROJECT_DIR="${PROJECT_DIR:-$SLURM_SUBMIT_DIR}"
21
+ SCRATCH_ROOT="/scratch/$USER/dovla"
22
+ SIF="${SIF:-$SCRATCH_ROOT/containers/pytorch_2.7.1_cuda12.8.sif}"
23
+ PYTHON="${PYTHON:-$SCRATCH_ROOT/envs/maniskill/bin/python}"
24
+ NATIVE_LIBS="$SCRATCH_ROOT/native_libs/lib"
25
+ CPU_RENDER_LIBS="$SCRATCH_ROOT/cpu_render_libs"
26
+ CA_BUNDLE="$SCRATCH_ROOT/ca-bundle.crt"
27
+ VULKAN_ICD="$CPU_RENDER_LIBS/share/vulkan/icd.d/lvp_icd.x86_64.json"
28
+ RUNTIME_DIR="/tmp/$USER/dovla-field-rollout-$SLURM_JOB_ID-${SLURM_ARRAY_TASK_ID:-0}"
29
+ CACHE_DIR="/tmp/$USER/dovla-field-mesa-$SLURM_JOB_ID-${SLURM_ARRAY_TASK_ID:-0}"
30
+
31
+ SEEDS=(0 1 2)
32
+ NUM_CANDIDATES_GRID=(8 16 32 64)
33
+ CANDIDATE_SIGMA_GRID=(0.10 0.20 0.35 0.50)
34
+
35
+ CONFIG_IDX=$((SLURM_ARRAY_TASK_ID / ${#SEEDS[@]}))
36
+ SEED_IDX=$((SLURM_ARRAY_TASK_ID % ${#SEEDS[@]}))
37
+ SEED="${SEEDS[$SEED_IDX]}"
38
+ NUM_CANDIDATES="${NUM_CANDIDATES_GRID[$CONFIG_IDX]}"
39
+ CANDIDATE_SIGMA="${CANDIDATE_SIGMA_GRID[$CONFIG_IDX]}"
40
+ SELECTION_SEED=$((91000 + CONFIG_IDX * 1000 + SEED))
41
+
42
+ DATASET="${DATASET:-$SCRATCH_ROOT/experiments/six_task_h16_collection}"
43
+ CHECKPOINT="${CHECKPOINT:-$SCRATCH_ROOT/experiments/dovla_h16_rollout_runs/seed_$SEED/best.pt}"
44
+ RUN_ROOT="${RUN_ROOT:-$SCRATCH_ROOT/experiments/dovla_h16_field_sweep}"
45
+ OUT_DIR="$RUN_ROOT/k${NUM_CANDIDATES}_sigma${CANDIDATE_SIGMA}/seed_${SEED}"
46
+ OUT="$OUT_DIR/online_rollout.json"
47
+ MAX_GROUPS="${MAX_GROUPS:-700}"
48
+ GROUP_BATCH_SIZE="${GROUP_BATCH_SIZE:-16}"
49
+
50
+ module load StdEnv/2023 apptainer/1.4.5
51
+ cd "$PROJECT_DIR"
52
+ mkdir -p outputs/hpc/logs "$RUNTIME_DIR" "$CACHE_DIR" "$OUT_DIR"
53
+ chmod 700 "$RUNTIME_DIR"
54
+
55
+ export OMP_NUM_THREADS=1
56
+ export OPENBLAS_NUM_THREADS=1
57
+ export MKL_NUM_THREADS=1
58
+ export DOVLA_TORCH_THREADS=1
59
+
60
+ ENVS="LD_LIBRARY_PATH=$CPU_RENDER_LIBS/lib:$NATIVE_LIBS:/.singularity.d/libs,VK_ICD_FILENAMES=$VULKAN_ICD,VK_DRIVER_FILES=$VULKAN_ICD,XDG_RUNTIME_DIR=$RUNTIME_DIR,MESA_SHADER_CACHE_DIR=$CACHE_DIR,LIBGL_ALWAYS_SOFTWARE=1,LP_NUM_THREADS=1,SSL_CERT_FILE=$CA_BUNDLE,REQUESTS_CA_BUNDLE=$CA_BUNDLE,OMP_NUM_THREADS=1,OPENBLAS_NUM_THREADS=1,MKL_NUM_THREADS=1,DOVLA_TORCH_THREADS=1,MPLBACKEND=Agg,PYTHONDONTWRITEBYTECODE=1"
61
+
62
+ echo "=================================================="
63
+ echo "Online Rollout Evaluation - h=16 Field-Guided"
64
+ echo "Array task: $SLURM_ARRAY_TASK_ID"
65
+ echo "Seed: $SEED"
66
+ echo "Candidates: $NUM_CANDIDATES"
67
+ echo "Candidate sigma: $CANDIDATE_SIGMA"
68
+ echo "Selection seed: $SELECTION_SEED"
69
+ echo "Checkpoint: $CHECKPOINT"
70
+ echo "Dataset: $DATASET"
71
+ echo "Out: $OUT"
72
+ echo "=================================================="
73
+
74
+ apptainer exec --nv --env "$ENVS" \
75
+ -B "$PROJECT_DIR:$PROJECT_DIR" \
76
+ -B "/scratch/$USER:/scratch/$USER" \
77
+ "$SIF" "$PYTHON" scripts/eval_maniskill_policy_rollout.py \
78
+ --checkpoint "$CHECKPOINT" \
79
+ --dataset "$DATASET" \
80
+ --out "$OUT" \
81
+ --device cuda \
82
+ --max-groups "$MAX_GROUPS" \
83
+ --group-batch-size "$GROUP_BATCH_SIZE" \
84
+ --sim-backend physx_cuda:0 \
85
+ --render-backend cpu \
86
+ --selection-mode field \
87
+ --num-candidates "$NUM_CANDIDATES" \
88
+ --candidate-sigma "$CANDIDATE_SIGMA" \
89
+ --selection-seed "$SELECTION_SEED"
90
+
91
+ echo ""
92
+ echo "Field-guided rollout complete"
93
+ echo "Results: $OUT"
scripts/slurm/eval_maniskill_policy_rollout.sbatch CHANGED
@@ -18,8 +18,9 @@ DATASET="${DATASET:?Set DATASET to a ManiSkill CIL dataset or collection}"
18
  SEED="${SLURM_ARRAY_TASK_ID:-0}"
19
  RUN_ROOT="${RUN_ROOT:-}"
20
  OBJECTIVE="${OBJECTIVE:-lattice_field}"
 
21
  if [[ -n "$RUN_ROOT" ]]; then
22
- CHECKPOINT="${CHECKPOINT:-$RUN_ROOT/$OBJECTIVE/seed_$SEED/best.pt}"
23
  OUT="${OUT:-$RUN_ROOT/$OBJECTIVE/seed_$SEED/policy_rollout.json}"
24
  else
25
  CHECKPOINT="${CHECKPOINT:?Set CHECKPOINT, or RUN_ROOT for seed-indexed array runs}"
@@ -38,6 +39,10 @@ SIM_BACKEND="${SIM_BACKEND:-physx_cuda:0}"
38
  RENDER_BACKEND="${RENDER_BACKEND:-none}"
39
  ALL_GROUPS="${ALL_GROUPS:-0}"
40
  DEVICE="${DEVICE:-cuda}"
 
 
 
 
41
 
42
  module load StdEnv/2023 apptainer/1.4.5
43
  cd "$PROJECT_DIR"
@@ -73,4 +78,8 @@ apptainer exec --nv \
73
  --group-batch-size "$GROUP_BATCH_SIZE" \
74
  --sim-backend "$SIM_BACKEND" \
75
  --render-backend "$RENDER_BACKEND" \
 
 
 
 
76
  "${EXTRA_ARGS[@]}"
 
18
  SEED="${SLURM_ARRAY_TASK_ID:-0}"
19
  RUN_ROOT="${RUN_ROOT:-}"
20
  OBJECTIVE="${OBJECTIVE:-lattice_field}"
21
+ CHECKPOINT_NAME="${CHECKPOINT_NAME:-best.pt}"
22
  if [[ -n "$RUN_ROOT" ]]; then
23
+ CHECKPOINT="${CHECKPOINT:-$RUN_ROOT/$OBJECTIVE/seed_$SEED/$CHECKPOINT_NAME}"
24
  OUT="${OUT:-$RUN_ROOT/$OBJECTIVE/seed_$SEED/policy_rollout.json}"
25
  else
26
  CHECKPOINT="${CHECKPOINT:?Set CHECKPOINT, or RUN_ROOT for seed-indexed array runs}"
 
39
  RENDER_BACKEND="${RENDER_BACKEND:-none}"
40
  ALL_GROUPS="${ALL_GROUPS:-0}"
41
  DEVICE="${DEVICE:-cuda}"
42
+ SELECTION_MODE="${SELECTION_MODE:-policy}"
43
+ NUM_CANDIDATES="${NUM_CANDIDATES:-1}"
44
+ CANDIDATE_SIGMA="${CANDIDATE_SIGMA:-0.2}"
45
+ SELECTION_SEED="${SELECTION_SEED:-0}"
46
 
47
  module load StdEnv/2023 apptainer/1.4.5
48
  cd "$PROJECT_DIR"
 
78
  --group-batch-size "$GROUP_BATCH_SIZE" \
79
  --sim-backend "$SIM_BACKEND" \
80
  --render-backend "$RENDER_BACKEND" \
81
+ --selection-mode "$SELECTION_MODE" \
82
+ --num-candidates "$NUM_CANDIDATES" \
83
+ --candidate-sigma "$CANDIDATE_SIGMA" \
84
+ --selection-seed "$SELECTION_SEED" \
85
  "${EXTRA_ARGS[@]}"
scripts/slurm/summarize_h16_field_sweep.sbatch ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ #SBATCH --job-name=sum_h16_field
3
+ #SBATCH --account=def-yalda
4
+ #SBATCH --time=00:20:00
5
+ #SBATCH --cpus-per-task=1
6
+ #SBATCH --mem=2G
7
+ #SBATCH --output=outputs/hpc/logs/%x_%j.out
8
+ #SBATCH --error=outputs/hpc/logs/%x_%j.err
9
+
10
+ set -euo pipefail
11
+
12
+ PROJECT_DIR="${PROJECT_DIR:-$SLURM_SUBMIT_DIR}"
13
+ RUN_ROOT="${RUN_ROOT:-/scratch/$USER/dovla/experiments/dovla_h16_field_sweep}"
14
+ if [[ -z "${PYTHON:-}" ]]; then
15
+ if [[ -x "$PROJECT_DIR/.venv/bin/python" ]]; then
16
+ PYTHON="$PROJECT_DIR/.venv/bin/python"
17
+ else
18
+ PYTHON="python3"
19
+ fi
20
+ fi
21
+
22
+ cd "$PROJECT_DIR"
23
+ mkdir -p results outputs/hpc/logs
24
+
25
+ "$PYTHON" - <<'PY'
26
+ from __future__ import annotations
27
+
28
+ import json
29
+ import statistics
30
+ from pathlib import Path
31
+
32
+ run_root = Path(__import__("os").environ["RUN_ROOT"])
33
+ baseline = 0.2967
34
+ policy_h16 = 0.29739130434782607
35
+ rows = []
36
+
37
+ for result_path in sorted(run_root.glob("k*_sigma*/seed_*/online_rollout.json")):
38
+ data = json.loads(result_path.read_text())
39
+ cfg = result_path.parents[1].name
40
+ seed_name = result_path.parent.name
41
+ rows.append(
42
+ {
43
+ "config": cfg,
44
+ "seed": int(seed_name.split("_")[-1]),
45
+ "path": str(result_path),
46
+ "selection_mode": data.get("selection_mode"),
47
+ "num_candidates": data.get("num_candidates"),
48
+ "candidate_sigma": data.get("candidate_sigma"),
49
+ "num_groups": data.get("num_groups"),
50
+ "policy_rollout_success_rate": data.get("policy_rollout_success_rate", 0.0),
51
+ "policy_rollout_progress": data.get("policy_rollout_progress", 0.0),
52
+ "oracle_success_rate": data.get("oracle_success_rate", 0.0),
53
+ "action_mse_to_best": data.get("action_mse_to_best", 0.0),
54
+ "per_task": data.get("per_task", {}),
55
+ }
56
+ )
57
+
58
+ by_config: dict[str, list[dict]] = {}
59
+ for row in rows:
60
+ by_config.setdefault(row["config"], []).append(row)
61
+
62
+ summary_rows = []
63
+ for config, config_rows in sorted(by_config.items()):
64
+ successes = [row["policy_rollout_success_rate"] for row in config_rows]
65
+ progresses = [row["policy_rollout_progress"] for row in config_rows]
66
+ action_mses = [row["action_mse_to_best"] for row in config_rows]
67
+ summary_rows.append(
68
+ {
69
+ "config": config,
70
+ "completed_seeds": sorted(row["seed"] for row in config_rows),
71
+ "num_completed": len(config_rows),
72
+ "mean_success": statistics.mean(successes),
73
+ "std_success": statistics.stdev(successes) if len(successes) > 1 else 0.0,
74
+ "mean_progress": statistics.mean(progresses),
75
+ "mean_action_mse_to_best": statistics.mean(action_mses),
76
+ "absolute_gain_vs_h4_baseline": statistics.mean(successes) - baseline,
77
+ "absolute_gain_vs_h16_policy": statistics.mean(successes) - policy_h16,
78
+ }
79
+ )
80
+
81
+ summary_rows.sort(key=lambda row: (row["mean_success"], row["num_completed"]), reverse=True)
82
+ best = summary_rows[0] if summary_rows else None
83
+
84
+ payload = {
85
+ "run_root": str(run_root),
86
+ "baseline_h4_policy_success": baseline,
87
+ "baseline_h16_policy_success": policy_h16,
88
+ "num_result_files": len(rows),
89
+ "configs": summary_rows,
90
+ "best": best,
91
+ "rows": rows,
92
+ }
93
+
94
+ json_path = Path("results/h16_field_sweep_summary.json")
95
+ json_path.write_text(json.dumps(payload, indent=2))
96
+
97
+ lines = [
98
+ "# h=16 Field-Guided Rollout Sweep",
99
+ "",
100
+ f"Result root: `{run_root}`",
101
+ f"Completed result files: {len(rows)}",
102
+ f"Baseline h=4 policy success: {baseline:.2%}",
103
+ f"Baseline h=16 policy success: {policy_h16:.2%}",
104
+ "",
105
+ "| config | seeds | mean success | gain vs h=16 | progress | action MSE |",
106
+ "|---|---:|---:|---:|---:|---:|",
107
+ ]
108
+ for row in summary_rows:
109
+ lines.append(
110
+ "| {config} | {num_completed} | {mean_success:.2%} | {gain:+.2%} | "
111
+ "{mean_progress:.2%} | {mse:.3f} |".format(
112
+ config=row["config"],
113
+ num_completed=row["num_completed"],
114
+ mean_success=row["mean_success"],
115
+ gain=row["absolute_gain_vs_h16_policy"],
116
+ mean_progress=row["mean_progress"],
117
+ mse=row["mean_action_mse_to_best"],
118
+ )
119
+ )
120
+ if best is not None:
121
+ lines.extend(
122
+ [
123
+ "",
124
+ "Best config:",
125
+ f"- {best['config']}",
126
+ f"- mean success: {best['mean_success']:.2%}",
127
+ f"- gain vs h=16 policy: {best['absolute_gain_vs_h16_policy']:+.2%}",
128
+ ]
129
+ )
130
+
131
+ md_path = Path("results/h16_field_sweep_summary.md")
132
+ md_path.write_text("\n".join(lines) + "\n")
133
+
134
+ print(json.dumps({"best": best, "num_result_files": len(rows)}, indent=2))
135
+ print(f"Wrote {json_path}")
136
+ print(f"Wrote {md_path}")
137
+ PY
tests/test_maniskill_policy_rollout.py CHANGED
@@ -194,3 +194,27 @@ def test_field_mode_can_prefer_perturbed_candidate() -> None:
194
  # i.e. strictly away from the bare mean.
195
  assert float(((actions - mean) ** 2).sum()) > 0.0
196
  assert index.tolist()[0] != 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  # i.e. strictly away from the bare mean.
195
  assert float(((actions - mean) ** 2).sum()) > 0.0
196
  assert index.tolist()[0] != 0
197
+
198
+
199
+ def test_field_mode_scores_clamped_candidates() -> None:
200
+ import torch
201
+
202
+ mean = torch.zeros(1, 1, 3)
203
+ offset = torch.full_like(mean, 10.0)
204
+ model = _StubModel(torch, mean, best_offset=offset)
205
+ actions, index = _select_action_chunk(
206
+ model,
207
+ observations=torch.zeros(1, 3),
208
+ instructions=["a"],
209
+ torch=torch,
210
+ selection_mode="field",
211
+ num_candidates=64,
212
+ candidate_sigma=10.0,
213
+ selection_seed=7,
214
+ action_low=torch.full_like(mean, -0.5),
215
+ action_high=torch.full_like(mean, 0.5),
216
+ )
217
+
218
+ assert float(actions.max()) <= 0.5
219
+ assert float(actions.min()) >= -0.5
220
+ assert index.tolist()[0] != 0
tests/test_trainer.py CHANGED
@@ -45,9 +45,12 @@ def test_trainer_runs_one_epoch_and_writes_checkpoints(tmp_path: Path) -> None:
45
 
46
  assert (run_dir / "latest.pt").exists()
47
  assert (run_dir / "best.pt").exists()
 
48
  assert "rank_acc" in result["history"][0]["val"]
 
49
  metrics = read_json(run_dir / "metrics.json")
50
  assert "rank_acc" in metrics["history"][0]["val"]
 
51
 
52
 
53
  def test_field_utility_includes_terminal_success_bonus() -> None:
 
45
 
46
  assert (run_dir / "latest.pt").exists()
47
  assert (run_dir / "best.pt").exists()
48
+ assert (run_dir / "best_policy.pt").exists()
49
  assert "rank_acc" in result["history"][0]["val"]
50
+ assert "bc_loss" in result["best_policy"]
51
  metrics = read_json(run_dir / "metrics.json")
52
  assert "rank_acc" in metrics["history"][0]["val"]
53
+ assert "best_policy" in metrics
54
 
55
 
56
  def test_field_utility_includes_terminal_success_bonus() -> None: