Tasks/Robotics/Offline RL Manipulation

Learn a TriFinger cube-pushing policy from a fixed offline dataset

Learn to push a cube from a fixed offline dataset

trifinger_offline_rl_push_refined Robotics Offline RL Manipulation
instruction.mdthis is what the agent is given

You inherit an offline reinforcement learning problem on the TriFinger robot simulator: a three-fingered robot must push a cube to a target position, and you may only learn from a fixed, pre-collected dataset of past trajectories (no live simulator interaction during training). The shipped methods/main/solver.py is a deliberately weak behavior-cloning baseline. You train a policy and save a checkpoint; a sealed verifier then reloads your checkpoint and re-runs your policy on a hidden, disjoint batch of episodes you never see (it does NOT re-train), scoring the mean return across those episodes (higher is better).

Hard Constraints

  • CRITICAL (artifact-eval timeout safety): your train() MUST persist the checkpoint to out_dir (/app/submission/model) incrementally, not only at the very end. The grader scores whatever is in /app/submission/model at the deadline; saving only at the end and hitting the timeout leaves an empty submission and scores 0. Populate it early and keep overwriting.
  • You may only edit code under /app/methods/main/; you may add sibling .py modules. The two entrypoints and their signatures must not change — the verifier imports them directly:
  • train(dataset_dir: str, out_dir: str, device: str = "cpu") -> None — train an offline-RL policy on the dataset cached in dataset_dir and save everything needed to reload it into out_dir. Any layout works as long as your own Policy.__init__ can read it back — several files, an .npz, a subdirectory, whatever you like. The verifier only checks that out_dir exists and is not empty. Naming your main checkpoint model.pt (as the shipped starter does) is suggested for consistency, not required.
  • class Policy(trifinger_rl_datasets.PolicyBase)__init__(self, action_space, observation_space, episode_length) must load your checkpoint from os.environ.get("MODEL_DIR", "/app/submission/model") (the base class signature is fixed by the upstream library, so the checkpoint path travels through this env var, not a constructor argument); get_action(self, observation) -> np.ndarray returns the 9-dim torque action for a 97-dim flat observation. No ground truth, no re-training, no network calls inside get_action.
  • Your policy must be deterministic given the observation stream — no unseeded randomness inside get_action. The verifier scores by replaying your recorded action trace on a fresh copy of each episode; nondeterminism makes the replayed score diverge from what you saw.
  • Train only on the shipped dataset; do not download or fabricate additional trajectories, and do not call the live simulator to generate new rollouts during training (this is an offline-RL task).
  • A crash or an empty checkpoint directory scores 0. Note what non-determinism actually costs you: the verifier does not run a determinism check, so a non-deterministic policy is not detected or penalised as such — instead your local evaluation and the graded value simply stop agreeing, and you have no way to tell which one is right. Also note that a crash inside a single episode only zeroes that episode (it contributes 0.0 to the mean), not the whole submission; a crash while loading your Policy zeroes everything.

The grading budget, in full — size your policy against it. You get no per-attempt feedback, so these numbers are published rather than left for you to guess:

grading run your own session / free selfcheck.py
episodes rolled out 32 sealed (hidden), then replayed once each 100 visible (selfcheck.py), plus any seeds you pick yourself
judged data scale vs. visible 0.32× the self-check pool
wall-clock, whole grading container 9000 s your session budget is 32400 s (9 h)
wall-clock, your policy's rollout phase 3600 s for all 32 episodes (~112 s/episode) none
wall-clock, the sealed replay afterwards 1800 s (does not run your code)
CPU / memory 4 cores / 4096 MB 4 cores / 16384 MB

Two consequences worth planning around. First, grading gives your policy less RAM than your own session does (4 GB vs 16 GB): a checkpoint you can train comfortably may still be too heavy to load and run at grading time — size the deployed model, not just the training job. Second, get_action is called 750 times per episode × 32 episodes = 24,000 times inside that 3600 s; a per-call cost above ~140 ms will not finish. If your policy does run out of wall clock, the episodes that already completed are still scored and the unreached ones count as return 0.0 — a slow policy degrades, it is not thrown away — but that is a floor, not a plan.

