"Training is slow" and "training is slow ON THE CPU with four million
parameters" are different problems with different fixes, and nothing in the log
told them apart — leaving it to be inferred from timings, which is how the
first guess at this went to the disk instead.
One line per run per value function, naming the device and the parameter count.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Off by default. On, the timeline sits as a strip — its header, so the title,
transport and Composer stay reachable — and opens to full height while the
pointer is on it or something inside it has focus.
It also opens for the whole of a DRAG. During one the pointer is in drag mode
and a strip that stays shut is a drop target you cannot hit, so dragenter holds
it open and drop/dragend closes it. The tracker counts depth rather than
holding a boolean: dragleave for the element being left fires AFTER dragenter
for the one being entered, so a flag closes the strip mid-drag as the pointer
crosses from one clip to the next.
The strip height is MEASURED from the header rather than fixed: .zone-head
wraps when the zone is narrow (34px min-height, 138px on a normal window), so
any constant clips the very controls the strip exists to keep visible. It is
re-measured on resize. flex: 0 0 auto matters — .zone is a shrinkable column
child, and a height with min-height: 0 let the workspace squeeze the strip to
1px. The body collapses rather than being display:none so the lanes are not
torn down and rebuilt on every open.
A browser preference like the colour scheme, not a project one, and registered
in the same Settings section for that reason.
Also in this commit:
- vf: train wherever there is a GPU, not only when the sample sits on one. The
x0 value function's snapshot loads with map_location="cpu", so keying on the
sample left it training on the CPU — the run that named it measured
"x0 vf: train 10.1s" against 46ms for the same net locally.
- The stage line counted nested sub-stages twice and reported 153% of a run.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Measured rather than assumed. The three value functions are ~16s of a 26.5s
rated run, and the phase that costs it is the training, not the disk:
text cond, dim 5120 3,982,467 params 16.2MB load 19ms TRAIN 1068ms save 26ms
x0 latent, dim 512 221,955 params 0.9MB load 3ms TRAIN 46ms save 2ms
The nets are tiny in FLOPs and not in parameters — a 5120-wide input makes the
first layer 94% of the weights — and twenty Adam steps over that ran on the
CPU because the checkpoint loads with map_location="cpu". Roughly 1.1s here,
about 7.5s on the rental's vCPU, three times per rated generation.
The conditioning is already on the GPU when there is one, so training moves
there and moves back before returning: the buffer and the checkpoint stay on
the CPU so the file remains portable, and inference elsewhere still finds a CPU
module. Adam's state does not follow module.to(), so it is dropped on the move
rather than migrated — it is rebuilt lazily and never persisted, so a run
starts from fresh moments either way.
Nothing about what training does changes; only where it runs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>