Skip to content

Commit a7ed731

Browse files
committed
Make Terra PPO actor unmasked by default
1 parent 3b62637 commit a7ed731

22 files changed

Lines changed: 1060 additions & 376 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ action, max-step, and reward settings.
9696
| Entropy schedule | `ent_schedule_start=0.15`, `ent_schedule_end=0.005`, `ent_schedule_steps=9500` |
9797
| Logging/eval/checkpoints | `--log_train_interval 1`, `--log_eval_interval 100`, `--checkpoint_interval 100`, `--eval_episodes 100` |
9898
| Reward multipliers | `dump_bonus_mult=0.5`, `excavator_relocate_dumped_mult=1.5`, `excavator_relocate_dug_dirt_mult=1.5` |
99-
| Action mask | Disabled by default; opt in only with `--enable_action_mask` for the coarse action-availability mask while full-shape masked PPO is still experimental |
99+
| Action mask | Disabled in PPO training/eval; `action_mask` remains an observation/debug signal for diagnostics |
100100

101101
### Available Presets
102102

docs/EXPERIMENTS_LOG.md

Lines changed: 328 additions & 0 deletions
Large diffs are not rendered by default.

docs/EXPERIMENTS_RUNNING.md

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,62 @@
44

55
Active Slurm jobs:
66