What You Have

  • /app/data/trifinger_dataset/: the visible offline dataset trifinger-cube-push-sim-mixed-v0 (~2.9M transitions of (observation, action, reward, timeout), mixed quality — expert, weak, and near-random trajectories). Load it with the standard trifinger_rl_datasets API: gym.make( "trifinger-cube-push-sim-mixed-v0", data_dir="/app/data/trifinger_dataset").unwrapped.get_dataset(). Observations are 97-dim flat vectors (robot joint state, cube pose+keypoints, goal, previous action); actions are 9-dim joint torques in [-0.397, 0.397].
  • /app/methods/main/solver.py: the weak BC starter (train() + Policy) — this directory is what gets graded, together with the checkpoint you save under /app/submission/model/. Improve it in place or replace the algorithm entirely (e.g. a genuine offline-RL method).
  • /app/trifinger_score.py: the exact seeding / env / run / replay helpers the verifier uses. Read it to see precisely how episodes are seeded and how a recorded action trace is replayed. It does not contain the metric-to-score mapping — that lives only on the sealed side. All you need to know about it is that your score rises monotonically with the mean return.
  • /app/selfcheck.py: a free, unlimited local dry-run (python /app/selfcheck.py) that trains your solver to a scratch checkpoint and reports the mean return (± standard error) on 100 visible episodes drawn from the same episode distribution as the hidden sealed batch (independent draws from one family, with no seed shared between the two pools). Use it for relative comparison — "is change A better than change B" — where it is reliable, because both sides are measured on the same fixed episodes and the episode-to-episode noise cancels. Do not read a single visible mean as a point estimate of your sealed score: at intermediate skill levels the per-episode spread is wide enough that the two pools' means can differ by ~50 return purely by sampling, in either direction. And it stops being informative at all the moment you tune against it. You may also evaluate a trained policy on episode seeds of your own choosing via /app/trifinger_score.py (seed_episode + run_policy_episode): simulator use for evaluation and model selection is allowed and encouraged; only training on simulator rollouts is forbidden.

What You Submit

Edit /app/methods/main/solver.py, keeping the train / Policy contract:

def train(dataset_dir: str, out_dir: str, device: str = "cpu") -> None:
    ...  # load the dataset, train, save a checkpoint into out_dir (checkpoint every epoch/N steps)

class Policy(PolicyBase):
    def __init__(self, action_space, observation_space, episode_length):
        ...  # load the checkpoint from os.environ.get("MODEL_DIR", "/app/submission/model")
    def get_action(self, observation):
        ...  # return a 9-dim torque action

Then run it to produce the checkpoint: python /app/methods/main/solver.py trains on the visible dataset and saves the checkpoint to /app/submission/model/. Leave both the edited solver.py and the trained checkpoint in place — there is no submit step and no per-attempt feedback; the verifier grades once at the end. The headroom over plain behavior cloning: the dataset mixes trajectories of very different quality, and a method that can tell the good transitions from the bad ones can exploit that spread — imitating everything uniformly, as plain BC does, cannot.

How It Is Judged

After your run, the verifier copies methods/main/ and /app/submission/model/ into a sealed sandbox, loads your checkpoint and re-runs your Policy.get_action() in a rollout on a HIDDEN, disjoint batch of episodes (it does NOT re-train), replays the recorded action trace on a fresh copy of each episode to independently recompute the return, and scores the mean return across the batch (higher is better). Your score rises monotonically with the mean return, so pushing the return up is always the goal. A policy that fails to load, or an empty /app/submission/model/, scores 0; an episode your policy crashes in contributes 0.0 to the mean and the rest still count. Actions must be finite 9-dim vectors — a trace containing NaN or inf is rejected outright and scores 0.

Metric

mean episode return over the 32 sealed push episodes · higher is better

Dense per-step reward summed over 750 steps per episode, replayed by a sealed scorer, then averaged.

