perf(ml-alpha): block-per-batch GRN bwd refactor (Phase B commit 2)
multi_horizon_heads_grn_bwd_batched refactored from grid=(1,1,1) to
grid=(B,1,1). Removes the single-SM bottleneck on the second-most-called
K-loop kernel (64×/step like cfc_bwd).
Adds 10 per-batch grad scratch buffers (one per GRN param tensor) + 10
reduce_axis0 launches collapsing B → final grad after the K-loop:
grn_grad_w1_scratch_d [B, 5, HEAD_MID, HIDDEN]
grn_grad_b1_scratch_d [B, 5, HEAD_MID]
grn_grad_w2_scratch_d [B, 5, HEAD_MID, HEAD_MID]
grn_grad_b2_scratch_d [B, 5, HEAD_MID]
grn_grad_w_gate_scratch_d [B, 5, HEAD_MID]
grn_grad_b_gate_scratch_d [B, 5]
grn_grad_w_main_scratch_d [B, 5, HEAD_MID]
grn_grad_b_main_scratch_d [B, 5]
grn_grad_w_skip_scratch_d [B, 5, HIDDEN]
grn_grad_b_skip_scratch_d [B, 5]
Total: ~8 MB scratch at B=32.
All 9 perception_overfit smokes pass (including stacked_trainer_loss_
shrinks_at_batch_32 which exercises the cross-batch reducer path on
both cfc and GRN grads).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>