Fix A_log loading via checkpoint-side slice instead of resizing the model parameter (alternative to #144)

#150
Files changed (1) hide show
  1. modeling_kimi_linear.py +23 -0
modeling_kimi_linear.py CHANGED
@@ -540,6 +540,29 @@ class KimiDeltaAttention(nn.Module):
540
  self.head_dim, eps=config.rms_norm_eps, activation='sigmoid')
541
  self.o_proj = nn.Linear(projection_size, self.hidden_size, bias=False)
542
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
543
  def forward(
544
  self,
545
  hidden_states: torch.Tensor,
 
540
  self.head_dim, eps=config.rms_norm_eps, activation='sigmoid')
541
  self.o_proj = nn.Linear(projection_size, self.hidden_size, bias=False)
542
 
543
+ def _load_from_state_dict(self, state_dict, prefix, *args, **kwargs):
544
+ # The released checkpoint stores A_log as [head_dim] rather than
545
+ # [num_heads], which raises a size mismatch on a plain load. Inspecting
546
+ # the checkpoint shows elements [num_heads:head_dim] are exactly zero in
547
+ # every KDA layer -- i.e. num_heads trained per-head decays, zero-padded
548
+ # to head_dim by the export pipeline. The KDA kernel indexes A_log per
549
+ # head (the head count used for indexing comes from the shape of v at
550
+ # call time, not from A_log's own shape), so the model's [num_heads]
551
+ # parameter is correct; only the checkpoint tensor needs slicing down to
552
+ # match it.
553
+ key = prefix + "A_log"
554
+ if key in state_dict:
555
+ ckpt_val = state_dict[key]
556
+ want = self.A_log.shape[0]
557
+ if ckpt_val.shape[0] > want:
558
+ tail = ckpt_val[want:]
559
+ if not torch.all(tail == 0):
560
+ raise ValueError(
561
+ f"{key}: checkpoint tail beyond index {want} is non-zero; "
562
+ "refusing to truncate real values")
563
+ state_dict[key] = ckpt_val[:want]
564
+ super()._load_from_state_dict(state_dict, prefix, *args, **kwargs)
565
+
566
  def forward(
567
  self,
568
  hidden_states: torch.Tensor,