anchorvisible setheld-outreward
Bshipped BC starter139.41169.070.00
Rreference solution373.54491.350.30
SSOTA checkpoint650.31653.830.60
Utheoretical ceiling (750 x 1.0/step)750.00750.001.00
normalisation
m <= B0
B < m <= R0.3 * (m - B) / (R - B)
R < m <= S0.3 + 0.3 * (m - R) / (S - R)
S < m <= U0.6 + 0.4 * (m - S) / (U - S)
m > U1

m = this run's held-out metric  ·  B = shipped BC starter  ·  R = reference solution  ·  S = SOTA checkpoint  ·  U = theoretical ceiling (750 x 1.0/step)

Linear in the raw metric, no log transform. One batch mean mapped once. Clamped both ends; a non-finite metric scores 0.

Rollouts

227 minwall clock
$10.46spend
13.5Mtokens
6versions, 6 kept
150 300 450 600 $0 $2.5 $5 $7.5 $10 cumulative spend on the run DEV(64) mean return, higher is better SOTA checkpoint · visible · 650.31 v0 v1 v2 v3 v4 v5
keptrevertedno scoreturning point
  1. v0Shipped starter: plain BC on all 2.88M transitions, 64-unit MLP, 1 epoch141.94 min · $1.16
  2. v1Top-25% episodes by return, relative-vector features, 3x256 LayerNorm MLPTreat the mixture as rankable: imitate only the best episodes, and feed the net cube/goal/fingertip relative vectors.529.827 min · $2.74
  3. v2Gradient budget fixed at 40k steps; keep_frac swept, 50% wins over 25%641.488 min · $4.06
  4. v3Width raised to 512; advantage weighting, input noise and 80k steps reverted664.4207 min · $9.36
  5. v4Stratified filter: top 50% within each of 8 initial cube-goal distance binsA global top-50% cut kept 0% of the episodes starting far from the goal, so the policy had never seen a hard reset.647.5227 min · $10.32
  6. v5Per-stratum rebalancing reverted; v4 config frozen as defaults and trained instratified est. only226 min · $10.20

The v4 point plotted is its h256 ablation; the submitted h512 config was chosen on a difficulty-stratified estimator, 677.3 +/- 6.7.

On the hidden set

