CompressedGemma commited on
Commit
8a88d87
Β·
verified Β·
1 Parent(s): 9b8ff1c

Qwen patches

Browse files
Files changed (1) hide show
  1. generate_imatrix.py +155 -7
generate_imatrix.py CHANGED
@@ -137,17 +137,35 @@ class GGUFModel:
137
 
138
  def get_config(self):
139
  arch = self.get_arch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  return {
141
  'arch': arch,
142
  'n_layers': self.kv.get(f'{arch}.block_count', 0),
143
- 'n_embd': self.kv.get(f'{arch}.embedding_length', 0),
144
- 'n_head': self.kv.get(f'{arch}.attention.head_count', 0),
145
- 'n_head_kv': self.kv.get(f'{arch}.attention.head_count_kv', 0),
146
  'n_ff': self.kv.get(f'{arch}.feed_forward_length', 0),
147
  'vocab_size': self.kv.get(f'{arch}.vocab_size', 0),
148
  'rms_eps': self.kv.get(f'{arch}.attention.layer_norm_rms_epsilon', 1e-6),
149
  'rope_base': self.kv.get(f'{arch}.rope.freq_base', 10000.0),
150
  'swa_window': self.kv.get(f'{arch}.attention.sliding_window', 0),
 
151
  }
152
 
153
  def get_tensor_f32(self, name):
@@ -458,7 +476,7 @@ class TransformerRunner:
458
  self.model = model
459
  self.cfg = config
460
  self.verbose = verbose
461
- self.head_dim = config['n_embd'] // config['n_head']
462
  self.act_fn = ACTIVATION_MAP.get(config['arch'], silu)
463
 
464
  # Importance accumulators: tensor_name β†’ (sum_x2, count)
@@ -701,6 +719,131 @@ class TransformerRunner:
701
 
702
  return hidden
703
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
704
  def forward(self, token_ids):
705
  """Full forward pass, collecting importance statistics."""
706
  cfg = self.cfg
@@ -718,14 +861,19 @@ class TransformerRunner:
718
 
719
  # Process each layer
720
  for layer_idx in range(cfg['n_layers']):
721
- # Check if this layer has DeltaNet tensors (Qwen 3.6 hybrid)
722
  pfx = f"blk.{layer_idx}"
 
 
723
  has_linear_attn = f'{pfx}.ssm_in_qkv.weight' in self.model.tensor_infos
724
- has_full_attn = f'{pfx}.attn_q.weight' in self.model.tensor_infos
725
 
726
- if has_linear_attn and not has_full_attn:
 
 
 
 
727
  hidden = self.forward_linear_attn_layer(hidden, layer_idx)
728
  else:
 
729
  hidden = self.forward_layer(hidden, layer_idx, cos_f, sin_f)
730
  if self.verbose and (layer_idx + 1) % 4 == 0:
731
  print(f" Layer {layer_idx + 1}/{cfg['n_layers']}", end='\r')
 
137
 
138
  def get_config(self):
139
  arch = self.get_arch()
140
+ n_embd = self.kv.get(f'{arch}.embedding_length', 0)
141
+ n_head = self.kv.get(f'{arch}.attention.head_count', 0)
142
+ n_head_kv = self.kv.get(f'{arch}.attention.head_count_kv', 0)
143
+
144
+ # Auto-detect head_dim: prefer fused QKV tensor dims over n_embd/n_head
145
+ # (Qwen 3.6 has n_embd=5120, n_head=24 β†’ non-integer ratio;
146
+ # real head_dim=320, computed from QKV: 10240 / (24+2*4) = 320)
147
+ head_dim = 0
148
+ qkv_name = 'blk.0.attn_qkv.weight'
149
+ if qkv_name in self.tensor_infos:
150
+ qkv_cols = self.tensor_infos[qkv_name]['dims'][1] # output dim
151
+ n_head_total = n_head + 2 * n_head_kv
152
+ if n_head_total > 0:
153
+ head_dim = qkv_cols // n_head_total
154
+ if head_dim == 0 and n_head > 0:
155
+ head_dim = n_embd // n_head
156
+
157
  return {
158
  'arch': arch,
159
  'n_layers': self.kv.get(f'{arch}.block_count', 0),
160
+ 'n_embd': n_embd,
161
+ 'n_head': n_head,
162
+ 'n_head_kv': n_head_kv,
163
  'n_ff': self.kv.get(f'{arch}.feed_forward_length', 0),
164
  'vocab_size': self.kv.get(f'{arch}.vocab_size', 0),
165
  'rms_eps': self.kv.get(f'{arch}.attention.layer_norm_rms_epsilon', 1e-6),
166
  'rope_base': self.kv.get(f'{arch}.rope.freq_base', 10000.0),
167
  'swa_window': self.kv.get(f'{arch}.attention.sliding_window', 0),
168
+ 'head_dim': head_dim,
169
  }
170
 
171
  def get_tensor_f32(self, name):
 
476
  self.model = model
477
  self.cfg = config
478
  self.verbose = verbose
479
+ self.head_dim = config.get('head_dim', config['n_embd'] // config['n_head'])
480
  self.act_fn = ACTIVATION_MAP.get(config['arch'], silu)
481
 
482
  # Importance accumulators: tensor_name β†’ (sum_x2, count)
 
719
 
720
  return hidden
721
 
722
+ def forward_qwen35_layer(self, hidden, layer_idx, cos_f, sin_f):
723
+ """Forward pass through a Qwen 3.6 hybrid layer (attention + SSM).
724
+
725
+ Qwen 3.6 uses:
726
+ - Fused attn_qkv.weight (Q+K+V in one tensor)
727
+ - attn_gate.weight (gated attention output, not attn_output)
728
+ - SSM tensors: ssm_alpha, ssm_beta, ssm_conv1d, ssm_out
729
+ - post_attention_norm.weight (instead of ffn_norm)
730
+ """
731
+ pfx = self._layer_prefix(layer_idx)
732
+ cfg = self.cfg
733
+ n_head = cfg['n_head']
734
+ n_head_kv = cfg['n_head_kv']
735
+ head_dim = self.head_dim
736
+ seq_len = hidden.shape[0]
737
+
738
+ # ── Attention norm ──
739
+ attn_norm_w = self._get_weight(f'{pfx}.attn_norm.weight')
740
+ if attn_norm_w is None:
741
+ return hidden
742
+ normed = rms_norm(hidden, attn_norm_w, cfg['rms_eps'])
743
+
744
+ # ── Fused QKV projection ──
745
+ qkv_w = self._get_weight(f'{pfx}.attn_qkv.weight')
746
+ gate_w = self._get_weight(f'{pfx}.attn_gate.weight')
747
+
748
+ attn_out_vec = np.zeros_like(hidden)
749
+ if qkv_w is not None:
750
+ self._record(f'{pfx}.attn_qkv.weight', normed)
751
+
752
+ qkv = normed @ qkv_w.T # [seq, (n_head + 2*n_head_kv) * head_dim]
753
+
754
+ # Split into Q, K, V
755
+ q_dim = n_head * head_dim
756
+ kv_dim = n_head_kv * head_dim
757
+ q = qkv[:, :q_dim].reshape(seq_len, n_head, head_dim)
758
+ k = qkv[:, q_dim:q_dim + kv_dim].reshape(seq_len, n_head_kv, head_dim)
759
+ v = qkv[:, q_dim + kv_dim:q_dim + 2 * kv_dim].reshape(seq_len, n_head_kv, head_dim)
760
+
761
+ # RoPE
762
+ q = apply_rope(q, cos_f, sin_f)
763
+ k = apply_rope(k, cos_f, sin_f)
764
+
765
+ # GQA: repeat KV heads
766
+ if n_head_kv < n_head:
767
+ rep = n_head // n_head_kv
768
+ k = np.repeat(k, rep, axis=1)
769
+ v = np.repeat(v, rep, axis=1)
770
+
771
+ # Scaled dot-product attention
772
+ q_t = q.transpose(1, 0, 2) # [n_head, seq, head_dim]
773
+ k_t = k.transpose(1, 0, 2)
774
+ v_t = v.transpose(1, 0, 2)
775
+
776
+ scale = 1.0 / np.sqrt(head_dim)
777
+ attn = np.matmul(q_t, k_t.transpose(0, 2, 1)) * scale
778
+
779
+ # Causal mask (with optional SWA)
780
+ mask = np.triu(np.full((seq_len, seq_len), -1e9, dtype=np.float32), k=1)
781
+ swa = cfg.get('swa_window', 0)
782
+ if swa and swa > 0:
783
+ for i in range(seq_len):
784
+ for j in range(0, max(0, i - swa)):
785
+ mask[i, j] = -1e9
786
+ attn = attn + mask[np.newaxis, :, :]
787
+ attn = softmax(attn, axis=-1)
788
+
789
+ out = np.matmul(attn, v_t)
790
+ attn_result = out.transpose(1, 0, 2).reshape(seq_len, -1) # [seq, n_head*head_dim]
791
+
792
+ # Gated attention output
793
+ if gate_w is not None:
794
+ self._record(f'{pfx}.attn_gate.weight', attn_result)
795
+ attn_out_vec = attn_result @ gate_w.T
796
+
797
+ # ── SSM path ──
798
+ ssm_alpha_w = self._get_weight(f'{pfx}.ssm_alpha.weight')
799
+ ssm_beta_w = self._get_weight(f'{pfx}.ssm_beta.weight')
800
+ ssm_conv_w = self._get_weight(f'{pfx}.ssm_conv1d.weight')
801
+ ssm_out_w = self._get_weight(f'{pfx}.ssm_out.weight')
802
+
803
+ ssm_out_vec = np.zeros_like(hidden)
804
+ if ssm_alpha_w is not None:
805
+ self._record(f'{pfx}.ssm_alpha.weight', normed)
806
+ if ssm_beta_w is not None:
807
+ self._record(f'{pfx}.ssm_beta.weight', normed)
808
+ if ssm_conv_w is not None:
809
+ # ssm_conv1d input is the QKV projection (reuse from attention)
810
+ if qkv_w is not None:
811
+ qkv_for_ssm = normed @ qkv_w.T
812
+ self._record(f'{pfx}.ssm_conv1d.weight', qkv_for_ssm)
813
+ if ssm_out_w is not None:
814
+ # SSM output projection β€” use normed as proxy for recurrent output
815
+ ssm_proxy = normed[:, :ssm_out_w.shape[1]] if normed.shape[-1] >= ssm_out_w.shape[1] else normed
816
+ self._record(f'{pfx}.ssm_out.weight', ssm_proxy)
817
+ ssm_out_vec = ssm_proxy @ ssm_out_w.T
818
+
819
+ # Combine attention + SSM
820
+ hidden = hidden + attn_out_vec + ssm_out_vec
821
+
822
+ # ── FFN (uses post_attention_norm instead of ffn_norm) ──
823
+ ffn_norm_w = self._get_weight(f'{pfx}.post_attention_norm.weight')
824
+ if ffn_norm_w is None:
825
+ ffn_norm_w = self._get_weight(f'{pfx}.ffn_norm.weight')
826
+ if ffn_norm_w is None:
827
+ return hidden
828
+
829
+ normed_ff = rms_norm(hidden, ffn_norm_w, cfg['rms_eps'])
830
+
831
+ gate_fw = self._get_weight(f'{pfx}.ffn_gate.weight')
832
+ up_w = self._get_weight(f'{pfx}.ffn_up.weight')
833
+ down_w = self._get_weight(f'{pfx}.ffn_down.weight')
834
+
835
+ if gate_fw is not None and up_w is not None and down_w is not None:
836
+ self._record(f'{pfx}.ffn_gate.weight', normed_ff)
837
+ self._record(f'{pfx}.ffn_up.weight', normed_ff)
838
+ gate_out = self.act_fn(normed_ff @ gate_fw.T)
839
+ up_out = normed_ff @ up_w.T
840
+ ff_mid = gate_out * up_out
841
+ self._record(f'{pfx}.ffn_down.weight', ff_mid)
842
+ ff_out = ff_mid @ down_w.T
843
+ hidden = hidden + ff_out
844
+
845
+ return hidden
846
+
847
  def forward(self, token_ids):
848
  """Full forward pass, collecting importance statistics."""
849
  cfg = self.cfg
 
861
 
862
  # Process each layer
863
  for layer_idx in range(cfg['n_layers']):
 
864
  pfx = f"blk.{layer_idx}"
865
+ has_fused_qkv = f'{pfx}.attn_qkv.weight' in self.model.tensor_infos
866
+ has_separate_q = f'{pfx}.attn_q.weight' in self.model.tensor_infos
867
  has_linear_attn = f'{pfx}.ssm_in_qkv.weight' in self.model.tensor_infos
 
868
 
869
+ if has_fused_qkv:
870
+ # Qwen 3.6 hybrid: fused QKV + SSM
871
+ hidden = self.forward_qwen35_layer(hidden, layer_idx, cos_f, sin_f)
872
+ elif has_linear_attn and not has_separate_q:
873
+ # DeltaNet-only layers
874
  hidden = self.forward_linear_attn_layer(hidden, layer_idx)
875
  else:
876
+ # Standard transformer (LLaMA, Mistral, Gemma, etc.)
877
  hidden = self.forward_layer(hidden, layer_idx, cos_f, sin_f)
878
  if self.verbose and (layer_idx + 1) % 4 == 0:
879
  print(f" Layer {layer_idx + 1}/{cfg['n_layers']}", end='\r')