Auto-sync: 2026-06-27 15:04:36 (part 3)
Browse files- scripts/eval_maniskill_policy_rollout.py +49 -4
- scripts/slurm/eval_h16_field_sweep.sbatch +19 -4
- scripts/slurm/eval_maniskill_policy_rollout.sbatch +10 -0
- scripts/slurm/summarize_h16_field_sweep.sbatch +6 -7
- scripts/slurm/summarize_h16_lattice_rollout.sbatch +1 -7
- scripts/slurm/summarize_h16_policy_ckpt.sbatch +13 -11
- tests/test_maniskill_policy_rollout.py +150 -0
scripts/eval_maniskill_policy_rollout.py
CHANGED
|
@@ -38,12 +38,22 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 38 |
)
|
| 39 |
parser.add_argument(
|
| 40 |
"--selection-mode",
|
| 41 |
-
choices=(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
default="policy",
|
| 43 |
help="'policy' executes the deterministic policy mean; 'field' scores model-generated "
|
| 44 |
-
"candidates with the learned interventional field; '
|
| 45 |
-
"
|
| 46 |
-
"the
|
|
|
|
|
|
|
|
|
|
| 47 |
)
|
| 48 |
parser.add_argument(
|
| 49 |
"--num-candidates",
|
|
@@ -63,6 +73,36 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 63 |
default=0,
|
| 64 |
help="Base RNG seed for candidate perturbations.",
|
| 65 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
parser.add_argument(
|
| 67 |
"--lattice-exclude-types",
|
| 68 |
default="",
|
|
@@ -87,6 +127,11 @@ def main(argv: list[str] | None = None) -> int:
|
|
| 87 |
num_candidates=args.num_candidates,
|
| 88 |
candidate_sigma=args.candidate_sigma,
|
| 89 |
selection_seed=args.selection_seed,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
lattice_exclude_types=lattice_exclude_types,
|
| 91 |
)
|
| 92 |
print(json.dumps({key: value for key, value in result.items() if key != "rows"}, indent=2))
|
|
|
|
| 38 |
)
|
| 39 |
parser.add_argument(
|
| 40 |
"--selection-mode",
|
| 41 |
+
choices=(
|
| 42 |
+
"policy",
|
| 43 |
+
"field",
|
| 44 |
+
"field_optim",
|
| 45 |
+
"lattice",
|
| 46 |
+
"retrieval_lattice",
|
| 47 |
+
"retrieval_residual",
|
| 48 |
+
),
|
| 49 |
default="policy",
|
| 50 |
help="'policy' executes the deterministic policy mean; 'field' scores model-generated "
|
| 51 |
+
"candidates with the learned interventional field; 'field_optim' additionally "
|
| 52 |
+
"optimizes model-generated candidates with projected action-space gradient ascent; "
|
| 53 |
+
"'lattice' scores the current state's CIL action lattice without reading rewards; "
|
| 54 |
+
"'retrieval_lattice' scores the nearest train-state lattice for the current state; "
|
| 55 |
+
"'retrieval_residual' translates nearest train-state counterfactual residuals around "
|
| 56 |
+
"the current policy mean before field scoring.",
|
| 57 |
)
|
| 58 |
parser.add_argument(
|
| 59 |
"--num-candidates",
|
|
|
|
| 73 |
default=0,
|
| 74 |
help="Base RNG seed for candidate perturbations.",
|
| 75 |
)
|
| 76 |
+
parser.add_argument(
|
| 77 |
+
"--field-optim-steps",
|
| 78 |
+
type=int,
|
| 79 |
+
default=0,
|
| 80 |
+
help="Projected gradient-ascent steps when selection-mode=field_optim.",
|
| 81 |
+
)
|
| 82 |
+
parser.add_argument(
|
| 83 |
+
"--field-optim-step-size",
|
| 84 |
+
type=float,
|
| 85 |
+
default=0.05,
|
| 86 |
+
help="Action-space step size for selection-mode=field_optim.",
|
| 87 |
+
)
|
| 88 |
+
parser.add_argument(
|
| 89 |
+
"--field-optim-trust-radius",
|
| 90 |
+
type=float,
|
| 91 |
+
default=0.5,
|
| 92 |
+
help="L-infinity trust radius around the policy proposal for field_optim.",
|
| 93 |
+
)
|
| 94 |
+
parser.add_argument(
|
| 95 |
+
"--field-optim-l2-penalty",
|
| 96 |
+
type=float,
|
| 97 |
+
default=0.0,
|
| 98 |
+
help="Mean squared action penalty around the policy proposal for field_optim.",
|
| 99 |
+
)
|
| 100 |
+
parser.add_argument(
|
| 101 |
+
"--retrieval-neighbors",
|
| 102 |
+
type=int,
|
| 103 |
+
default=1,
|
| 104 |
+
help="Nearest train states to use for retrieval_lattice/retrieval_residual proposals.",
|
| 105 |
+
)
|
| 106 |
parser.add_argument(
|
| 107 |
"--lattice-exclude-types",
|
| 108 |
default="",
|
|
|
|
| 127 |
num_candidates=args.num_candidates,
|
| 128 |
candidate_sigma=args.candidate_sigma,
|
| 129 |
selection_seed=args.selection_seed,
|
| 130 |
+
field_optim_steps=args.field_optim_steps,
|
| 131 |
+
field_optim_step_size=args.field_optim_step_size,
|
| 132 |
+
field_optim_trust_radius=args.field_optim_trust_radius,
|
| 133 |
+
field_optim_l2_penalty=args.field_optim_l2_penalty,
|
| 134 |
+
retrieval_neighbors=args.retrieval_neighbors,
|
| 135 |
lattice_exclude_types=lattice_exclude_types,
|
| 136 |
)
|
| 137 |
print(json.dumps({key: value for key, value in result.items() if key != "rows"}, indent=2))
|
scripts/slurm/eval_h16_field_sweep.sbatch
CHANGED
|
@@ -14,8 +14,9 @@
|
|
| 14 |
set -euo pipefail
|
| 15 |
|
| 16 |
# Field-guided h=16 rollout sweep.
|
| 17 |
-
# Each job evaluates one seed/config pair by
|
| 18 |
-
#
|
|
|
|
| 19 |
|
| 20 |
PROJECT_DIR="${PROJECT_DIR:-$SLURM_SUBMIT_DIR}"
|
| 21 |
SCRATCH_ROOT="/scratch/$USER/dovla"
|
|
@@ -43,6 +44,11 @@ DATASET="${DATASET:-$SCRATCH_ROOT/experiments/six_task_h16_collection}"
|
|
| 43 |
SOURCE_RUN_ROOT="${SOURCE_RUN_ROOT:-$SCRATCH_ROOT/experiments/dovla_h16_rollout_runs}"
|
| 44 |
SOURCE_OBJECTIVE="${SOURCE_OBJECTIVE:-}"
|
| 45 |
CHECKPOINT_NAME="${CHECKPOINT_NAME:-best.pt}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
if [[ -z "${CHECKPOINT:-}" ]]; then
|
| 47 |
if [[ -n "$SOURCE_OBJECTIVE" ]]; then
|
| 48 |
CHECKPOINT="$SOURCE_RUN_ROOT/$SOURCE_OBJECTIVE/seed_$SEED/$CHECKPOINT_NAME"
|
|
@@ -75,6 +81,11 @@ echo "Seed: $SEED"
|
|
| 75 |
echo "Candidates: $NUM_CANDIDATES"
|
| 76 |
echo "Candidate sigma: $CANDIDATE_SIGMA"
|
| 77 |
echo "Selection seed: $SELECTION_SEED"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
echo "Checkpoint: $CHECKPOINT"
|
| 79 |
echo "Dataset: $DATASET"
|
| 80 |
echo "Out: $OUT"
|
|
@@ -92,10 +103,14 @@ apptainer exec --nv --env "$ENVS" \
|
|
| 92 |
--group-batch-size "$GROUP_BATCH_SIZE" \
|
| 93 |
--sim-backend physx_cuda:0 \
|
| 94 |
--render-backend cpu \
|
| 95 |
-
--selection-mode
|
| 96 |
--num-candidates "$NUM_CANDIDATES" \
|
| 97 |
--candidate-sigma "$CANDIDATE_SIGMA" \
|
| 98 |
-
--selection-seed "$SELECTION_SEED"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
echo ""
|
| 101 |
echo "Field-guided rollout complete"
|
|
|
|
| 14 |
set -euo pipefail
|
| 15 |
|
| 16 |
# Field-guided h=16 rollout sweep.
|
| 17 |
+
# Each job evaluates one seed/config pair by generating deploy-clean action chunks,
|
| 18 |
+
# optionally optimizing them in action space with DoVLA's learned interventional field,
|
| 19 |
+
# and executing only the best.
|
| 20 |
|
| 21 |
PROJECT_DIR="${PROJECT_DIR:-$SLURM_SUBMIT_DIR}"
|
| 22 |
SCRATCH_ROOT="/scratch/$USER/dovla"
|
|
|
|
| 44 |
SOURCE_RUN_ROOT="${SOURCE_RUN_ROOT:-$SCRATCH_ROOT/experiments/dovla_h16_rollout_runs}"
|
| 45 |
SOURCE_OBJECTIVE="${SOURCE_OBJECTIVE:-}"
|
| 46 |
CHECKPOINT_NAME="${CHECKPOINT_NAME:-best.pt}"
|
| 47 |
+
SELECTION_MODE="${SELECTION_MODE:-field}"
|
| 48 |
+
FIELD_OPTIM_STEPS="${FIELD_OPTIM_STEPS:-0}"
|
| 49 |
+
FIELD_OPTIM_STEP_SIZE="${FIELD_OPTIM_STEP_SIZE:-0.05}"
|
| 50 |
+
FIELD_OPTIM_TRUST_RADIUS="${FIELD_OPTIM_TRUST_RADIUS:-0.5}"
|
| 51 |
+
FIELD_OPTIM_L2_PENALTY="${FIELD_OPTIM_L2_PENALTY:-0.0}"
|
| 52 |
if [[ -z "${CHECKPOINT:-}" ]]; then
|
| 53 |
if [[ -n "$SOURCE_OBJECTIVE" ]]; then
|
| 54 |
CHECKPOINT="$SOURCE_RUN_ROOT/$SOURCE_OBJECTIVE/seed_$SEED/$CHECKPOINT_NAME"
|
|
|
|
| 81 |
echo "Candidates: $NUM_CANDIDATES"
|
| 82 |
echo "Candidate sigma: $CANDIDATE_SIGMA"
|
| 83 |
echo "Selection seed: $SELECTION_SEED"
|
| 84 |
+
echo "Selection mode: $SELECTION_MODE"
|
| 85 |
+
echo "Field optim steps: $FIELD_OPTIM_STEPS"
|
| 86 |
+
echo "Field optim step size: $FIELD_OPTIM_STEP_SIZE"
|
| 87 |
+
echo "Field optim trust radius: $FIELD_OPTIM_TRUST_RADIUS"
|
| 88 |
+
echo "Field optim L2 penalty: $FIELD_OPTIM_L2_PENALTY"
|
| 89 |
echo "Checkpoint: $CHECKPOINT"
|
| 90 |
echo "Dataset: $DATASET"
|
| 91 |
echo "Out: $OUT"
|
|
|
|
| 103 |
--group-batch-size "$GROUP_BATCH_SIZE" \
|
| 104 |
--sim-backend physx_cuda:0 \
|
| 105 |
--render-backend cpu \
|
| 106 |
+
--selection-mode "$SELECTION_MODE" \
|
| 107 |
--num-candidates "$NUM_CANDIDATES" \
|
| 108 |
--candidate-sigma "$CANDIDATE_SIGMA" \
|
| 109 |
+
--selection-seed "$SELECTION_SEED" \
|
| 110 |
+
--field-optim-steps "$FIELD_OPTIM_STEPS" \
|
| 111 |
+
--field-optim-step-size "$FIELD_OPTIM_STEP_SIZE" \
|
| 112 |
+
--field-optim-trust-radius "$FIELD_OPTIM_TRUST_RADIUS" \
|
| 113 |
+
--field-optim-l2-penalty "$FIELD_OPTIM_L2_PENALTY"
|
| 114 |
|
| 115 |
echo ""
|
| 116 |
echo "Field-guided rollout complete"
|
scripts/slurm/eval_maniskill_policy_rollout.sbatch
CHANGED
|
@@ -44,6 +44,11 @@ SELECTION_MODE="${SELECTION_MODE:-policy}"
|
|
| 44 |
NUM_CANDIDATES="${NUM_CANDIDATES:-1}"
|
| 45 |
CANDIDATE_SIGMA="${CANDIDATE_SIGMA:-0.2}"
|
| 46 |
SELECTION_SEED="${SELECTION_SEED:-0}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
LATTICE_EXCLUDE_TYPES="${LATTICE_EXCLUDE_TYPES:-}"
|
| 48 |
if [[ -n "${LATTICE_EXCLUDE_TYPES_COLON:-}" ]]; then
|
| 49 |
LATTICE_EXCLUDE_TYPES="${LATTICE_EXCLUDE_TYPES_COLON//:/,}"
|
|
@@ -87,5 +92,10 @@ apptainer exec --nv \
|
|
| 87 |
--num-candidates "$NUM_CANDIDATES" \
|
| 88 |
--candidate-sigma "$CANDIDATE_SIGMA" \
|
| 89 |
--selection-seed "$SELECTION_SEED" \
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
--lattice-exclude-types "$LATTICE_EXCLUDE_TYPES" \
|
| 91 |
"${EXTRA_ARGS[@]}"
|
|
|
|
| 44 |
NUM_CANDIDATES="${NUM_CANDIDATES:-1}"
|
| 45 |
CANDIDATE_SIGMA="${CANDIDATE_SIGMA:-0.2}"
|
| 46 |
SELECTION_SEED="${SELECTION_SEED:-0}"
|
| 47 |
+
FIELD_OPTIM_STEPS="${FIELD_OPTIM_STEPS:-0}"
|
| 48 |
+
FIELD_OPTIM_STEP_SIZE="${FIELD_OPTIM_STEP_SIZE:-0.05}"
|
| 49 |
+
FIELD_OPTIM_TRUST_RADIUS="${FIELD_OPTIM_TRUST_RADIUS:-0.5}"
|
| 50 |
+
FIELD_OPTIM_L2_PENALTY="${FIELD_OPTIM_L2_PENALTY:-0.0}"
|
| 51 |
+
RETRIEVAL_NEIGHBORS="${RETRIEVAL_NEIGHBORS:-1}"
|
| 52 |
LATTICE_EXCLUDE_TYPES="${LATTICE_EXCLUDE_TYPES:-}"
|
| 53 |
if [[ -n "${LATTICE_EXCLUDE_TYPES_COLON:-}" ]]; then
|
| 54 |
LATTICE_EXCLUDE_TYPES="${LATTICE_EXCLUDE_TYPES_COLON//:/,}"
|
|
|
|
| 92 |
--num-candidates "$NUM_CANDIDATES" \
|
| 93 |
--candidate-sigma "$CANDIDATE_SIGMA" \
|
| 94 |
--selection-seed "$SELECTION_SEED" \
|
| 95 |
+
--field-optim-steps "$FIELD_OPTIM_STEPS" \
|
| 96 |
+
--field-optim-step-size "$FIELD_OPTIM_STEP_SIZE" \
|
| 97 |
+
--field-optim-trust-radius "$FIELD_OPTIM_TRUST_RADIUS" \
|
| 98 |
+
--field-optim-l2-penalty "$FIELD_OPTIM_L2_PENALTY" \
|
| 99 |
+
--retrieval-neighbors "$RETRIEVAL_NEIGHBORS" \
|
| 100 |
--lattice-exclude-types "$LATTICE_EXCLUDE_TYPES" \
|
| 101 |
"${EXTRA_ARGS[@]}"
|
scripts/slurm/summarize_h16_field_sweep.sbatch
CHANGED
|
@@ -12,13 +12,7 @@ set -euo pipefail
|
|
| 12 |
PROJECT_DIR="${PROJECT_DIR:-$SLURM_SUBMIT_DIR}"
|
| 13 |
RUN_ROOT="${RUN_ROOT:-/scratch/$USER/dovla/experiments/dovla_h16_field_sweep}"
|
| 14 |
SUMMARY_TAG="${SUMMARY_TAG:-field_sweep}"
|
| 15 |
-
|
| 16 |
-
if [[ -x "$PROJECT_DIR/.venv/bin/python" ]]; then
|
| 17 |
-
PYTHON="$PROJECT_DIR/.venv/bin/python"
|
| 18 |
-
else
|
| 19 |
-
PYTHON="python3"
|
| 20 |
-
fi
|
| 21 |
-
fi
|
| 22 |
export RUN_ROOT
|
| 23 |
export SUMMARY_TAG
|
| 24 |
|
|
@@ -52,6 +46,11 @@ for result_path in sorted(run_root.glob("k*_sigma*/seed_*/online_rollout.json"))
|
|
| 52 |
"selection_mode": data.get("selection_mode"),
|
| 53 |
"num_candidates": data.get("num_candidates"),
|
| 54 |
"candidate_sigma": data.get("candidate_sigma"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
"num_groups": data.get("num_groups"),
|
| 56 |
"policy_rollout_success_rate": data.get("policy_rollout_success_rate", 0.0),
|
| 57 |
"policy_rollout_progress": data.get("policy_rollout_progress", 0.0),
|
|
|
|
| 12 |
PROJECT_DIR="${PROJECT_DIR:-$SLURM_SUBMIT_DIR}"
|
| 13 |
RUN_ROOT="${RUN_ROOT:-/scratch/$USER/dovla/experiments/dovla_h16_field_sweep}"
|
| 14 |
SUMMARY_TAG="${SUMMARY_TAG:-field_sweep}"
|
| 15 |
+
PYTHON="${PYTHON:-python3}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
export RUN_ROOT
|
| 17 |
export SUMMARY_TAG
|
| 18 |
|
|
|
|
| 46 |
"selection_mode": data.get("selection_mode"),
|
| 47 |
"num_candidates": data.get("num_candidates"),
|
| 48 |
"candidate_sigma": data.get("candidate_sigma"),
|
| 49 |
+
"field_optim_steps": data.get("field_optim_steps", 0),
|
| 50 |
+
"field_optim_step_size": data.get("field_optim_step_size", 0.0),
|
| 51 |
+
"field_optim_trust_radius": data.get("field_optim_trust_radius", 0.0),
|
| 52 |
+
"field_optim_l2_penalty": data.get("field_optim_l2_penalty", 0.0),
|
| 53 |
+
"retrieval_neighbors": data.get("retrieval_neighbors", 0),
|
| 54 |
"num_groups": data.get("num_groups"),
|
| 55 |
"policy_rollout_success_rate": data.get("policy_rollout_success_rate", 0.0),
|
| 56 |
"policy_rollout_progress": data.get("policy_rollout_progress", 0.0),
|
scripts/slurm/summarize_h16_lattice_rollout.sbatch
CHANGED
|
@@ -12,13 +12,7 @@ set -euo pipefail
|
|
| 12 |
PROJECT_DIR="${PROJECT_DIR:-$SLURM_SUBMIT_DIR}"
|
| 13 |
RUN_ROOT="${RUN_ROOT:-/scratch/$USER/dovla/experiments/dovla_h16_rollout_runs}"
|
| 14 |
OUT_NAME="${OUT_NAME:-lattice_rollout.json}"
|
| 15 |
-
|
| 16 |
-
if [[ -x "$PROJECT_DIR/.venv/bin/python" ]]; then
|
| 17 |
-
PYTHON="$PROJECT_DIR/.venv/bin/python"
|
| 18 |
-
else
|
| 19 |
-
PYTHON="python3"
|
| 20 |
-
fi
|
| 21 |
-
fi
|
| 22 |
export RUN_ROOT
|
| 23 |
export OUT_NAME
|
| 24 |
|
|
|
|
| 12 |
PROJECT_DIR="${PROJECT_DIR:-$SLURM_SUBMIT_DIR}"
|
| 13 |
RUN_ROOT="${RUN_ROOT:-/scratch/$USER/dovla/experiments/dovla_h16_rollout_runs}"
|
| 14 |
OUT_NAME="${OUT_NAME:-lattice_rollout.json}"
|
| 15 |
+
PYTHON="${PYTHON:-python3}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
export RUN_ROOT
|
| 17 |
export OUT_NAME
|
| 18 |
|
scripts/slurm/summarize_h16_policy_ckpt.sbatch
CHANGED
|
@@ -14,13 +14,7 @@ RUN_ROOT="${RUN_ROOT:-/scratch/$USER/dovla/experiments/dovla_h16_policy_ckpt_run
|
|
| 14 |
OBJECTIVE="${OBJECTIVE:-base}"
|
| 15 |
OUT_NAME="${OUT_NAME:-policy_rollout.json}"
|
| 16 |
SUMMARY_TAG="${SUMMARY_TAG:-}"
|
| 17 |
-
|
| 18 |
-
if [[ -x "$PROJECT_DIR/.venv/bin/python" ]]; then
|
| 19 |
-
PYTHON="$PROJECT_DIR/.venv/bin/python"
|
| 20 |
-
else
|
| 21 |
-
PYTHON="python3"
|
| 22 |
-
fi
|
| 23 |
-
fi
|
| 24 |
export RUN_ROOT
|
| 25 |
export OBJECTIVE
|
| 26 |
export OUT_NAME
|
|
@@ -61,6 +55,11 @@ for result_path in sorted(base_dir.glob(f"seed_*/{out_name}")):
|
|
| 61 |
"selection_mode": data.get("selection_mode"),
|
| 62 |
"num_candidates": data.get("num_candidates"),
|
| 63 |
"candidate_sigma": data.get("candidate_sigma"),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
"policy_rollout_success_rate": data.get("policy_rollout_success_rate", 0.0),
|
| 65 |
"policy_rollout_progress": data.get("policy_rollout_progress", 0.0),
|
| 66 |
"oracle_success_rate": data.get("oracle_success_rate", 0.0),
|
|
@@ -121,17 +120,20 @@ lines = [
|
|
| 121 |
f"Mean progress: {summary['mean_progress']:.2%}",
|
| 122 |
f"Mean action MSE to best: {summary['mean_action_mse_to_best']:.3f}",
|
| 123 |
"",
|
| 124 |
-
"| seed | mode | k | sigma | success | progress | oracle | action MSE |",
|
| 125 |
-
"|---:|---|---:|---:|---:|---:|---:|---:|",
|
| 126 |
]
|
| 127 |
for row in rows:
|
| 128 |
lines.append(
|
| 129 |
-
"| {seed} | {mode} | {k} | {sigma:.2f} | {
|
| 130 |
-
"{progress:.2%} | {oracle:.2%} | {mse:.3f} |".format(
|
| 131 |
seed=row["seed"],
|
| 132 |
mode=row.get("selection_mode") or "policy",
|
| 133 |
k=row.get("num_candidates") or 1,
|
|
|
|
| 134 |
sigma=row.get("candidate_sigma") or 0.0,
|
|
|
|
|
|
|
| 135 |
success=row["policy_rollout_success_rate"],
|
| 136 |
progress=row["policy_rollout_progress"],
|
| 137 |
oracle=row["oracle_success_rate"],
|
|
|
|
| 14 |
OBJECTIVE="${OBJECTIVE:-base}"
|
| 15 |
OUT_NAME="${OUT_NAME:-policy_rollout.json}"
|
| 16 |
SUMMARY_TAG="${SUMMARY_TAG:-}"
|
| 17 |
+
PYTHON="${PYTHON:-python3}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
export RUN_ROOT
|
| 19 |
export OBJECTIVE
|
| 20 |
export OUT_NAME
|
|
|
|
| 55 |
"selection_mode": data.get("selection_mode"),
|
| 56 |
"num_candidates": data.get("num_candidates"),
|
| 57 |
"candidate_sigma": data.get("candidate_sigma"),
|
| 58 |
+
"field_optim_steps": data.get("field_optim_steps", 0),
|
| 59 |
+
"field_optim_step_size": data.get("field_optim_step_size", 0.0),
|
| 60 |
+
"field_optim_trust_radius": data.get("field_optim_trust_radius", 0.0),
|
| 61 |
+
"field_optim_l2_penalty": data.get("field_optim_l2_penalty", 0.0),
|
| 62 |
+
"retrieval_neighbors": data.get("retrieval_neighbors", 0),
|
| 63 |
"policy_rollout_success_rate": data.get("policy_rollout_success_rate", 0.0),
|
| 64 |
"policy_rollout_progress": data.get("policy_rollout_progress", 0.0),
|
| 65 |
"oracle_success_rate": data.get("oracle_success_rate", 0.0),
|
|
|
|
| 120 |
f"Mean progress: {summary['mean_progress']:.2%}",
|
| 121 |
f"Mean action MSE to best: {summary['mean_action_mse_to_best']:.3f}",
|
| 122 |
"",
|
| 123 |
+
"| seed | mode | k | retrieval K | sigma | opt steps | trust | success | progress | oracle | action MSE |",
|
| 124 |
+
"|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|",
|
| 125 |
]
|
| 126 |
for row in rows:
|
| 127 |
lines.append(
|
| 128 |
+
"| {seed} | {mode} | {k} | {retrieval} | {sigma:.2f} | {steps} | {trust:.2f} | "
|
| 129 |
+
"{success:.2%} | {progress:.2%} | {oracle:.2%} | {mse:.3f} |".format(
|
| 130 |
seed=row["seed"],
|
| 131 |
mode=row.get("selection_mode") or "policy",
|
| 132 |
k=row.get("num_candidates") or 1,
|
| 133 |
+
retrieval=row.get("retrieval_neighbors") or 0,
|
| 134 |
sigma=row.get("candidate_sigma") or 0.0,
|
| 135 |
+
steps=row.get("field_optim_steps") or 0,
|
| 136 |
+
trust=row.get("field_optim_trust_radius") or 0.0,
|
| 137 |
success=row["policy_rollout_success_rate"],
|
| 138 |
progress=row["policy_rollout_progress"],
|
| 139 |
oracle=row["oracle_success_rate"],
|
tests/test_maniskill_policy_rollout.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
| 2 |
|
| 3 |
import pickle
|
| 4 |
from pathlib import Path
|
|
|
|
| 5 |
|
| 6 |
import numpy as np
|
| 7 |
|
|
@@ -14,7 +15,9 @@ from dovla_cil.data.schema import (
|
|
| 14 |
StructuredEffect,
|
| 15 |
)
|
| 16 |
from dovla_cil.eval.maniskill_policy_rollout import (
|
|
|
|
| 17 |
_adapt_action_dim,
|
|
|
|
| 18 |
_load_state_archive,
|
| 19 |
_numeric_action_values,
|
| 20 |
_select_action_chunk,
|
|
@@ -220,6 +223,60 @@ def test_field_mode_scores_clamped_candidates() -> None:
|
|
| 220 |
assert index.tolist()[0] != 0
|
| 221 |
|
| 222 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
def test_lattice_mode_selects_best_scored_candidate() -> None:
|
| 224 |
import torch
|
| 225 |
|
|
@@ -288,3 +345,96 @@ def test_retrieval_lattice_mode_uses_candidate_tensor() -> None:
|
|
| 288 |
|
| 289 |
assert torch.allclose(actions, mean + offset)
|
| 290 |
assert index.tolist() == [1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
import pickle
|
| 4 |
from pathlib import Path
|
| 5 |
+
from types import SimpleNamespace
|
| 6 |
|
| 7 |
import numpy as np
|
| 8 |
|
|
|
|
| 15 |
StructuredEffect,
|
| 16 |
)
|
| 17 |
from dovla_cil.eval.maniskill_policy_rollout import (
|
| 18 |
+
_RolloutCase,
|
| 19 |
_adapt_action_dim,
|
| 20 |
+
_attach_retrieved_residual_candidates,
|
| 21 |
_load_state_archive,
|
| 22 |
_numeric_action_values,
|
| 23 |
_select_action_chunk,
|
|
|
|
| 223 |
assert index.tolist()[0] != 0
|
| 224 |
|
| 225 |
|
| 226 |
+
def test_field_optim_mode_improves_policy_mean() -> None:
|
| 227 |
+
import torch
|
| 228 |
+
|
| 229 |
+
mean = torch.zeros(1, 1, 3)
|
| 230 |
+
offset = torch.full_like(mean, 0.4)
|
| 231 |
+
model = _StubModel(torch, mean, best_offset=offset)
|
| 232 |
+
actions, index = _select_action_chunk(
|
| 233 |
+
model,
|
| 234 |
+
observations=torch.zeros(1, 3),
|
| 235 |
+
instructions=["a"],
|
| 236 |
+
torch=torch,
|
| 237 |
+
selection_mode="field_optim",
|
| 238 |
+
num_candidates=1,
|
| 239 |
+
candidate_sigma=0.0,
|
| 240 |
+
selection_seed=7,
|
| 241 |
+
field_optim_steps=8,
|
| 242 |
+
field_optim_step_size=0.1,
|
| 243 |
+
field_optim_trust_radius=0.5,
|
| 244 |
+
field_optim_l2_penalty=0.0,
|
| 245 |
+
)
|
| 246 |
+
|
| 247 |
+
assert float(((actions - (mean + offset)) ** 2).sum()) < float(
|
| 248 |
+
((mean - (mean + offset)) ** 2).sum()
|
| 249 |
+
)
|
| 250 |
+
assert index.tolist() == [0]
|
| 251 |
+
|
| 252 |
+
|
| 253 |
+
def test_field_optim_mode_respects_trust_region_and_bounds() -> None:
|
| 254 |
+
import torch
|
| 255 |
+
|
| 256 |
+
mean = torch.zeros(1, 1, 3)
|
| 257 |
+
offset = torch.full_like(mean, 10.0)
|
| 258 |
+
model = _StubModel(torch, mean, best_offset=offset)
|
| 259 |
+
actions, _index = _select_action_chunk(
|
| 260 |
+
model,
|
| 261 |
+
observations=torch.zeros(1, 3),
|
| 262 |
+
instructions=["a"],
|
| 263 |
+
torch=torch,
|
| 264 |
+
selection_mode="field_optim",
|
| 265 |
+
num_candidates=4,
|
| 266 |
+
candidate_sigma=1.0,
|
| 267 |
+
selection_seed=7,
|
| 268 |
+
field_optim_steps=8,
|
| 269 |
+
field_optim_step_size=0.2,
|
| 270 |
+
field_optim_trust_radius=0.25,
|
| 271 |
+
field_optim_l2_penalty=0.0,
|
| 272 |
+
action_low=torch.full_like(mean, -0.5),
|
| 273 |
+
action_high=torch.full_like(mean, 0.5),
|
| 274 |
+
)
|
| 275 |
+
|
| 276 |
+
assert float(actions.max()) <= 0.25
|
| 277 |
+
assert float(actions.min()) >= -0.25
|
| 278 |
+
|
| 279 |
+
|
| 280 |
def test_lattice_mode_selects_best_scored_candidate() -> None:
|
| 281 |
import torch
|
| 282 |
|
|
|
|
| 345 |
|
| 346 |
assert torch.allclose(actions, mean + offset)
|
| 347 |
assert index.tolist() == [1]
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
def test_retrieval_residual_mode_translates_residuals_around_policy_mean() -> None:
|
| 351 |
+
import torch
|
| 352 |
+
|
| 353 |
+
mean = torch.full((1, 1, 3), 0.1)
|
| 354 |
+
offset = torch.full_like(mean, 0.4)
|
| 355 |
+
model = _StubModel(torch, mean, best_offset=offset)
|
| 356 |
+
residuals = torch.stack([torch.zeros_like(mean), offset], dim=1)
|
| 357 |
+
actions, index = _select_action_chunk(
|
| 358 |
+
model,
|
| 359 |
+
observations=torch.zeros(1, 3),
|
| 360 |
+
instructions=["a"],
|
| 361 |
+
torch=torch,
|
| 362 |
+
selection_mode="retrieval_residual",
|
| 363 |
+
num_candidates=1,
|
| 364 |
+
candidate_sigma=0.0,
|
| 365 |
+
selection_seed=0,
|
| 366 |
+
action_candidates=residuals,
|
| 367 |
+
)
|
| 368 |
+
|
| 369 |
+
assert torch.allclose(actions, mean + offset)
|
| 370 |
+
assert index.tolist() == [1]
|
| 371 |
+
|
| 372 |
+
|
| 373 |
+
def test_retrieval_residual_candidates_use_knn_train_residuals() -> None:
|
| 374 |
+
def record(group_id: str, candidate_type: str, action_value: float, feature: float):
|
| 375 |
+
return SimpleNamespace(
|
| 376 |
+
group_id=group_id,
|
| 377 |
+
task_id="PickCube-v1",
|
| 378 |
+
candidate_type=candidate_type,
|
| 379 |
+
record_id=f"{group_id}-{candidate_type}-{action_value}",
|
| 380 |
+
observation_inline={"features": [feature, 0.0]},
|
| 381 |
+
action_chunk=ActionChunk(
|
| 382 |
+
representation="continuous",
|
| 383 |
+
horizon=1,
|
| 384 |
+
values=[[action_value, 0.0]],
|
| 385 |
+
),
|
| 386 |
+
)
|
| 387 |
+
|
| 388 |
+
dataset = SimpleNamespace(
|
| 389 |
+
group_ids=["train_a", "train_b", "heldout"],
|
| 390 |
+
get_group=lambda group_id: {
|
| 391 |
+
"train_a": [
|
| 392 |
+
record("train_a", "expert", 1.0, 0.0),
|
| 393 |
+
record("train_a", "near_miss", 1.2, 0.0),
|
| 394 |
+
],
|
| 395 |
+
"train_b": [
|
| 396 |
+
record("train_b", "expert", -1.0, 0.4),
|
| 397 |
+
record("train_b", "wrong_direction", -1.3, 0.4),
|
| 398 |
+
],
|
| 399 |
+
"heldout": [
|
| 400 |
+
record("heldout", "expert", 9.0, 0.1),
|
| 401 |
+
record("heldout", "near_miss", 9.9, 0.1),
|
| 402 |
+
],
|
| 403 |
+
}[group_id],
|
| 404 |
+
)
|
| 405 |
+
case = _RolloutCase(
|
| 406 |
+
group_id="heldout",
|
| 407 |
+
task_id="PickCube-v1",
|
| 408 |
+
source_dataset=Path("."),
|
| 409 |
+
state={},
|
| 410 |
+
observation={"features": [0.1, 0.0]},
|
| 411 |
+
instruction="pick",
|
| 412 |
+
oracle_score=1.0,
|
| 413 |
+
oracle_success=True,
|
| 414 |
+
expert_score=1.0,
|
| 415 |
+
expert_success=True,
|
| 416 |
+
best_action_values=[[9.9, 0.0]],
|
| 417 |
+
candidate_action_values=[],
|
| 418 |
+
candidate_types=[],
|
| 419 |
+
)
|
| 420 |
+
|
| 421 |
+
[attached] = _attach_retrieved_residual_candidates(
|
| 422 |
+
dataset,
|
| 423 |
+
[case],
|
| 424 |
+
heldout_group_ids=["heldout"],
|
| 425 |
+
obs_dim=2,
|
| 426 |
+
observation_mode="state",
|
| 427 |
+
retrieval_neighbors=2,
|
| 428 |
+
)
|
| 429 |
+
|
| 430 |
+
assert attached.candidate_source_group_id == "train_a;train_b"
|
| 431 |
+
assert attached.candidate_types == [
|
| 432 |
+
"policy_residual",
|
| 433 |
+
"residual_near_miss",
|
| 434 |
+
"policy_residual",
|
| 435 |
+
"residual_wrong_direction",
|
| 436 |
+
]
|
| 437 |
+
assert np.allclose(
|
| 438 |
+
np.asarray(attached.candidate_action_values, dtype=np.float32),
|
| 439 |
+
np.asarray([[[0.0, 0.0]], [[0.2, 0.0]], [[0.0, 0.0]], [[-0.3, 0.0]]]),
|
| 440 |
+
)
|