held-out metricreward
shipped BC starter169.070.00
reference solution491.350.30
SOTA checkpoint653.830.60
theoretical ceiling (750 x 1.0/step)750.001.00
this run695.340.7727
322 minwall clock
$89.23spend
152.7Mtokens
44versions, 9 kept
200 300 400 500 600 700 $0 $20 $40 $60 $80 cumulative spend on the run dev24 mean return, higher is better SOTA checkpoint · visible · 650.31 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31 v32 v33 v34 v35 v36 v37 v38 v39 v40 v41 v42 v43 v44
keptrevertedno scoreturning point
  1. v1Shipped starter: 64x64 BC, 1 epoch, all 2.88M transitionsvisible pool only6 min · $0.77
  2. v23x256 ReLU MLP, AdamW, 10 epochs, action clipping, per-epoch checkpoints421.29812 min · $1.48
  3. v3Whole-trajectory filter: keep the 3069 episodes with return >= 500Drop whole low-return trajectories instead of reweighting transitions; the mixture, not the model, was the binding limit.542.42317 min · $2.28
  4. v4Cutoff raised to return >= 650, keeping 2720 episodes458.0419 min · $2.69
  5. v5Deterministic mean of three independently initialised 3x256 models633.57726 min · $3.90
  6. v6Ensemble widened from three members to five645.61133 min · $5.17
  7. v7Ensemble widened to seven members632.1940 min · $6.55
  8. v8Inference-time 120-degree rotation and finger-permutation averaging235.44248 min · $8.42
  9. v9Temporal smoothing, 0.8 ensemble plus 0.2 previous action631.63150 min · $8.82
  10. v10Lighter smoothing, 0.95 ensemble plus 0.05 previous action634.97551 min · $9.22
  11. v11Each ensemble member widened from 256 to 512 units640.63469 min · $13.94
  12. v12Terminal-success filter: last-100-step mean reward >= 0.8629.56576 min · $15.63
  13. v13Ensemble actions scaled by 1.05 to undo averaging shrinkage631.75278 min · $16.03
  14. v14Elementwise median instead of mean across the five members658.28280 min · $16.86
  15. v15Coordinatewise trimmed mean, dropping one min and one max647.59281 min · $17.26
  16. v16Residual target: predict the action minus the previous commanded actionModel the change from the last command rather than the absolute torque, turning the net into an increment controller.684.9188 min · $20.04
  17. v1750/50 blend of the absolute and residual five-member ensembles680.11791 min · $20.96
  18. v18Residual blend weight cut from 0.50 to 0.25658.08393 min · $21.72
  19. v19Residual ensemble retrained from scratch with seed offset 100681.702104 min · $24.93
  20. v20Permanent fallback to the absolute policy if the cube stalls by step 100681.72107 min · $26.00
  21. v21Reset-time routing on residual-vs-absolute disagreement > 0.07650.12119 min · $30.63
  22. v22RNG state saved after init so the dual-family retrain is bit-identical664.867137 min · $37.94
  23. v23Return-based loss weights, 0.5x at return 500 rising to 1.5x at 750675.556145 min · $41.37
  24. v24Residual ensemble trained only on return >= 650 trajectories661.877152 min · $44.28
  25. v25Residual training broadened to return >= 300 trajectories663.569158 min · $47.15
  26. v26Residual training stopped early at 5 epochs603.496162 min · $48.98
  27. v27Residual training extended to 15 epochs681.205170 min · $52.82
  28. v28Relational inputs: cube-goal, fingertip-cube, fingertip-goal vectorsGive the residual net translation-invariant geometry so one push generalises across cube and goal placements.688.054182 min · $58.19
  29. v29Progress router: fall back to the absolute policy at step 50 if stuck676.495197 min · $59.74
  30. v30Goal-aligned contact frame and fingertip-to-corner distances, 163 inputs684.669204 min · $60.83
  31. v31Partial residual: target is action minus 0.75x the previous action688.22220 min · $63.47
  32. v32Relational residual MLPs widened from 256 to 512 units694.19238 min · $66.69
  33. v33Loss weight doubled on the first 150 steps of each trajectory686.671245 min · $67.91
  34. v34Top 80% within 8 distance x 12 direction strata replaces the cutoff620.552251 min · $69.14
  35. v35Trajectories ranked by return + 400x initial distance, same count kept666.94257 min · $70.42
  36. v36Huber loss, beta 0.05, on the residual torques678.273262 min · $71.66
  37. v37Same ensemble retrained with seed family 200, then a ten-model mean683.374270 min · $73.66
  38. v38ReLU replaced with SiLU throughout684.776276 min · $75.04
  39. v3927 history features from one-step cube-centre and corner motion680.122284 min · $77.65
  40. v40Normalised episode time appended to the inputs687.597291 min · $79.45
  41. v41LayerNorm inserted before each ReLU495.302298 min · $81.68
  42. v42Relational inputs kept, but predicting the absolute action again672.913305 min · $83.63
  43. v43Return-conditioned training on all 3840 trajectories, 730 requested680.114312 min · $85.81
  44. v44Architecture check at load and a zero-torque fallback for bad actionsno dev24 measurement312 min · $85.91

Forty-four snapshots, $89 and 322 min. The last sixteen were all reverted, and dev24 never moved past v28 except on ablations that lost the tail.

On the hidden set

held-out metricreward
shipped BC starter169.070.00
reference solution491.350.30
SOTA checkpoint653.830.60
theoretical ceiling (750 x 1.0/step)750.001.00
this run690.800.7538
186 minwall clock
$1.44spend
7.4Mtokens
8versions, 7 kept
150 300 450 600 $0 $0.2 $0.5 $0.8 $1 cumulative spend on the run selfcheck 100-seed mean return, higher is better SOTA checkpoint · visible · 650.31 v0 v1 v2 v3 v4 v5 v6 v7
keptrevertedno scoreturning point
  1. v0Shipped starter: 64-unit BC MLP, 1 epoch, all 2.88M transitions127.30716 min · $0.11
  2. v1Filtered BC, return >= 650; 3x256 LayerNorm MLP, 5 epochsImitate only high-return episodes with a wider normalized net; the mixture, not capacity, was the binding limit.427.2824 min · $0.21
  3. v2Same filter and net, training extended from 5 to 15 epochs579.79132 min · $0.29
  4. v3Return cutoff tightened from 650 to 680476.20746 min · $0.44
  5. v4Return cutoff loosened to 620Sweep the cutoff downward instead of up: coverage of harder starts is worth more than expert purity.590.06654 min · $0.54
  6. v5Return cutoff loosened further to 580590.61563 min · $0.68
  7. v6Cutoff at 600; net widened to 4x512 LayerNorm, 20 epochs623.06380 min · $0.79
  8. v7Weight decay 1e-5 and cosine annealing added to the 4x512 recipeRegularize and anneal the widened net so it lands on a converged iterate rather than a noisy one.648.195116 min · $1.05

Eight snapshots, $1.44 and 186 min. One straight line: filter the mixture, sweep the cutoff, widen the net, fix the schedule.

On the hidden set

