Files
foxhunt/crates
jgrusewski 0f75d6bb7b feat(rl): FRD layer-1 backward (dW1, db1, dh_t with ReLU mask) — F.3c
Third and final FRD backward stage. Closes the chain from
softmax+CE loss back to the encoder's hidden state h_t.

Kernel `cuda/rl_frd_layer1_bwd.cu`:
  * grid_dim = (B, 1, 1), block_dim = (HIDDEN_DIM=128, 1, 1)
  * Phase 0: threads 0..63 stage dL/dpre_hidden = grad_hidden ×
    1{hidden > 0} into shared mem (the cached post-ReLU `hidden`
    buffer encodes the mask — hidden == 0 ⇔ pre-activation was
    ≤ 0 → ReLU killed it). Same thread also writes db1_per_batch.
  * Phase 1: each thread k (k < 128) writes one row of
    grad_W1_per_batch[b, k, 0..64] (64 writes per thread, no atomics)
  * Phase 2: same thread computes grad_h_t[b, k] =
    Σ_i W1[k, i] × dL/dpre_hidden[b, i]
  * Per-(b, k, i) sole-writer per feedback_no_atomicadd

Rust wiring `FrdHead::layer1_bwd` — takes h_t, hidden (forward cache),
grad_hidden (from layer2_bwd), self.w1_d; writes grad_w1_per_batch,
grad_b1_per_batch, grad_h_t. The grad_h_t buffer becomes the encoder-
upstream gradient that the trainer's grad_h_accumulate kernel folds
into the encoder's gradient with λ_frd scaling (same pattern as Q/π/V
heads — wiring lives in F.4).

Tests (2 new, 10/10 file total):
  * frd_layer1_bwd_finite_diff_w1 — perturbs the W1 slot with MAX
    |analytical gradient| (instead of an arbitrary fixed slot — fp32
    finite-diff is rounding-error-limited so a tiny gradient gives
    misleading rel_err). At max-magnitude slot (k=84, i=55): analytical
    = -0.0451, numerical = -0.0448, rel_err = 5.6e-3 — well within
    1e-2 tolerance (slightly looser than dW2's 5e-3 because dW1
    crosses an extra matmul + the ReLU mask boundary).
  * frd_layer1_bwd_relu_mask_zeros_grad — fixture with h_t = all -1
    produces ~half the hidden slots ReLU-masked (cached hidden = 0).
    For every masked slot i, asserts:
      * db1_per_batch[b, i] == 0 (exact equality — mask is hard 0)
      * dW1_per_batch[b, k, i] == 0 for every k (~32 × 128 = 4096
        slots checked)
    Empirically 32/64 masked, 32/64 active — confirms ReLU mask
    is wired through the chain correctly without leaking gradient
    through dead branches.

F.3 backward chain is now complete end-to-end:
  rl_frd_softmax_ce_grad (F.3a) → rl_frd_layer2_bwd (F.3b) →
  rl_frd_layer1_bwd (F.3c) → grad_h_t (consumed by F.4 wiring)

F.4 wires Adam optimizers for W1/b1/W2/b2 + grad_h_accumulate into
the encoder gradient + loader-side label generation + λ_frd × CE
into stats.l_total.
2026-05-24 18:40:30 +02:00
..