7+
- `66756388`: running 120h-queue four-GPU ResMap64 R1/R2 terminal-reward-fix replacement from paired `codex/mask-speedup-wip` worktrees.
8+
- Script: `scripts/euler/terra_train_resmap64_phase_4gpu.sbatch`
9+
- Shape: `4` GPUs requested, `1024` envs/GPU, `4096` envs total, `num_steps=32`, `num_minibatches=32`, `total_timesteps=50000000000`.
10+
- Architecture: `--map_encoder resnet_delayed --map_feature_dim 128 --use_map_derived_channels --separate_actor_critic_trunks`.
11+
- Masking: PPO actor is unmasked by construction; current code has no action-mask train/eval switch.
12+
- R1/R2 flags: `--use_critic_affordances --include_episode_progress --edge_features_dim 10`.
13+
- Timeout semantics: pre-reset `final_observation` bootstrap for max-step timeouts; true task terminals do not bootstrap; recursive GAE stops at reset boundaries; initial `env_steps`/`episode_progress` are randomized once after startup reset to desynchronize max-step timeouts; terminal success reward is paid only on `task_done`, not on max-step timeout.
14+
- W&B: online full run `04e8dada`, `https://wandb.ai/aless-weber-eth/mixed-agents/runs/04e8dada`, entity `aless-weber-eth`, project `mixed-agents`.
15+
- Local gates on `2026-05-16 12:07 CEST`: `py_compile`, CPU `env-episode-progress` high-completion timeout terminal-zero validation, CPU `training-accounting`, CPU `synthetic-env-action-mask`, and two-agent review passed.
16+
- Local 4090 smoke result: one update, `1024` envs, `num_steps=32`, `num_minibatches=32`, ResMap64 + critic affordances, `432.00s`, `79.36` steps/s.
17+
- Current status on `2026-05-16 12:34 CEST`: running on `eu-g6-072` in `gpuhe.120h`, `5-00:00:00`, with `4 x NVIDIA GeForce RTX 4090`.
18+
- Euler gates: GPU guard passed, CUDA/cuDNN/NCCL preflight passed, and the W&B-disabled full-shape smoke completed one update in `416.07s` at `315.15` steps/s.
19+
- First online row, W&B step `0`: `entropy=2.0771589` (`ln(8)=2.07944`, not collapsed), `value_loss=0.0018877`, `explained_variance=0.0001058`, `sched/entropy_coef=0.15`, `train/timeout_rate=train/done_rate=0.002037`, `train/task_done_rate=0`, `eval/success_rate=0`, `eval/positive_terminations=0`, `eval/failure/rewards/terminal=0`, and `eval/rewards/terminal=0`.
20+
- Update `100` health on `2026-05-16 12:46 CEST`: `entropy=1.9799`, `value_loss=0.00231`, `explained_variance=0.954`, `train/timeout_rate=0.0017166`, `train/task_done_rate=0`, `eval/success_rate=0`, `eval/max_reward=0.86875`, `eval/rewards=-0.00295`, and terminal reward on eval failures remains `0`.
21+
- Update `100` local rollout probe: `docs/policy_diagnostics/04e8dada_update100_rollout_32x550_seed0_1.json`, `32` envs, `550` steps, seeds `0` and `1`, unmasked plus forced-mask. Result: `0/128` total successes across all mode/seed rollouts, invalid selections are low or zero, forced masking does not change success, final dig coverage is about `0.07-0.08`, final dump coverage is about `0.22-0.28`, and the policy still uses sparse `DO` with high `DO_NOTHING`.
22+
- Update `500` health on `2026-05-16 13:36 CEST`: W&B around step `536` has `entropy=1.8695`, `value_loss=0.00244`, `explained_variance=0.9907`, `train/timeout_rate=0.001724`, `train/task_done_rate=0`, `eval/success_rate=0`, `eval/max_reward=0.823`, `eval/rewards=-0.00046`, `eval/DO=0.0725`, `eval/DO_NOTHING %=0.156`, and terminal reward on eval failures remains `0`.
23+
- Update `500` local rollout probe: `docs/policy_diagnostics/04e8dada_update500_rollout_32x550_seed0_1.json`. Result: still `0` successes, but terrain changed in `30/32` envs in every seed/mode, terrain-change/action rose to `0.0146-0.0159`, final dig coverage rose to about `0.50`, final dump coverage rose to about `0.93-0.94`, returns improved versus update `100`, and max returns became positive up to `2.46`. Unmasked logits use more `DO` (`4.6-5.6%`) but include `4-5%` invalid selections; forced mask removes invalid selections but pushes more mass to `DO_NOTHING`.
24+
- Update `900-1000` health on `2026-05-16 14:52 CEST`: W&B now has tiny nonzero eval success rows at step `600` (`0.000244`), step `900` (`0.000244`, `eval/max_reward=4.59`), and step `1000` (`0.000977`, `eval/max_reward=5.22`).
25+
- Update `1100` eval on `2026-05-16 15:08 CEST`: success returned to `0`, `eval/max_reward=0.847`, `eval/rewards=0.000135`, `eval/DO=0.0886`, and `eval/DO_NOTHING %=0.155`. Completion still trends up (`completion=0.6467`, `core=0.8069`, `edge=0.5855` on the eval row; latest summary completion `0.666`). Treat the `600/900/1000` successes as rare discovery, not persistent learning yet.
26+
- Update `1200` eval on `2026-05-16 15:18 CEST`: tiny success returned (`eval/success_rate=0.000244`, `eval/max_reward=5.45`, `eval/rewards=0.000303`, `eval/DO=0.0829`, `eval/DO_NOTHING %=0.153`).
27+
- Update `1300` eval/latest summary at step `1320`: tiny success rose to `0.001709`, `eval/max_reward=5.54`, `eval/rewards=0.000518`, `eval/DO=0.0820`, `eval/DO_NOTHING %=0.159`, `entropy=1.8642`, `value_loss=0.00148`, `explained_variance=0.9956`, `train/timeout_rate=0.00182`, `train/task_done_rate=0`, `progress/completion=0.6711`, `core=0.8164`, and `edge=0.6129`.
28+
- Latest W&B summary at step `1474`: tiny success remains nonzero at `0.000732`, `eval/max_reward=5.44`, `eval/rewards=0.000463`, `eval/DO=0.0880`, `eval/DO_NOTHING %=0.155`, `entropy=1.8593`, `value_loss=0.00142`, `explained_variance=0.9953`, `train/timeout_rate=0.00168`, `train/task_done_rate=0`, `progress/completion=0.6883`, `core=0.8257`, and `edge=0.6370`.
29+
- Value/termination history through W&B step `1053`: no return of the old synchronized timeout spike pattern. `value_loss` median is `0.00185`, p95 `0.00264`, max `0.00627`; `explained_variance` median is `0.992`; `train/timeout_rate` stays near `1/550` (`0.00153-0.00208`); `train/task_done_rate` is mostly `0` with rare `1.5e-5` rows.
30+
- Update `1000` local rollout probe: `docs/policy_diagnostics/04e8dada_update1000_rollout_32x550_seed0_1.json`. Result: still `0/128` successes across unmasked/forced-mask seeds, so local deterministic completions are not reliable yet. Several behavior metrics moved in the useful direction versus update `500`: unmasked `DO` is about `7.4%`, invalid raw selections are down to about `1.9-2.6%`, terrain-change/action rose to `0.021-0.025`, and final dig coverage rose to about `0.59-0.63`; terrain changed in `27-29/32` envs and max returns remain positive up to `1.56`. Forced masking still removes invalid selections but lowers `DO` to about `4.9%` and increases `DO_NOTHING` to about `20-21%`, so re-enabling a naive action mask is not yet the obvious rescue.
31+
- Update `1000` failure summary: final undug fraction is still high at about `0.37-0.41`. Positive moved dirt exists in `26/32` seed-0 failures and `29/32` seed-1 failures; within those positive-dirt failures, only about `1.0-2.7%` of moved dirt is off the dump zones, and all positive-dirt failures are below the simple `<=20%` off-dump threshold. `8-10/32` envs are still loaded at timeout. Current local evidence points more to unfinished digging/sequence completion than to wrong-place dumping, but it does not prove every failed env completed dumping.
32+
- Latest rolling-checkpoint probe at W&B step about `1258`: `docs/policy_diagnostics/04e8dada_latest_step1258_rollout_32x550_seed0_1.json`, `0/128` successes. It improves the final state versus update `1000`: avg returns are about `-0.34` to `-0.06`, final dig coverage is about `0.65-0.70`, final dump coverage about `0.89-0.97`, final undug fraction about `0.30-0.35`, off-dump moved dirt about `0.4-1.4%`, and loaded-at-timeout is `0-1/32`. The concern is action distribution: unmasked `DO` fell to `4.1-4.8%`, forced-mask `DO` fell to `2.2-2.3%`, and `DO_NOTHING` rose to `27-43%`, so the policy is improving final maps but may be drifting toward too much waiting.
33+
- Stochastic rolling-checkpoint probe: `docs/policy_diagnostics/04e8dada_latest_step1258_stochastic_rollout_32x550_seed0_1.json`, unmasked only, `0/64` successes. This better matches W&B eval action sampling: `DO=8.0-8.1%`, `DO_NOTHING=15.2-15.7%`, entropy `1.88`, invalid selections about `7.1-7.3%`. Final maps are closer than argmax: final dig coverage `0.74-0.77`, dump coverage `0.995`, final undug fraction `0.23-0.26`, no loaded-at-timeout failures, and off-dump moved dirt `0.4-0.5%`. The W&B-comparable bottleneck is still finishing the remaining dig, not dumping placement or entropy collapse.
34+
- Clean-baseline stochastic comparison: `docs/policy_diagnostics/clean_baseline_stochastic_rollout_32x550_seed0_1.json` succeeds `12-14/32` per seed on the same local probe. It reaches final dig coverage `0.89-0.90`, final undug fraction `0.095-0.112`, terrain-change/action `0.058-0.064`, low invalid selection `0.3-0.8%`, and near-deterministic entropy `0.03-0.04`. Current `04e8dada` has similar raw `DO` in stochastic mode, but only about half the productive terrain-change/action and much more remaining dig.
35+
- Early checkpoint preservation: `train_mixed.py` now keeps additional snapshots at updates `0`, `100`, `500`, `1000`, `2000`, `5000`, and `10000` in addition to the rolling checkpoint.
36+
- Logs once started: `/cluster/home/lterenzi/codex_terra_edge_validation/logs/66756388_resmap64_phase_4gpu.out`.
37+
- Next health checks: monitor update `2000`, whether the tiny `600/900/1000` success rows become persistent, value-loss/explained-variance spikes, entropy trend, `DO` rising toward historical healthy levels, `DO_NOTHING` falling, and early checkpoints at updates `2000`, `5000`, and `10000`.
38+
39+
Recently cancelled:
40+
41+
- `66670662`: online W&B four-GPU ResMap64 R1/R2 staggered-timeout run, W&B `xxf7eoap`.
42+
- Cancelled on `2026-05-16 12:05 CEST` after `12:58:11` on `eu-g4-019`.
43+
- Reason: latest-checkpoint diagnosis found zero success despite timeout desync; W&B showed nonzero `eval/failure/rewards/terminal` while `eval/success_rate=0`, and code paid terminal reward on `done` where `done` includes timeouts. Replaced by `66756388` with terminal reward gated on `task_done`.
44+
45+
- `66591675`: online W&B four-GPU ResMap64 R1/R2 combined-fix run, W&B `faen4uin`.
46+
- Cancelled on `2026-05-15 21:41 CEST` after `06:02:00` on `eu-g4-027`.
47+
- Reason: superseded by the staggered-start timeout fix. Diagnosis before cancellation: value-loss/explained-variance spikes remained timeout-synchronized; spike updates had `timeout_rate ~= 1/32`, `task_done_rate=0`, and high error in `train/value_loss_timeout_bucket_75_100`.
48+
49+
- `66660010`: first staggered-timeout 120h replacement.
50+
- Failed on `2026-05-15 22:11 CEST` after `00:00:48` on `eu-g4-027`.
51+
- Reason: partial code sync left remote `train.py` older than `train_mixed.py`, causing `ImportError: cannot import name 'eval_component_metrics' from 'train'`.
52+
- Fix: resynced both paired WIP trees to Euler and submitted replacement `66670662`.
53+
54+
- `66438404`: `terra-clean-ma-4x4090`, W&B/checkpoint name `terra-clean-multiagent-4x4090-autotune0-euler-pr-2026-05-13-19-49-55`.
55+
- Cancelled on `2026-05-15 15:16 CEST` after `1-19:26:22` on `eu-g4-031`.
56+
- Reason: run appeared saturated and freeing its four RTX 3090 GPUs/fairshare should help the pending R1/R2 launch.
57+
758
- `66574910`: online W&B four-GPU residual-map architecture run from paired `codex/mask-speedup-wip` worktrees.
859
- Script: `scripts/euler/terra_train_resmap64_phase_4gpu.sbatch`
960
- Shape: `4` GPUs requested, `1024` envs/GPU, `4096` envs total, `num_steps=32`, `total_timesteps=50000000000`.
1061
- Architecture: `--map_encoder resnet_delayed --map_feature_dim 128 --use_map_derived_channels --separate_actor_critic_trunks`.
11-
- Masking: explicit `--disable_action_mask`; this is an architecture run, not a mask run.
62+
- Masking: unmasked PPO actor; this is an architecture run, not a mask run.
1263
- PPO minibatching: `num_minibatches=32` to keep the residual-map gradient batch at `1024` map frames instead of the failed `2048`.
1364
- Eval/checkpointing: every `100` updates, `eval_episodes=100`, `num_rollouts_eval=550`.
1465
- W&B: online, entity `aless-weber-eth`, project `mixed-agents`.
@@ -22,6 +73,20 @@ Active Slurm jobs:
2273
- W&B run: `d1dkjojl`, `https://wandb.ai/aless-weber-eth/mixed-agents/runs/d1dkjojl`.
2374
- Euler health: GPU guard passed, CUDA/cuDNN/NCCL preflight passed, full-shape W&B-disabled smoke passed in `422.93s` at `310.04` steps/s, and the full online run is past update `300`.
2475
- Log note: W&B emits `ERROR:root:Driver not initialized (amdgpu not found in modules)` from system monitoring; this is not a training failure.
76+
- Cancelled on `2026-05-15 11:48 CEST` after `03:01:32` on `eu-g6-061`; Slurm state `CANCELLED by 542598`.
77+
- Last diagnostic read before cancellation: W&B was around update `998`; periodic value-loss spikes aligned with the episode horizon, eval terminations were still zero, and the run was too early to judge learning.
78+
79+
Combined-fix run lineage:
80+
81+
- Detailed plan: `docs/RESMAP_AFFORDANCE_TIMEOUT_PLAN.md`.
82+
- Keep the ResMap64 spatial architecture, derived map channels, separate actor/critic trunks, and `num_minibatches=32`.
83+
- Feed existing `edge_features` plus a new `episode_progress = env_steps / max_steps_in_episode` scalar to the critic trunk only.
84+
- Add training diagnostics for `task_done_rate`, `timeout_rate`, value loss by timeout bucket, and explained variance by timeout bucket.
85+
- Fix time-limit handling as a separate training semantics change: bootstrap through max-step truncations, but still zero bootstrap for true task success.
86+
- Keep actor-visible affordances as a later deployability-gated ablation; anything fed to the actor must be computable on the real robot with the same semantics.
87+
- `66591675` tested this combined R1/R2 setup without initial timeout staggering. It reached online training but was cancelled when W&B diagnostics showed value-loss spikes phase-locked to max-step timeouts.
88+
- `66670662` added startup `env_steps`/`episode_progress` randomization and fixed timeout synchronization, but still paid timeout terminal reward.
89+
- `66756388` is the active replacement and adds the terminal-reward gate fix on top of the same architecture and PPO shape.
2590

