feat(sp14-c.5a-fixup): missing scratch buffers + collector ptr scaffolding (dead code)
Phase C.5a-fixup — completes C.5a's additive infrastructure so C.5b can be
a true atomic contract flip with zero scaffolding work mixed in:
- Allocate dh_aux1_pre_scratch [B_max, AUX_TRUNK_H1=256] +
dh_aux2_pre_scratch [B_max, AUX_TRUNK_H2=128] (missed in C.5a — both
required by aux_trunk_backward.launch per gpu_aux_trunk.rs:266-267).
- Collector struct gains 6× u64 aux_trunk_{w1,b1,w2,b2,w3,b3}_ptr fields,
exp_aux_trunk_forward_ops: AuxTrunkForwardOps field (constructed in
ctor on collector's stream), and set_trainer_aux_trunk_param_ptrs
setter — mirrors the existing set_trainer_params_ptr zero-copy pattern.
- Trainer gains aux_trunk_param_ptrs() -> (u64×6) accessor returning
raw_ptr() for all 6 aux trunk parameter tensors.
- training_loop wires the new setter at both existing
set_trainer_params_ptr call sites (initial fused-ctx init + fold-boundary
re-init).
NO contract change: wire sites still call save_h_s2. The setter is called
and the 6 aux trunk param ptrs are populated, but no collector-side launch
reads them yet — C.5b atomically inserts aux_trunk_forward.launch(...)
post-forward_online_f32 and switches the aux head input pointer.
Graph-capture audit: aux_heads_backward IS INSIDE the captured `forward`
child graph (call chain: submit_forward_ops_main → launch_cublas_backward
→ launch_cublas_backward_to → aux_heads_backward; capture begins at
fused_training.rs:2964 / capture_child_graph). The existing function body
is fully device-side (zero host writes) — capture-safe by construction.
C.5b's new aux_trunk Adam launch is also fully device-side and will sit
inside the same captured region. The host writes for aux_trunk_t_pinned
must use the existing GPU-side increment_step_counters kernel chain
(submit_counters_ops, line 22799) — NOT host-side aux_trunk_adam_step
+= 1 inside capture. ISV-driven LR/clip writes happen pre-capture
(cold-path); the captured graph reads via aux_trunk_lr_dev_ptr /
aux_trunk_grad_clip_dev_ptr. This avoids the &self → &mut self ripple on
aux_heads_backward (gap 4 in C.5b implementer's blocker report). Full
wiring strategy + alternative (pre-capture host-write) documented in
docs/dqn-wire-up-audit.md C.5a-fixup section.
Verification:
- cargo check -p ml --tests --all-targets: clean (no new warnings).
- cargo test -p ml --test aux_trunk_oracle_tests --test sp14_oracle_tests
--release -- --ignored --nocapture: 12/12 pass (8 aux_trunk + 4 sp14;
bit-identical to C.5a baseline — pure scaffolding, no regression).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7386,6 +7386,22 @@ pub struct GpuDqnTrainer {
|
||||
#[allow(dead_code)]
|
||||
aux_trunk_b3_grad: CudaSlice<f32>,
|
||||
|
||||
/// SP14 Layer C Phase C.5a-fixup (2026-05-08): pre-activation gradient
|
||||
/// scratch for aux trunk Layer-1 (`dh_aux1_pre [B_max, AUX_TRUNK_H1=256]`).
|
||||
/// `aux_trunk_backward.launch` writes this scratch in its dh_pre kernel
|
||||
/// (overwrites; not accumulated) and reads it back in the dW_reduce
|
||||
/// kernel for `dW1 = x_in.T @ dh_aux1_pre` + `db1 = sum_b dh_aux1_pre`.
|
||||
/// Required by `gpu_aux_trunk.rs:266-267` — C.5a missed it. DEAD until
|
||||
/// C.5b atomically wires the aux trunk backward into the gradient chain.
|
||||
#[allow(dead_code)]
|
||||
dh_aux1_pre_scratch: CudaSlice<f32>,
|
||||
/// SP14 Layer C Phase C.5a-fixup: pre-activation gradient scratch for
|
||||
/// aux trunk Layer-2 (`dh_aux2_pre [B_max, AUX_TRUNK_H2=128]`). Same
|
||||
/// role + lifecycle as `dh_aux1_pre_scratch`; consumed by Layer-2/3
|
||||
/// matmul reductions in `aux_trunk_backward.launch`.
|
||||
#[allow(dead_code)]
|
||||
dh_aux2_pre_scratch: CudaSlice<f32>,
|
||||
|
||||
/// `[num_blocks_total]` per-block partial sum-of-squares written by
|
||||
/// `dqn_grad_norm_kernel` across all 6 grad tensors (offsets matching
|
||||
/// `aux_trunk_grad_block_offsets`). Sized to the maximum total block
|
||||
@@ -10617,6 +10633,32 @@ impl GpuDqnTrainer {
|
||||
self.target_params_buf.raw_ptr()
|
||||
}
|
||||
|
||||
/// SP14 Layer C Phase C.5a-fixup (2026-05-08): raw device pointers to
|
||||
/// the aux trunk's 6 parameter tensors (`w1, b1, w2, b2, w3, b3`).
|
||||
///
|
||||
/// Returned in the same order as the Adam launcher's per-tensor tuple
|
||||
/// list (`launch_aux_trunk_adam_update`). The collector calls the
|
||||
/// matching `set_trainer_aux_trunk_param_ptrs` setter once after the
|
||||
/// fused training context is created (cold-path, mirrors the existing
|
||||
/// `set_trainer_params_ptr` zero-copy contract — pointers are stable
|
||||
/// for the lifetime of the trainer's CudaSlice fields).
|
||||
///
|
||||
/// C.5b consumes these ptrs to launch `aux_trunk_forward.launch(...)`
|
||||
/// from the collector's per-rollout-step body, reading the trainer's
|
||||
/// authoritative aux trunk weights without a DtoD copy. The accessor
|
||||
/// itself is dead in C.5a-fixup — populated but unread until C.5b
|
||||
/// flips the contract.
|
||||
pub fn aux_trunk_param_ptrs(&self) -> (u64, u64, u64, u64, u64, u64) {
|
||||
(
|
||||
self.aux_trunk_w1.raw_ptr(),
|
||||
self.aux_trunk_b1.raw_ptr(),
|
||||
self.aux_trunk_w2.raw_ptr(),
|
||||
self.aux_trunk_b2.raw_ptr(),
|
||||
self.aux_trunk_w3.raw_ptr(),
|
||||
self.aux_trunk_b3.raw_ptr(),
|
||||
)
|
||||
}
|
||||
|
||||
/// SP15 Phase 3.5.4.c (2026-05-07): return the
|
||||
/// `(w_b0out_dev_ptr, n_weights, fan_in)` triple for the
|
||||
/// directional advantage-head last-Linear weight tensor (param-
|
||||
@@ -22657,6 +22699,15 @@ impl GpuDqnTrainer {
|
||||
let aux_trunk_w3_grad = alloc_f32(&stream, aux_trunk_w3_count, "aux_trunk_w3_grad")?;
|
||||
let aux_trunk_b3_grad = alloc_f32(&stream, aux_trunk_out_dim, "aux_trunk_b3_grad")?;
|
||||
|
||||
// SP14 Layer C Phase C.5a-fixup (2026-05-08): pre-activation gradient
|
||||
// scratch buffers required by `aux_trunk_backward.launch`
|
||||
// (`gpu_aux_trunk.rs:266-267`). Sized to `B_max × layer_h` so the
|
||||
// backward kernel can write `dh_pre` once and read it back for
|
||||
// dW/db reductions without aliasing. C.5a missed these. DEAD until
|
||||
// C.5b atomically wires the backward chain.
|
||||
let dh_aux1_pre_scratch = alloc_f32(&stream, b * aux_trunk_h1, "dh_aux1_pre_scratch")?;
|
||||
let dh_aux2_pre_scratch = alloc_f32(&stream, b * aux_trunk_h2, "dh_aux2_pre_scratch")?;
|
||||
|
||||
// Per-tensor block counts for the dqn_grad_norm_kernel launches
|
||||
// (block_dim=256). One partial slot per (block × tensor) pair —
|
||||
// we lay them out in a contiguous buffer with fixed offsets so
|
||||
@@ -23593,6 +23644,9 @@ impl GpuDqnTrainer {
|
||||
aux_trunk_b2_grad,
|
||||
aux_trunk_w3_grad,
|
||||
aux_trunk_b3_grad,
|
||||
// SP14 Layer C Phase C.5a-fixup (2026-05-08): dh_pre scratch buffers (DEAD).
|
||||
dh_aux1_pre_scratch,
|
||||
dh_aux2_pre_scratch,
|
||||
aux_trunk_grad_norm_partials,
|
||||
aux_trunk_grad_block_offsets,
|
||||
aux_trunk_grad_norm_buf,
|
||||
|
||||
Reference in New Issue
Block a user