mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-10 16:04:04 +00:00
175 lines
8.0 KiB
Markdown
175 lines
8.0 KiB
Markdown
# Training on the Linux / RTX 3090 box
|
||
|
||
Remote-training workflow: run long training sessions on the Linux machine and
|
||
watch the dashboard from any machine on the network. **All training artifacts
|
||
(checkpoints, TensorBoard logs, exported bots) are committed to git** — no
|
||
result ever depends on a single machine, and moving models between the box
|
||
and the Mac is just `git pull`. General training concepts and the
|
||
export/evaluate workflow live in [TRAINING.md](TRAINING.md) — this doc is
|
||
only what differs on the Linux box.
|
||
|
||
Both workflows below are wrapped in idempotent scripts in `training/` —
|
||
re-running either is always safe.
|
||
|
||
## One-time setup
|
||
|
||
GitHub auth first (git-over-HTTPS no longer accepts account passwords, so
|
||
clone over SSH — this key also lets `run_training.sh` push results):
|
||
|
||
```bash
|
||
ssh-keygen -t ed25519 # accept the defaults
|
||
cat ~/.ssh/id_ed25519.pub # add at github.com/settings/keys → "New SSH key"
|
||
|
||
cd ~/ai-training
|
||
git clone git@github.com:jcreek/CosmicClash.git
|
||
# (submodules are editor tooling only — training doesn't need them)
|
||
|
||
~/ai-training/CosmicClash/training/setup_linux.sh
|
||
```
|
||
|
||
`setup_linux.sh` is safe to re-run any time (after a Godot upgrade, a broken
|
||
venv, a fresh clone — it checks each step before acting). It:
|
||
|
||
- downloads the Godot 4.7.1 Linux binary to `~/ai-training/godot/` if missing
|
||
(override the location by exporting `GODOT_BIN`);
|
||
- creates `training/.venv` if missing and installs requirements;
|
||
- verifies CUDA torch, reinstalling from the CUDA wheel index if the box got
|
||
a CPU-only build;
|
||
- runs the Godot import pass (fresh clones have no `.godot/` cache, so
|
||
`class_name` scripts aren't registered until the project imports once);
|
||
- finishes with the headless smoke test — the game must boot without
|
||
rendering.
|
||
|
||
## Maximising throughput
|
||
|
||
Env stepping is CPU-bound (each `--n-parallel` instance is one headless Godot
|
||
process simulating 2 agents); the 3090 only accelerates the PPO updates. So
|
||
the two levers are instance count and in-engine speedup:
|
||
|
||
- **`--n-parallel`**: start at `nproc` minus 2 (leave headroom for the
|
||
trainer process itself). The Mac mini sustains 6; a many-core box should
|
||
take considerably more. Each instance opens its own TCP port upward from
|
||
`--port` (default 11008).
|
||
- **`--speedup`**: in-engine physics time-scale. 16 is proven; try 24–32 and
|
||
keep raising while `time/fps` in the console/TensorBoard still scales up.
|
||
Back off if fps stops improving (CPU saturated) or physics glitches appear
|
||
(ball tunnelling, ships escaping the arena — watch for respawn warnings in
|
||
the Godot output).
|
||
|
||
Tune by watching `time/fps`: run a 2-minute smoke run per setting and keep
|
||
the best. Reference: 6 instances × speedup 16 ≈ 1,385 steps/s on an M4 Mac
|
||
mini — a 20M-step run in ~4 h. Doubling fps halves that.
|
||
|
||
## Run training
|
||
|
||
One command does everything (needs `tmux`: `sudo apt install tmux`):
|
||
|
||
```bash
|
||
cd ~/ai-training/CosmicClash/training
|
||
./start_training.sh run03 --timesteps 20000000 --n-parallel 14 --speedup 24
|
||
```
|
||
|
||
`start_training.sh` launches a detached tmux session with two windows —
|
||
**training survives SSH disconnects** — and prints the dashboard URL:
|
||
|
||
- `train` runs `run_training.sh`: `git pull` → train → export the policy
|
||
JSON → commit and push checkpoints, logs, and the exported bot;
|
||
- `dashboard` serves TensorBoard on `0.0.0.0:6006` for the whole network
|
||
(reused if one is already running).
|
||
|
||
Re-running `start_training.sh` while a session exists just attaches you to
|
||
it (detach again with `Ctrl-B` then `D`) — it will never start a second
|
||
trainer. To stop training, attach and Ctrl-C: the trainer writes `final.zip`
|
||
on the way out and the script still exports, commits, and pushes what it has.
|
||
|
||
Resuming a previous policy (continues its timestep counter; `--timesteps` is
|
||
*additional* steps). Lessons from run01/run02 hard-coded into flags:
|
||
|
||
```bash
|
||
./start_training.sh run03 --timesteps 20000000 --n-parallel 14 --speedup 24 \
|
||
--resume checkpoints/run02/final.zip --ent-coef 0.001 --reset-std 0.3
|
||
```
|
||
|
||
- `--ent-coef` — entropy bonus. `0.0001` collapsed the policy std to 0.075 by
|
||
20M steps (no exploration left); `0.005` blew it up to 3.0 (random play).
|
||
`0.001` is the current middle. Healthy `train/std` drifts between ~0.2 and
|
||
~1.0 — check it 30–45 min in before committing to a long run.
|
||
- `--reset-std` — on resume, restores exploration a collapsed checkpoint lost.
|
||
|
||
## Results travel via git
|
||
|
||
`run_training.sh` commits and pushes everything a run produces:
|
||
|
||
- `training/checkpoints/<exp>/` — periodic checkpoints + `final.zip`, for
|
||
future `--resume`, evaluation, and difficulty tiers (an early checkpoint
|
||
*is* an easy bot);
|
||
- `training/logs/` — TensorBoard history;
|
||
- `Game/bots/<exp>.json` — the exported policy, immediately playable (point
|
||
Match or Spectate mode at `res://bots/<exp>.json`);
|
||
- `training/eval_history.json` — if evaluations ran.
|
||
|
||
On the Mac (or anywhere), collecting the results is just `git pull`. A
|
||
20M-step run adds roughly 40 MB of checkpoints — acceptable growth for the
|
||
guarantee that training is never lost with a machine.
|
||
|
||
## Exported-binary training (faster parallel startup)
|
||
|
||
By default (and in every example above) `train.py` runs the project from
|
||
source via `--godot_bin` — each of the `--n-parallel` instances re-parses
|
||
project settings and re-imports scripts/resources on launch. An **exported**
|
||
build skips that: resources are pre-imported and packed once at export time,
|
||
so each instance just loads a binary. Worth it once `--n-parallel` is large
|
||
enough that per-instance startup overhead adds up (i.e. this box, not the Mac
|
||
mini's `--n-parallel 6`).
|
||
|
||
Opt in once — `run_training.sh` (and so `start_training.sh`/`next_run.sh`/
|
||
`curriculum.sh`, which all funnel through it) takes it from there automatically:
|
||
|
||
```bash
|
||
./export_linux.sh # one-time opt-in: builds training/build/CosmicClash.x86_64
|
||
./next_run.sh # from here on, every standing/curriculum run uses it
|
||
```
|
||
|
||
You don't need to (and shouldn't) pass `--exported-binary` yourself through
|
||
those entry points — `run_training.sh` adds it whenever `training/build/`
|
||
exists, after re-exporting against whatever `git pull` just fetched. Calling
|
||
`train.py` directly still takes it explicitly, same as any other flag:
|
||
|
||
```bash
|
||
.venv/bin/python train.py --experiment run04 --exported-binary build/CosmicClash.x86_64 \
|
||
--timesteps 20000000 --n-parallel 14 --speedup 24
|
||
```
|
||
|
||
To go back to a source run permanently, delete `training/build/` — with it
|
||
gone, `run_training.sh` stops re-exporting and stops adding the flag, so
|
||
`next_run.sh`/`curriculum.sh` revert to plain source runs with no code changes.
|
||
|
||
`export_linux.sh` builds from the "Linux Training" preset in
|
||
`Game/export_presets.cfg`, which is training-only — its
|
||
`custom_features="training"` activates project.godot's
|
||
`run/main_scene.training` override, so the resulting binary boots straight
|
||
into `training.tscn` on its own. This indirection is required, not
|
||
incidental: official Godot export templates have path/scene overrides
|
||
compiled out, so passing `--scene` at launch time (the way the source run
|
||
does) hard-aborts an exported binary with "compiled without support for path
|
||
overrides" — there's no way to redirect an exported build to a different
|
||
scene at runtime. Because the main scene is baked in at export time, this
|
||
preset can't later double as a normal "ship the game" Linux build (which
|
||
would need `main_menu.tscn` and no training feature tag) — a real game export
|
||
would need its own separate preset.
|
||
|
||
`setup_linux.sh` installs the export templates this needs alongside the
|
||
Godot binary. If you never opt in (no `training/build/` directory), this
|
||
costs nothing — training stays a plain source run.
|
||
|
||
## Dashboard over the network
|
||
|
||
`start_training.sh` already serves TensorBoard on all interfaces — browse to
|
||
the URL it prints (`http://10.0.0.20:6006`) from the Mac or anything on
|
||
the LAN.
|
||
|
||
- If `ufw` is active on the box: `sudo ufw allow 6006/tcp`.
|
||
- If you'd rather not open a port, tunnel instead:
|
||
`ssh -L 6006:localhost:6006 10.0.0.20` from the Mac, then browse
|
||
`http://localhost:6006`.
|