2691
Recent failed predecessor:
2792

eval.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@
22
import jax
33
import math
44
import sys
5-
from utils.models import (
6-
infer_edge_features_dim_from_model_params,
7-
infer_use_action_mask_from_train_config,
8-
load_neural_network,
9-
)
5+
from utils.models import load_neural_network, restore_checkpoint_model_config
106
from utils.helpers import load_pkl_object
117
from terra.env import TerraEnvBatch
128
from terra.actions import (
@@ -16,7 +12,6 @@
1612
TrackedActionType,
1713
)
1814
import jax.numpy as jnp
19-
from utils.action_masking import apply_action_mask
2015
from utils.utils_ppo import obs_to_model_input, wrap_action
2116
from train_mixed import MixedAgentTrainConfig
2217

@@ -96,8 +91,6 @@ def rollout_episode(
9691
if model is not None:
9792
obs_model = obs_to_model_input(timestep.observation, prev_actions, rl_config)
9893
v, logits_pi = model.apply(model_params, obs_model)
99-
if getattr(rl_config, "use_action_mask", False):
100-
logits_pi = apply_action_mask(logits_pi, obs_model[22])
10194
if deterministic:
10295
action = np.argmax(logits_pi, axis=-1)
10396
else:
@@ -268,8 +261,7 @@ def print_stats(
268261

269262
log = load_pkl_object(f"{args.run_name}")
270263
config = log["train_config"]
271-
config.edge_features_dim = infer_edge_features_dim_from_model_params(log["model"])
272-
config.use_action_mask = infer_use_action_mask_from_train_config(config, default=False)
264+
restore_checkpoint_model_config(config, log["model"])
273265
# from utils.helpers import load_config
274266
# config = load_config("agents/Terra/ppo.yaml", 22333, 33222, 5e-04, True, "")["train_config"]
275267

eval_mcts.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,8 @@
2222
import jax.random as jrandom
2323
from tensorflow_probability.substrates import jax as tfp
2424

25-
from utils.models import (
26-
infer_edge_features_dim_from_model_params,
27-
infer_use_action_mask_from_train_config,
28-
load_neural_network,
29-
)
25+
from utils.models import load_neural_network, restore_checkpoint_model_config
3026
from utils.helpers import load_pkl_object
31-
from utils.action_masking import apply_action_mask
3227
from utils.utils_ppo import obs_to_model_input, wrap_action
3328
from terra.env import TerraEnvBatch
3429
from terra.config import BatchConfig
@@ -95,8 +90,6 @@ def make_mcts_step_fn(model, env, config):
9590

9691
def apply_model(params, inp):
9792
val, logits_pi = model.apply(params, inp)
98-
if getattr(config, "use_action_mask", False):
99-
logits_pi = apply_action_mask(logits_pi, inp[22])
10093
pi = tfp.distributions.Categorical(logits=logits_pi)
10194
return val, pi
10295

@@ -319,8 +312,6 @@ def rollout_episode(
319312
rng, rng_act, rng_step = jrandom.split(rng, 3)
320313
obs_model = obs_to_model_input(timestep.observation, prev_actions, rl_config)
321314
v, logits_pi = model.apply(model_params, obs_model)
322-
if getattr(rl_config, "use_action_mask", False):
323-
logits_pi = apply_action_mask(logits_pi, obs_model[22])
324315
if deterministic:
325316
action = jnp.argmax(logits_pi, axis=-1)
326317
else:
@@ -708,8 +699,7 @@ def _fmt(x):
708699
n_envs = args.n_envs
709700
log = load_pkl_object(f"{args.run_name}")
710701
config = log["train_config"]
711-
config.edge_features_dim = infer_edge_features_dim_from_model_params(log["model"])
712-
config.use_action_mask = infer_use_action_mask_from_train_config(config, default=False)
702+
restore_checkpoint_model_config(config, log["model"])
713703
config.num_test_rollouts = n_envs
714704
config.num_devices = 1
715705
# MCTS params (only used when --use-mcts)

eval_mixed.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@
77
import jax
88
import math
99
from tqdm import tqdm
10-
from utils.models import (
11-
infer_edge_features_dim_from_model_params,
12-
infer_use_action_mask_from_train_config,
13-
load_neural_network,
14-
)
10+
from utils.models import load_neural_network, restore_checkpoint_model_config
1511
from utils.helpers import load_pkl_object
1612
from terra.env import TerraEnvBatch
1713
from terra.actions import (
@@ -22,7 +18,6 @@
2218
)
2319
from terra.config import BatchConfig
2420
import jax.numpy as jnp
25-
from utils.action_masking import apply_action_mask
2621
from utils.utils_ppo import obs_to_model_input, wrap_action
2722
from terra.state import State
2823
from tensorflow_probability.substrates import jax as tfp
@@ -149,8 +144,6 @@ def rollout_episode(
149144
if model is not None:
150145
obs_model = obs_to_model_input(timestep.observation, prev_actions, rl_config)
151146
v, logits_pi = model.apply(model_params, obs_model)
152-
if getattr(rl_config, "use_action_mask", False):
153-
logits_pi = apply_action_mask(logits_pi, obs_model[22])
154147
if deterministic:
155148
action = np.argmax(logits_pi, axis=-1)
156149
else:
@@ -621,8 +614,7 @@ def _fmt(x):
621614

622615
log = load_pkl_object(f"{args.run_name}")
623616
config = log["train_config"]
624-
config.edge_features_dim = infer_edge_features_dim_from_model_params(log["model"])
625-
config.use_action_mask = infer_use_action_mask_from_train_config(config, default=False)
617+
restore_checkpoint_model_config(config, log["model"])
626618
config.num_test_rollouts = n_envs
627619
config.num_devices = 1
628620

0 commit comments

Comments
 (0)