held-out metricreward
shipped BC starter169.070.00
reference solution491.350.30
SOTA checkpoint653.830.60
theoretical ceiling (750 x 1.0/step)750.001.00
this run689.820.7497
347 minwall clock
$97.51spend
168.5Mtokens
71versions, 9 kept
150 300 450 600 $0 $20 $40 $60 $80 cumulative spend on the run mean return on the run's own dev pool, higher is better SOTA checkpoint · visible · 650.31 v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20 v21 v22 v23 v24 v25 v26 v27 v28 v29 v30 v31 v32 v33 v34 v35 v36 v37 v38 v39 v40 v41 v42 v43 v44 v45 v46 v47 v48 v49 v50 v51 v52 v53 v54 v55 v56 v57 v58 v59 v60 v61 v62 v63 v64 v65 v66 v67 v68 v69 v70
keptrevertedno scoreturning point
  1. v0Shipped starter: 64x64 plain BC, 1 epoch, all 2.88M transitions uniformly weightedno dev panel yet8 min · $1.01
  2. v1Deterministic 24-seed dev panel evaluator added; policy and training unchanged123.83611 min · $1.51
  3. v23x256 ReLU MLP, 5 epochs, memory-efficient normalization, per-epoch checkpoints414.93315 min · $2.05
  4. v3Trajectory filter: keep the 2948 episodes with return >= 600The mixture, not the model, was the binding limit: drop whole low-return episodes instead of reweighting transitions.524.47620 min · $2.95
  5. v4Cutoff relaxed to return >= 500, keeping 3069 episodes540.8222 min · $3.33
  6. v5Cutoff tightened to return >= 650, keeping 2720 episodes413.87624 min · $3.71
  7. v6Filtered BC training doubled from 5 to 10 epochs582.58428 min · $4.44
  8. v7Filter on final-100-step mean reward >= 0.5 instead of episode return510.32732 min · $5.40
  9. v8Deterministic three-member ensemble, seeds 0/1/2, mean torque604.27337 min · $6.42
  10. v9tanh action head replaced with an unconstrained linear head549.94141 min · $7.30
  11. v10Single filtered-BC model widened from 256 to 512 units608.48445 min · $8.25
  12. v11Heterogeneous ensemble: the three 256-wide members plus the 512-wide oneMix members that fail on different starts; width diversity, not more copies of one width, is what removes collapses.628.41748 min · $8.97
  13. v12512-wide member's ensemble weight cut from 0.25 to 0.125622.81251 min · $9.71
  14. v13512-wide member weight at the 0.1875 midpoint621.60252 min · $10.09
  15. v14512-wide member weight at 0.21875624.66854 min · $10.49
  16. v15Standalone-weak 256-wide member 2 dropped from the ensemble568.05558 min · $11.96
  17. v16Exact 3-fold rotational augmentation, 6.91M transitions, single model586.91864 min · $13.57
  18. v17Return-conditioned BC on all 3840 trajectories, target return 750555.69668 min · $14.66
  19. v18Deployment target return lowered from 750 to 700 without retraining574.10270 min · $15.27
  20. v19Filtered single-model BC extended from 10 to 20 epochs533.49974 min · $16.57
  21. v20Normalized observation features clamped to [-5,5] at inference640.7976 min · $17.30
  22. v21Conservative observation clamp at [-10,10]632.59778 min · $18.32
  23. v22Test-time augmentation: 12 member/frame outputs averaged over +/-120 degrees384.44684 min · $20.18
  24. v23Action smoothing, 0.8 ensemble prediction plus 0.2 previous command599.25285 min · $20.72
  25. v24Single model trained on the torque residual from the previous command596.10188 min · $21.68
  26. v25Five-member ensemble: four absolute models plus one residual model614.53289 min · $22.21
  27. v26Residual member weight cut from 0.20 to 0.10594.95391 min · $22.75
  28. v27Hard-goal loss weights, 1x at 0.15 m initial relocation rising to 3x by 0.25 m589.63793 min · $23.73
  29. v28Ensemble enlarged from four to six with 256-wide seeds 3/4602.845103 min · $27.18
  30. v29ReLU replaced with SiLU in the filtered single-model learner535.869106 min · $28.39
  31. v30Full-data IQL: twin critics, expectile 0.7, advantage-weighted actor extraction547.979117 min · $32.54
  32. v3127 one-step cube-keypoint and object-position change features appended541.524120 min · $33.80
  33. v32Gaussian input noise at 0.02 normalized sigma during filtered BC554.06122 min · $34.83
  34. v33Weight EMA, decay 0.999, deployed instead of the final iterate587.415125 min · $36.24
  35. v34Coordinate-wise trimmed mean over the four member torques617.769127 min · $37.03
  36. v35Pre-tanh member logits averaged, then tanh applied once606.835129 min · $38.00
  37. v36Top 75% within five initial-goal-distance strata replaces the global cutoff605.328132 min · $38.17
  38. v37Stratified-filter model added as a 0.5-weight fifth member603.158135 min · $38.64
  39. v38Per-transition loss weight 0.5x at return 500 rising to 1.5x at 750536.835150 min · $40.72
  40. v39Action MSE replaced with SmoothL1/Huber loss, beta 0.05520.875152 min · $41.16
  41. v40Normalized episode phase over the 750 steps appended to the inputs508.917155 min · $41.67
  42. v41Duplicate achieved-position and constant inputs removed, 97 to 92 features514.252159 min · $42.65
  43. v42Goal minus camera cube position appended as a relative vector603.491162 min · $43.28
  44. v43Three-seed ensemble of the goal-delta models615.269168 min · $44.55
  45. v44Sticky switch to the goal-delta ensemble at step 100 if the cube has not moved628.328173 min · $45.53
  46. v45Fallback moved to step 50, gated on <5% progress and goal direction628.292174 min · $46.00
  47. v46Cube-to-fingertip and goal-to-fingertip vectors added, 118 inputs529.313177 min · $46.73
  48. v47Only the planar goal-cube displacement appended, dropping the vertical axis585.715181 min · $47.55
  49. v48Independent 512-wide BC member with seed 1601.684186 min · $48.93
  50. v49Wide seed-1 model added as a fifth equal-weight member633.907188 min · $49.73
  51. v50Fifth wide seed-1 member reduced to half weight627.373190 min · $50.25
  52. v51Independent 512-wide BC member with seed 2519.283195 min · $51.80
  53. v52D2RL-style MLP: the observation concatenated into every deeper hidden layer576.256199 min · $52.74
  54. v53Three-seed ensemble trained on the stratified top-75% slice614.52204 min · $54.17
  55. v54Global trajectory-return cutoff raised from 500 to 550496.859206 min · $55.08
  56. v55Cube displacement over the true 5-step camera cadence appended536.741210 min · $56.05
  57. v56Bottom 10% dropped within five start-distance bins, 3059 episodes kept514.84214 min · $57.35
  58. v57Adam L2 weight decay 1e-5 on the unchanged filtered BC objective424.14219 min · $58.99
  59. v58Ensemble mean torque scaled by 1.03 before clipping644.633225 min · $61.53
  60. v59Torque gain reduced to 1.01626.859227 min · $62.21
  61. v60Torque gain at the 1.02 midpoint623.08228 min · $62.91
  62. v61Ensemble medoid member emitted instead of the coordinate mean636.601232 min · $64.04
  63. v62BC pretrain, then two bounded advantage-weighted IQL refinement epochs603.5246 min · $69.15
  64. v63Three IQL-refined 256-wide actors sharing one full-data critic fit619.798255 min · $72.86
  65. v64Three IQL-refined 256-wide actors plus the unrefined 512-wide BC actorUse the offline-RL critic only as a bounded two-epoch nudge on BC-pretrained actors, keeping one unrefined actor as ballast.631.394272 min · $80.69
  66. v65The 512-wide member IQL-refined as well as the three small ones598.455285 min · $85.79
  67. v66Exact 50/50 midpoint of v64 and v11, seven networks weighted 1:1:1:1:1:1:2627.08289 min · $86.50
  68. v67Switch to the unrefined BC trio when a long push has stalled by step 100631.353302 min · $88.24
  69. v68Wide actor's ensemble weight raised from 0.25 to 0.30624.069304 min · $88.68
  70. v69IQL refinement of the three small actors shortened from two epochs to one637.404324 min · $92.39
  71. v70Parameter midpoint of the one- and two-epoch refined small actors655.211332 min · $94.03

Seventy-one snapshots, $97.51 and 347 min. v11 led for fifty versions; only the IQL-refined v64 displaced it, on 308 paired starts.

On the hidden set

held-out metricreward
shipped BC starter169.070.00
reference solution491.350.30
SOTA checkpoint653.830.60
theoretical ceiling (750 x 1.0/step)750.001.00
this run687.820.7414
97 minwall clock
-spend
-tokens
9versions, 4 kept
575 600 625 650 675 0 30 60 90 120 agent step (this harness reports no tokens or timestamps) T16 tune-seed mean return, higher is better SOTA checkpoint · visible · 650.31 v0 v1 v2 v3 v4 v5 v6 v7 v8
keptrevertedno scoreturning point
  1. v0Inherited starter: 64-unit MLP, 1 epoch, uniform BC on all 2.88M transitionsnot rolled out
  2. v1Filtered BC, return >= 620, relative features, loss weight 1 + 40*dist_xyFilter the mixture, then upweight the rare approach steps so holding does not drown out the 5% that push.643.6
  3. v2Stratified batches, half far states, 384-wide net, 16 epochs, input noise639.8
  4. v3k-NN action copy over 148k push transitions, gated to start distance > 0.145569
  5. v4L1 approach net for long pushes, gated on distance and k-NN match qualityRoute hard starts to a specialist and keep BC for the hold; the gate could not tell which of the two would fail.676.9
  6. v5Single 384-wide net, L1 loss, half of each batch from the first 80 stepsF32 holdout only
  7. v6IQL on the full 2.88M mixed set, expectile 0.8, beta 3, gamma 0.99G32 holdout only
  8. v7v1 recipe restored after the specialists failed on the unused holdoutsF32 holdout only
  9. v8Mean torque of three independently seeded v1 members, checkpointed per memberAverage independent BC modes instead of adding assumptions; it removed one collapse on each never-tuned holdout.F32 holdout only

Nine snapshots, 97 min; this harness reports no token or cost figures. Only v1-v4 were scored on T16, so the later points are blank.

On the hidden set

held-out metricreward
shipped BC starter169.070.00
reference solution491.350.30
SOTA checkpoint653.830.60
theoretical ceiling (750 x 1.0/step)750.001.00
this run670.590.6697