fix: precommit audit — gradient offset s1_input_dim + q_attn_params zero-init

CRITICAL: backward_full used state_dim for goff_b_s1 offset but
compute_param_sizes uses s1_input_dim (smaller with bottleneck active).
All downstream gradient offsets were misaligned. Fixed: sd → s1d.

HIGH: q_attn_params used alloc_f32 (potentially non-zero) instead of
alloc_zeros. Cross-branch Q-attention residual connection needs near-zero
init for stability. Fixed: alloc_zeros.

MEDIUM (deferred): VSN masking bypassed for magnitude branch — mag_concat
reads raw h_s2 instead of vsn_masked. No impact while W_vsn2 is zero-init
(identity mask). Will fix when VSN backward is wired.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-04-15 07:16:56 +02:00
parent 1fdc712df6
commit 298455e24a
2 changed files with 4 additions and 3 deletions

View File

@@ -815,7 +815,7 @@ impl CublasBackwardSet {
// We compute these inline from the config dimensions.
// grad_buf is now f32, so byte offsets use sizeof(f32) = 4.
let f32 = std::mem::size_of::<f32>() as u64;
let sd = self.state_dim as u64;
let s1d = self.s1_input_dim as u64; // CRITICAL: must match compute_param_sizes (not state_dim)
let sh1 = self.shared_h1 as u64;
let sh2 = self.shared_h2 as u64;
let vh = self.value_h as u64;
@@ -828,7 +828,7 @@ impl CublasBackwardSet {
// GOFF byte offsets (must match compute_param_sizes order)
let goff_w_s1: u64 = 0;
let goff_b_s1: u64 = goff_w_s1 + sh1 * sd * f32;
let goff_b_s1: u64 = goff_w_s1 + sh1 * s1d * f32;
let goff_w_s2: u64 = goff_b_s1 + sh1 * f32;
let goff_b_s2: u64 = goff_w_s2 + sh2 * sh1 * f32;
let goff_w_v1: u64 = goff_b_s2 + sh2 * f32;

View File

@@ -2694,7 +2694,8 @@ impl GpuDqnTrainer {
info!("GpuDqnTrainer: mag_concat_qdir + strided_accumulate kernels loaded");
// ── Cross-Branch Q Attention buffers ──────────────────────────
let q_attn_params = alloc_f32(&stream, 624, "q_attn_params")?;
let q_attn_params = stream.alloc_zeros::<f32>(624)
.map_err(|e| MLError::ModelError(format!("alloc q_attn_params: {e}")))?;
let q_attn_adam_m = stream.alloc_zeros::<f32>(624)
.map_err(|e| MLError::ModelError(format!("alloc q_attn_adam_m: {e}")))?;
let q_attn_adam_v = stream.alloc_zeros::<f32>(624)