@@ -456,6 +456,64 @@ def _patched_forward(
456456# ---------------------------------------------------------------------------
457457
458458
459+ @torch .no_grad ()
460+ def capture_verifier_own_kv (
461+ verifier_model : Any , input_ids : torch .Tensor ,
462+ ) -> Tuple [List [torch .Tensor ], List [torch .Tensor ]]:
463+ """Capture the verifier's OWN pre-norm per-layer K/V via k_proj /
464+ v_proj forward hooks (identity-restoration diagnostic).
465+
466+ Returns ``(k_layers, v_layers)``: per-layer lists where element
467+ ``i`` is ``[B, T, kv_heads_i, head_dim_i]`` (heterogeneous per
468+ layer, matching the f_θ output layout). Layers whose ``v_proj`` is
469+ ``None`` (Gemma 4 full-attention K==V) take V from the k_proj
470+ output, mirroring the model's own behaviour.
471+
472+ Injecting these at evicted positions reproduces exactly what the
473+ verifier would have computed under full attention — so cross-model
474+ recall under identity restoration should match the oracle. This
475+ isolates "is the K/V Restoration machinery correct?" (this helper)
476+ from "is f_θ accurate enough?" (the trained projection).
477+ """
478+ layers = get_verifier_decoder (verifier_model ).layers
479+ n = len (layers )
480+ k_cap : List [Optional [torch .Tensor ]] = [None ] * n
481+ v_cap : List [Optional [torch .Tensor ]] = [None ] * n
482+ v_shared : List [int ] = []
483+ handles = []
484+ for i , layer in enumerate (layers ):
485+ attn = layer .self_attn
486+
487+ def _kh (_m , _inp , out , idx = i ):
488+ k_cap [idx ] = out .detach ()
489+
490+ def _vh (_m , _inp , out , idx = i ):
491+ v_cap [idx ] = out .detach ()
492+
493+ handles .append (attn .k_proj .register_forward_hook (_kh ))
494+ if getattr (attn , "v_proj" , None ) is not None :
495+ handles .append (attn .v_proj .register_forward_hook (_vh ))
496+ else :
497+ v_shared .append (i )
498+ try :
499+ verifier_model (input_ids = input_ids , use_cache = False )
500+ finally :
501+ for h in handles :
502+ h .remove ()
503+ for i in v_shared :
504+ v_cap [i ] = k_cap [i ]
505+ if any (k is None for k in k_cap ) or any (v is None for v in v_cap ):
506+ raise RuntimeError ("verifier own-K/V capture missing some layers" )
507+ k_layers : List [torch .Tensor ] = []
508+ v_layers : List [torch .Tensor ] = []
509+ for i , layer in enumerate (layers ):
510+ hd = layer .self_attn .head_dim
511+ b , t , kvdim = k_cap [i ].shape
512+ k_layers .append (k_cap [i ].view (b , t , kvdim // hd , hd ))
513+ v_layers .append (v_cap [i ].view (b , t , kvdim // hd , hd ))
514+ return k_layers , v_layers
515+
516+
459517def _capture_drafter_kv (
460518 * , verifier_model : Any , drafter : Any , input_ids : torch .Tensor ,
461519) -> KVCapture :
0 commit comments