| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 7d2a3de commit f54c07c
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,31 +19,13 @@ jobs: | |||
| 19 | 19 | with: | |
| 20 | 20 | python-version: "3.10" | |
| 21 | 21 | ||
| 22 | - # Compile every Python file we ship. PaliGemma and AirSim imports are | ||
| 23 | - # avoided because the runner has no GPU and no upstream OpenFly-Platform | ||
| 24 | - # checkout; the syntax check still catches `SyntaxError` and | ||
| 25 | - # `IndentationError` across the whole tree. | ||
| 22 | + # Compile every Python file we ship. Isaac Sim / Isaac Lab are not | ||
| 23 | + # installed on the runner (no GPU, no Omniverse), so we don't import the | ||
| 24 | + # modules — compileall still catches `SyntaxError` / `IndentationError` | ||
| 25 | + # across the whole tree without executing any isaaclab imports. | ||
| 26 | 26 | - name: Compile Python sources | |
| 27 | 27 | run: | | |
| 28 | - python -m compileall -q \ | ||
| 29 | - openfly \ | ||
| 30 | - vla/vla_policy.py | ||
| 31 | - | ||
| 32 | - # Smoke-import the lightweight RL modules. AirSim, transformers, and | ||
| 33 | - # PaliGemma are not installed on the runner, so we only touch modules | ||
| 34 | - # that do not import the heavy stack at module load. | ||
| 35 | - - name: Import-check RL core | ||
| 36 | - run: | | ||
| 37 | - pip install --quiet numpy 'gymnasium>=1.0' | ||
| 38 | - PYTHONPATH=. python - <<'PY' | ||
| 39 | - import openfly.actions | ||
| 40 | - import openfly.episodes | ||
| 41 | - import openfly.rewards | ||
| 42 | - import openfly.rollout | ||
| 43 | - # envs module triggers gymnasium.register on import | ||
| 44 | - from openfly.envs import AirSimVLNEnv, AirSimVLNEnvConfig # noqa: F401 | ||
| 45 | - print("imports ok") | ||
| 46 | - PY | ||
| 28 | + python -m compileall -q skyvla_isaac | ||
| 47 | 29 | ||
| 48 | 30 | markdown-links: | |
| 49 | 31 | name: Markdown link check | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,197 +1,102 @@ | |||
| 1 | 1 | # SkyVLA — agent conventions | |
| 2 | 2 | ||
| 3 | - Rules for me (the agent) when working in this repo. Short and rule-focused. | ||
| 3 | + Rules for me (the agent) when working in this repo. Short and rule-focused. The | ||
| 4 | + repo is the Isaac Sim / Isaac Lab gripper-drone work in `skyvla_isaac/` — a | ||
| 5 | + free-floating quadrotor with a 4-jaw gripper doing pick-and-place (`tasks/pick_place_env.py`) | ||
| 6 | + and Gaussian-map navigation (`gs/`). Training is PPO via rsl_rl (`scripts/train.py`). | ||
| 4 | 7 | ||
| 5 | - ## W&B is on by default — don't disable it | ||
| 6 | - | ||
| 7 | - The DiT trainer (`openfly/train_subgoal_dit.py`) auto-initializes a W&B run on every launch. The API key lives at `/home/ubuntu/SkyVLA/.wandb_key` (mode 600, gitignored); the shell wrapper exports it as `WANDB_API_KEY` before invoking Python, and the trainer falls back to reading the same file if the env var is missing. | ||
| 8 | - | ||
| 9 | - Defaults: | ||
| 10 | - - project: `skyvla-subgoal-dit` | ||
| 11 | - - run name / id: `basename(out_dir)` — same run dir → same W&B run (auto-resumes via `resume="allow"`), so crash-loop relaunches stitch into one continuous series. | ||
| 12 | - - mode: `online` | ||
| 8 | + ## Environment | ||
| 13 | 9 | ||
| 14 | - **Log only measurable training progress to W&B, nothing else.** No per-step jitter, no operational counters, no constants. The dashboard exists to answer one question: "is training getting better?" Every metric you add must move the needle on that question. Specifically: | ||
| 10 | + All Isaac scripts run in the isolated `isaac` conda env (Python 3.10) and need: | ||
| 15 | 11 | ||
| 16 | - DO log: | ||
| 17 | - - **`val/cos_seen`, `val/cos_ood`** — THE metric. The whole reason we train. Per-epoch. | ||
| 18 | - - **`val/cos_gap_seen_ood`** — generalization gap (seen − ood). Near zero = generalizing. Going up = overfit. | ||
| 19 | - - **`val/best_cos`** — running max of `val/cos_seen`. Easy visual ceiling. | ||
| 20 | - - **`val/loss_seen`, `val/loss_ood`** — secondary, but worth tracking the trend. | ||
| 21 | - - **`epoch/train_cos_mean`** — denoised in-training direction quality (a leading indicator of what val_cos will be). | ||
| 22 | - - **`epoch/train_loss`** — the headline objective. | ||
| 23 | - - **`epoch/nan_skip_ratio`** — health check. > 5% means the run is fighting numerical instability and val numbers are fragile; investigate before drawing conclusions. | ||
| 24 | - - **`train/*_ema`** (per step, EMA-smoothed) — `train/loss_ema`, `train/train_cos_ema`, `train/cos_loss_ema`, `train/repa_loss_ema`. EMA half-life ~50 steps. These are how you watch training "live" — raw per-batch numbers swing too wildly (`train_cos` jitters ±0.5 batch-to-batch). | ||
| 25 | - | ||
| 26 | - DO NOT log: | ||
| 27 | - - Raw per-step metrics (use EMA instead). | ||
| 28 | - - `lr` (constant after warmup; not progress). | ||
| 29 | - - `epoch_idx`, `step_in_epoch` (already encoded in gstep on the x-axis). | ||
| 30 | - - `n_valid` per batch (debug noise). | ||
| 31 | - - Operational counters that don't move with training quality (`nan_skip_count` cumulative is debug, `nan_skip_ratio` per epoch is signal). | ||
| 32 | - - Anything with no monotonic / interpretable shape. | ||
| 12 | + ```bash | ||
| 13 | + conda activate isaac | ||
| 14 | + export OMNI_KIT_ACCEPT_EULA=YES | ||
| 15 | + export PYTHONPATH=/home/ubuntu/SkyVLA | ||
| 16 | + ``` | ||
| 33 | 17 | ||
| 34 | - If you're tempted to add a new metric, ask: "would this on a chart change what I'd do next?" If the answer is no, it goes to stdout, not W&B. | ||
| 18 | + ## W&B is on by default — don't disable it | ||
| 35 | 19 | ||
| 36 | - To turn it off for a one-shot smoke run: `--wandb_mode disabled` (or `--wandb_project ""`). Don't disable on long runs — we want the dashboard. | ||
| 20 | + `scripts/train.py` sets `logger="wandb"`, project `skyvla-isaac`. The API key | ||
| 21 | + lives at `/home/ubuntu/SkyVLA/.wandb_key` (mode 600, gitignored). **The | ||
| 22 | + `.wandb_key` file must never be committed** — `.gitignore` already covers | ||
| 23 | + `.wandb_key` and `.env.local`. If a new credential file is needed, add it to | ||
| 24 | + `.gitignore` first. | ||
| 37 | 25 | ||
| 38 | - The .wandb_key file must never be committed. .gitignore already covers `.wandb_key` and `.env.local`. If a new credential file is needed, add it to .gitignore first. | ||
| 26 | + **Log only measurable training progress to W&B, nothing else** — the dashboard | ||
| 27 | + exists to answer one question: "is training getting better?" For this task the | ||
| 28 | + metrics that matter are the real success rates (`grasp_rate`, `lift_rate`, | ||
| 29 | + `place_success`, `obj_to_goal`) plus mean episode reward. No per-step jitter, no | ||
| 30 | + constants (e.g. `lr` after warmup), no operational counters. If a metric wouldn't | ||
| 31 | + change what I'd do next on a chart, it goes to stdout, not W&B. Don't disable | ||
| 32 | + W&B on long runs — we want the dashboard. | ||
| 39 | 33 | ||
| 40 | 34 | ## After launching ANY training or eval run — ALWAYS give tail commands | |
| 41 | 35 | ||
| 42 | - **Hard rule, no exceptions.** Whenever you launch a training run, eval, ablation, or any background process that writes to a log file, immediately follow the launch confirmation with the user-runnable tail commands. The user has explicitly asked for this — they want to be able to watch progress without having to ask me where the log is. | ||
| 43 | - | ||
| 44 | - Default set to surface (adapt grep filters to whatever metrics the run produces): | ||
| 36 | + **Hard rule, no exceptions.** Whenever I launch a training run, eval, or any | ||
| 37 | + background process that writes to a log file, I immediately follow the launch | ||
| 38 | + confirmation with the user-runnable tail commands, in a small code block right | ||
| 39 | + after the "tmux session / log" lines (not buried later). Adapt the grep filters | ||
| 40 | + to whatever the run prints. | ||
| 45 | 41 | ||
| 46 | 42 | ```bash | |
| 47 | - # Live training-step lines | ||
| 48 | - tail -f <LOG> | grep -E "epoch [0-9]+ step" | ||
| 49 | - | ||
| 50 | - # Clean tail (warnings filtered) | ||
| 51 | - tail -f <LOG> | grep -vE "UserWarning|tensor_numpy|ascontiguous|FutureWarning" | ||
| 52 | - | ||
| 53 | - # Epoch summaries + saves + restarts only (the moments that matter) | ||
| 54 | - tail -f <LOG> | grep -E "epoch [0-9]+ →|saved best|periodic save|==== launch|EXIT reason" | ||
| 55 | - | ||
| 56 | - # Attach to live tmux (interactive view; Ctrl-B D to detach) | ||
| 57 | - tmux attach -t <SESS> | ||
| 43 | + tail -f <LOG> # raw progress | ||
| 44 | + tail -f <LOG> | grep -E "Iteration|reward|success" # iteration summaries + rates | ||
| 45 | + tmux attach -t <SESS> # live view (Ctrl-B then D to detach) | ||
| 46 | + tmux ls # find running sessions | ||
| 58 | 47 | ``` | |
| 59 | 48 | ||
| 60 | - For eval scripts that don't emit per-step lines, default to a simpler set — just the clean tail + a one-shot "show results so far" pattern. | ||
| 61 | - | ||
| 62 | - Phrasing: surface them in a small code block right after the "tmux session: X / log: Y" lines. Don't bury them later in the message; the user reads top-down. | ||
| 63 | - | ||
| 64 | 49 | ## Long-running training runs | |
| 65 | 50 | ||
| 66 | - **Always launch long training runs (>15 min) inside a tmux session.** Never use bare `nohup ... &` for SFT / DiT / RL training — tmux is interactively attachable, has cleaner process management, and the user explicitly asked for it so that closing their laptop never matters. | ||
| 67 | - | ||
| 68 | - **For any multi-hour DiT run, always use `--run_dir <pinned-path> --auto_resume --ckpt_every_steps 500`** so a Xid 43 / segfault / OOM doesn't lose the entire run. See the Xid 43 section below for why. | ||
| 69 | - | ||
| 70 | - Pattern (resilient, with crash-loop wrapper): | ||
| 51 | + **Always launch long training runs (>15 min) inside a tmux session.** Never use | ||
| 52 | + bare `nohup ... &` for PPO training — tmux is interactively attachable, has | ||
| 53 | + cleaner process management, and the user explicitly asked for it so closing | ||
| 54 | + their laptop never matters. Stop a run with `tmux kill-session -t <SESS>` | ||
| 55 | + (preferred over `pkill -9`). | ||
| 71 | 56 | ||
| 72 | 57 | ```bash | |
| 73 | - RUN_DIR=/home/ubuntu/SkyVLA/logs/openfly/subgoal_dit/<descriptive_name> | ||
| 74 | - SESS=<phase>_$(date +%Y%m%d_%H%M%S) | ||
| 58 | + SESS=isaac_pickplace_$(date +%Y%m%d_%H%M%S) | ||
| 75 | 59 | LOG=/tmp/${SESS}.log | |
| 76 | - | ||
| 77 | - # write a relaunch script that retries up to MAX_RESTARTS times on non-clean exit | ||
| 78 | - RELAUNCH=/tmp/${SESS}_loop.sh | ||
| 79 | - cat > "$RELAUNCH" <<EOF | ||
| 80 | - #!/bin/bash | ||
| 81 | - cd /home/ubuntu/SkyVLA | ||
| 82 | - MAX_RESTARTS=8 | ||
| 83 | - RESTART=0 | ||
| 84 | - while true; do | ||
| 85 | - RESTART=\$((RESTART+1)) | ||
| 86 | - echo "==== launch #\$RESTART at \$(date) ====" | tee -a $LOG | ||
| 87 | - ./openfly/run_train_<phase>.sh \\ | ||
| 88 | - <your args> \\ | ||
| 89 | - --ckpt_every_steps 500 \\ | ||
| 90 | - --run_dir $RUN_DIR \\ | ||
| 91 | - --auto_resume 2>&1 | tee -a $LOG | ||
| 92 | - if tail -200 $LOG | grep -q "EXIT reason=clean"; then | ||
| 93 | - LAST_EPOCH=\$(grep -oE "epoch [0-9]+ →" $LOG | tail -1 | grep -oE "[0-9]+") | ||
| 94 | - [ -n "\$LAST_EPOCH" ] && [ "\$LAST_EPOCH" -ge \$((EPOCHS-1)) ] && break | ||
| 95 | - fi | ||
| 96 | - [ \$RESTART -ge \$MAX_RESTARTS ] && break | ||
| 97 | - sleep 15 | ||
| 98 | - done | ||
| 99 | - EOF | ||
| 100 | - chmod +x "$RELAUNCH" | ||
| 101 | - tmux new-session -d -s "$SESS" "$RELAUNCH" | ||
| 60 | + tmux new-session -d -s "$SESS" \ | ||
| 61 | + "conda activate isaac && OMNI_KIT_ACCEPT_EULA=YES PYTHONPATH=/home/ubuntu/SkyVLA \ | ||
| 62 | + python skyvla_isaac/scripts/train.py --num_envs 2048 --max_iterations 1500 2>&1 | tee $LOG" | ||
| 102 | 63 | ``` | |
| 103 | 64 | ||
| 104 | - For a one-off short smoke (<15 min) where a Xid 43 just means rerunning is fine, the simpler one-line tmux is OK: | ||
| 105 | - | ||
| 106 | - ```bash | ||
| 107 | - tmux new-session -d -s "$SESS" "./openfly/run_train_<phase>.sh <args> 2>&1 | tee $LOG" | ||
| 108 | - ``` | ||
| 109 | - | ||
| 110 | - After launching, tell the user: | ||
| 111 | - - `tmux attach -t <SESS>` to view live (Ctrl-B then D to detach without killing) | ||
| 112 | - - `tail -f <LOG>` for file-based tail | ||
| 113 | - - `tmux ls` to find running sessions | ||
| 114 | - | ||
| 115 | - Stopping a run: `tmux kill-session -t <SESS>` (preferred over `pkill -9`). | ||
| 65 | + `scripts/train.py` checkpoints every `save_interval` iterations to | ||
| 66 | + `logs/isaac/drone_pick_place/`, so a crash loses at most that window — resume by | ||
| 67 | + relaunching from the latest `model_*.pt`. | ||
| 116 | 68 | ||
| 117 | 69 | ## Xid 43 on this machine | |
| 118 | 70 | ||
| 119 | - The A100 on this host throws NVIDIA Xid 43 ("GPU stopped processing" / channel reset) errors at a rate of roughly ~50% per hour of sustained training. They surface in Python as `Fatal Python error: Segmentation fault` with no preceding stack and no caught exception. They happen across PyTorch versions, model architectures, and boot cycles — confirmed by multiple entries in `sudo dmesg` / `/var/log/kern.log` dating back days. No ECC errors, no hardware fault. Suspected cause: PyTorch 2.12+cu130 binary on a system with CUDA 12.8 nvcc, causing latent issues in triton JIT or cuDNN algorithm selection. | ||
| 120 | - | ||
| 121 | - This means **any multi-hour DiT run will probably crash mid-way.** Don't fight this — design for it: | ||
| 122 | - | ||
| 123 | - 1. Pin the run directory with `--run_dir`. | ||
| 124 | - 2. Save state with `--ckpt_every_steps 500` (mid-epoch save bounds crash-loss to ~3 min on this hardware). | ||
| 125 | - 3. Auto-resume from `last.pt` with `--auto_resume`. | ||
| 126 | - 4. Wrap launch in a restart loop (see the tmux pattern above). | ||
| 127 | - | ||
| 128 | - The trainer's `last.pt` carries `epoch`, `global_step`, `step_in_epoch`, optimizer, EMA — full state. Mid-epoch resume REPLAYS the current epoch from step 0 (preserves optimizer/EMA, redoes already-seen batches; the redo cost is ~10 min and is much simpler than rewinding the DataLoader). Clean epoch boundaries advance to the next epoch. | ||
| 129 | - | ||
| 130 | - **Diagnostic output routing:** the trainer's faulthandler heartbeat (`dump_traceback_later(120, repeat=True)`) is routed to `<run_dir>/diagnostics.log`, NOT the main log. If the main log shows a thread-dump-looking block, it's the SIGTERM/SIGINT handler (one-shot at signal time) or an actual fatal — not the periodic heartbeat. Past confusion: a tail of the main log used to show repeating `Timeout (0:02:00)!` blocks every 2 min and looked like a crash; that was just the heartbeat. | ||
| 131 | - | ||
| 132 | - ## Don't rerun cu128 reinstall without authorization | ||
| 133 | - | ||
| 134 | - We diagnosed the Xid 43 issue and considered reinstalling PyTorch with cu128 wheels to match the system CUDA toolkit. The user explicitly chose **not** to do that (preferred crash-loop + auto-resume instead). Don't propose the reinstall again unless the auto-resume strategy starts failing in a new way. The reinstall has a real blast radius (PaliGemma policy, transformers version pinning, accelerate, diffusers). | ||
| 135 | - | ||
| 136 | - ## Diagnostic logging in long runs | ||
| 137 | - | ||
| 138 | - The trainer (`openfly/train_subgoal_dit.py`) already installs: | ||
| 139 | - - `faulthandler.dump_traceback_later(120, repeat=True)` — periodic stack dumps so a hang isn't silent | ||
| 140 | - - `atexit` handler printing `EXIT reason=clean|signal(N)|exception(...)` | ||
| 141 | - - SIGTERM/SIGINT trap that dumps thread stacks before exiting | ||
| 142 | - | ||
| 143 | - The shell wrapper (`openfly/run_train_subgoal_dit.sh`) sets `PYTHONUNBUFFERED=1` + `python -u` so prints flush in real time. **Don't pipe long runs through `tail -<N>` without `tee` first** — `tail` only emits its output buffer when its input closes, so a SIGTERM kills the pipe before any captured progress reaches the log. | ||
| 144 | - | ||
| 145 | - ## Val splits — never random_split | ||
| 146 | - | ||
| 147 | - For any train/val split: load `train.json` for training, `seen.json` and/or `unseen.json` for val. **Never** `random_split(full_ds, ...)` on a single split — it leaks adjacent frames of the same trajectory across train/val and inflates metrics to look-too-good. See `docs/TRAIN.md` "Gotchas" for the full history. | ||
| 148 | - | ||
| 149 | - ## val_ddim_steps | ||
| 150 | - | ||
| 151 | - Default is **4** in the trainer — matches the policy's inference (`PaliGemmaVLNPolicy.subgoal_sample_steps=4`). Past `val_cos≈0.61` numbers were measured at 20 steps and are deploy-inflated. Use 20 only as a one-off "denoising ceiling" diagnostic. | ||
| 71 | + The A100 on this host throws NVIDIA Xid 43 ("GPU stopped processing" / channel | ||
| 72 | + reset) errors at roughly ~50% per hour of sustained training. They surface in | ||
| 73 | + Python as `Fatal Python error: Segmentation fault` with no stack and no caught | ||
| 74 | + exception, across PyTorch versions and architectures — no ECC errors, no | ||
| 75 | + hardware fault. Suspected cause: a PyTorch cu130 binary on a system with CUDA | ||
| 76 | + 12.8 nvcc. **Design for it:** checkpoint often, and wrap long launches in a | ||
| 77 | + restart loop so a mid-run segfault just resumes from the latest checkpoint | ||
| 78 | + rather than losing the run. | ||
| 79 | + | ||
| 80 | + **Don't rerun the cu128 reinstall without authorization.** We diagnosed Xid 43 | ||
| 81 | + and considered reinstalling PyTorch with cu128 wheels to match the system CUDA | ||
| 82 | + toolkit; the user explicitly chose **not** to (preferred checkpoint + restart). | ||
| 83 | + Don't propose the reinstall again unless the restart strategy starts failing in | ||
| 84 | + a new way — the reinstall has a real blast radius (Isaac Lab / rsl_rl pinning). | ||
| 152 | 85 | ||
| 153 | 86 | ## Disk hygiene | |
| 154 | 87 | ||
| 155 | - Each DiT run writes `best.pt` (~2.5 GB) + `last.pt` (~10 GB). `/dev/vda1` is shared with `/tmp` and 95%+ full on this machine. **Before launching a multi-epoch run**, check `df -h /tmp` has ≥30 GB free. If not, delete old `last.pt` files first: | ||
| 156 | - | ||
| 157 | - ```bash | ||
| 158 | - find /home/ubuntu/SkyVLA/logs/openfly/subgoal_dit -name "last.pt" -size +5G | ||
| 159 | - # review then: | ||
| 160 | - find /home/ubuntu/SkyVLA/logs/openfly/subgoal_dit -name "last.pt" -size +5G -delete | ||
| 161 | - ``` | ||
| 162 | - | ||
| 163 | - A full root disk also breaks the Claude Code harness (task-output dir can't be written), so this matters more than usual. | ||
| 164 | - | ||
| 165 | - ## Image data caveat — and why per-env balancing requires the new flag | ||
| 166 | - | ||
| 167 | - **Only ~14% of `train.json` steps have local frames** in `~/assets/OpenFly/images/Image`. The dataset's `require_images=True` filter silently drops the rest. **Coverage is wildly uneven across envs** — env_ue_bigcity has 91% coverage (181k steps), env_gs_ecust has 0%, and most others sit at 1-10%. As of 2026-05-29 the breakdown is: | ||
| 168 | - | ||
| 169 | - | env | usable steps | coverage | | ||
| 170 | - |---|---|---| | ||
| 171 | - | env_ue_bigcity | 181,792 | 91.4% | | ||
| 172 | - | env_airsim_16 | 17,468 | 9.1% | | ||
| 173 | - | env_airsim_26 | 6,913 | 4.0% | | ||
| 174 | - | env_airsim_23 | 6,779 | 12.7% | | ||
| 175 | - | env_gs_sjtu01 | 6,771 | 6.9% | | ||
| 176 | - | env_airsim_sh | 6,410 | 2.0% | | ||
| 177 | - | env_airsim_18 | 1,613 | 1.0% | | ||
| 178 | - | env_airsim_gz | 1,612 | 0.9% | | ||
| 179 | - | env_gs_nwpu02 | 509 | 0.4% | | ||
| 180 | - | env_gs_nwpu01 | 57 | 0.1% | | ||
| 181 | - | env_gs_ecust | 0 | 0.0% | | ||
| 182 | - | ||
| 183 | - The 286k "missing" frames aren't a naming bug — the trajectory directories exist but are empty (download was incomplete). Trying to fix this by changing the path resolution in [openfly/dataset.py](openfly/dataset.py) won't help; the files genuinely aren't on disk. | ||
| 184 | - | ||
| 185 | - **Why `--per_env_max_episodes` doesn't actually balance:** it caps EPISODES BEFORE the image-existence filter. Because bigcity has both more episodes AND higher per-episode coverage, any episode cap that's high enough to produce a usable training set is dominated by bigcity. Concretely `--per_env_max_episodes 2000` produces ~95% bigcity samples in the final dataset. | ||
| 186 | - | ||
| 187 | - **Use `--per_env_max_index_samples N` for actual balance** — caps usable step-pairs per env AFTER image filtering. With N=10000 the dataset lands at ~50k step-pairs with bigcity at ~20%. Deterministic sampling (seed=0) so configs are reproducible. Always use this when "balanced multi-env training" is what you actually want — `--per_env_max_episodes` alone produces a heavily-skewed bigcity-mostly run. | ||
| 188 | - | ||
| 189 | - ## Training script gotchas to know about | ||
| 190 | - | ||
| 191 | - * **Don't trust `history.json` mid-multi-launch run alone — the log has the truth.** Fixed 2026-05-29: resumes now load prior history.json so summaries from earlier launches survive. Before the fix, a Xid-43 mid-run dropped earlier epoch summaries from the file (they stayed in the stdout log though). | ||
| 192 | - * The wrapper script `/openfly/run_train_subgoal_dit.sh` sets `PYTHONUNBUFFERED=1` and uses `python -u` — don't pipe long runs through `tail -N` without `tee` first, or progress prints get lost on signal. | ||
| 193 | - * `args.json` is persisted to `out_dir` at startup so a mid-training crash still leaves the run config behind. | ||
| 88 | + `/dev/vda1` is shared with `/tmp` and runs 90%+ full on this machine. PPO | ||
| 89 | + checkpoints and rendered mp4s add up. **Before a long run**, check `df -h /tmp` | ||
| 90 | + has headroom; delete stale checkpoints/videos first if not. A full root disk | ||
| 91 | + also breaks the Claude Code harness (task-output dir can't be written), so this | ||
| 92 | + matters more than usual. | ||
| 194 | 93 | ||
| 195 | 94 | ## Don't break what works | |
| 196 | 95 | ||
| 197 | - When making architectural changes to a model that has saved checkpoints, the `load_state_dict(strict=False)` + shape-filter pattern (see `openfly/policies.py:PaliGemmaOpenFlyPolicy.__init__`) keeps old checkpoints loadable with the new architecture. Apply the same pattern when adding/removing layers from `PaliGemmaVLNPolicy` or `PixArtSubgoalDiT`. | ||
| 96 | + The converged pick-place config is the result of careful reward balancing | ||
| 97 | + (strong-but-capped lift gradient, dominant held-only placement reward, start-pose | ||
| 98 | + curriculum). When changing `pick_place_env._get_rewards`, keep that structure — | ||
| 99 | + getting lift vs. placement weights wrong collapses the whole task. When changing | ||
| 100 | + the articulation or observation layout, keep old checkpoints loadable | ||
| 101 | + (`load_state_dict(strict=False)` + shape filter) rather than silently breaking | ||
| 102 | + every saved `model_*.pt`. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments