@@ -101,14 +101,75 @@ the optimizer hold handles to the same weight and the same gradient, which is wh
101101without special support: use the same handle twice and both paths' gradients add
102102up on their own.
103103
104+ ## Running unattended
105+
106+ Four things a long run needs, none of which the training loop above shows.
107+
108+ ** Resume where you stopped.** ` save() ` writes weights, which is what you want for
109+ a finished model. Resuming needs the optimizer too — its momentum, Adam's two
110+ moment estimates, and the step count that drives bias correction. Restore weights
111+ alone and the optimizer restarts at step 1, so the first update after resuming
112+ lands far harder than it should.
113+
114+ ``` rust
115+ let mut step = load_training (& model , & mut opt , " run.fdl" ). unwrap_or (0 );
116+
117+ while step < total {
118+ // ... train ...
119+ step += 1 ;
120+ if step % 500 == 0 { save_training (& model , & opt , step , " run.fdl" )? ; }
121+ }
122+ ```
123+
124+ Loading a plain checkpoint with ` load_training ` is an error rather than a silent
125+ optimizer reset. ` char_lm ` does this, so Ctrl-C costs at most a few hundred steps.
126+
127+ ** Find the NaN at the op that made it.** One non-finite gradient becomes a
128+ non-finite weight, and every activation downstream is NaN from then on — the loss
129+ only * prints* as NaN some steps later, by which point the checkpoint is poisoned
130+ too and the culprit is long gone.
131+
132+ ``` rust
133+ detect_anomaly (|| {
134+ loss . backward (); // panics: "anomaly: Log produced inf in the gradient for input 0"
135+ });
136+
137+ if ! opt . gradients_are_finite () { continue ; } // cheap guard: skip the batch
138+ ```
139+
140+ Both read every gradient, so they are debugging and guard-rail tools, not
141+ something to leave on in a healthy loop.
142+
143+ ** Freeze a backbone.** Frozen parameters hand out a detached tensor, so the
144+ backward pass stops there — no gradient is computed only to be discarded.
145+
146+ ``` rust
147+ backbone . freeze ();
148+ let mut opt = Adam :: new (model . parameters (), 1e - 3 ); // updates only the head
149+ ```
150+
151+ ** Report a bad shape instead of dying.** Ordinary ops panic, which is right
152+ inside a model. At the edge of an app — a shape from a config file, a batch from
153+ an upload — use the ` try_ ` variants.
154+
155+ ``` rust
156+ let y = x . try_matmul (& w )? ; // Error::Shape, not a panic
157+ x . try_reshape (& [2 , - 1 ])? ;
158+ table . try_index_select (& ids )? ;
159+ ```
160+
161+ They validate and then delegate, so there is still exactly one implementation of
162+ each operation, and they build the same graph.
163+
104164## Layout
105165
106- Every file is one idea, and none are long. 67 files, ~ 7,000 lines.
166+ Every file is one idea, and none are long. 71 files, ~ 8.0k lines.
107167
108168```
109169src/
110170 tensor/ the array type and everything you can do to it
111171 core.rs Tensor: shape, storage, graph link
172+ checked.rs try_* variants that report instead of panicking
112173 shape.rs strides, broadcasting, index math
113174 storage.rs the bytes, on one device or the other
114175 device.rs Device::cuda(0) -> Result
@@ -121,16 +182,17 @@ src/
121182 node.rs Backward trait, graph nodes, gradient slots
122183 engine.rs the reverse pass
123184 mode.rs no_grad
185+ anomaly.rs detect_anomaly
124186 ops/ one backward rule per forward op, same file names
125187
126188 nn/ layers, all implementing Module
127189 module.rs param.rs sequential.rs linear.rs conv.rs pooling.rs
128190 norm.rs activation.rs dropout.rs shape.rs embedding.rs
129191 attention.rs transformer.rs rnn.rs loss.rs
130192
131- optim/ sgd.rs adam.rs schedule.rs
193+ optim/ sgd.rs adam.rs schedule.rs state.rs
132194 data/ dataset.rs loader.rs mnist.rs
133- serialize/ checkpoint.rs
195+ serialize/ checkpoint.rs (weights) training.rs (weights + optimizer)
134196 cuda/ ffi.rs (raw bindings) kernels.rs (safe wrappers) buffer.rs
135197 rng.rs error.rs lib.rs
136198
@@ -204,6 +266,7 @@ load(&model, "model.fdl")?; // missing file, or a shape that moved
204266
205267``` bash
206268cargo test --no-default-features --test gradcheck # every backward rule
269+ cargo test --no-default-features --test robustness # resume, anomalies, freezing
207270cargo test --test cuda_parity -- --test-threads=1 # CPU vs GPU
208271cargo test --no-default-features # everything
209272cargo bench --no-default-features # throughput
0 commit comments