CompressedGemma commited on
Commit
6bf97ec
·
verified ·
1 Parent(s): 1581489

Qwen changes

Browse files
Files changed (3) hide show
  1. generate_imatrix.py +90 -39
  2. hexstate_quantize.c +89 -57
  3. hpc_forward_merged.c +44 -34
generate_imatrix.py CHANGED
@@ -166,6 +166,8 @@ class GGUFModel:
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):
@@ -643,7 +645,7 @@ class TransformerRunner:
643
  imp_fu_p, cnt_fu_p = make_imp(f'{pfx}.ffn_up.weight', n_embd if ffn_up_w is not None else 0)
644
  imp_fd_p, cnt_fd_p = make_imp(f'{pfx}.ffn_down.weight', ffn_d if ffn_down_w is not None else 0)
645
 
646
- # Call C function — entire layer in one call
647
  lib.hexstate_forward_layer(
648
  h_ptr,
649
  norm_p,
@@ -669,16 +671,97 @@ class TransformerRunner:
669
  ctypes.c_int64(n_head), ctypes.c_int64(n_head_kv),
670
  ctypes.c_int64(head_dim), ctypes.c_float(eps))
671
 
672
- # Read back importance
673
  for name, arr, cnt in imp_refs:
674
  self.importance[name] = (arr.astype(np.float64), cnt.value)
675
 
 
 
 
 
 
 
676
  # Force-free per-layer weight buffers (~1.4 GB) before next layer
677
  del refs, imp_refs
678
  import gc; gc.collect()
679
 
680
  return hidden
681
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
682
  def _hpc_rms_norm(self, x, weight, eps):
683
  """RMS norm via HPC C library, falling back to numpy."""
684
  if self._hpc_lib and x.flags['C_CONTIGUOUS']:
@@ -1055,43 +1138,7 @@ class TransformerRunner:
1055
  hidden = hidden + ff_out
1056
  else:
1057
  # MoE path
1058
- gate_inp_w = self._get_weight(f'{pfx}.ffn_gate_inp.weight')
1059
- if gate_inp_w is not None:
1060
- self._record(f'{pfx}.ffn_gate_inp.weight', normed_ff)
1061
- router_logits = normed_ff @ gate_inp_w.T
1062
- n_experts = router_logits.shape[-1]
1063
- probs = softmax(router_logits, axis=-1)
1064
- top2 = np.argsort(probs, axis=-1)[:, -2:]
1065
-
1066
- ff_out = np.zeros_like(normed_ff)
1067
- for exp_id in range(n_experts):
1068
- ew_gate = self._get_weight(f'{pfx}.ffn_gate.{exp_id}.weight')
1069
- ew_up = self._get_weight(f'{pfx}.ffn_up.{exp_id}.weight')
1070
- ew_down = self._get_weight(f'{pfx}.ffn_down.{exp_id}.weight')
1071
- if ew_gate is None:
1072
- continue
1073
-
1074
- mask_exp = np.any(top2 == exp_id, axis=-1) # [seq]
1075
- if not np.any(mask_exp):
1076
- continue
1077
-
1078
- exp_input = normed_ff[mask_exp]
1079
- self._record(f'{pfx}.ffn_gate.{exp_id}.weight', exp_input)
1080
- self._record(f'{pfx}.ffn_up.{exp_id}.weight', exp_input)
1081
-
1082
- g = self.act_fn(exp_input @ ew_gate.T)
1083
- u = exp_input @ ew_up.T
1084
- mid = g * u
1085
- self._record(f'{pfx}.ffn_down.{exp_id}.weight', mid)
1086
-
1087
- exp_out = mid @ ew_down.T
1088
- # Weight by routing probability
1089
- for token_idx in np.where(mask_exp)[0]:
1090
- w = probs[token_idx, exp_id]
1091
- local_idx = np.sum(mask_exp[:token_idx])
1092
- ff_out[token_idx] += w * exp_out[local_idx]
1093
-
1094
- hidden = hidden + ff_out
1095
 
1096
  return hidden
1097
 
@@ -1167,6 +1214,8 @@ class TransformerRunner:
1167
  self._record(f'{pfx}.ffn_down.weight', ff_mid)
1168
  ff_out = ff_mid @ down_w.T
1169
  hidden = hidden + ff_out
 
 
1170
 
1171
  return hidden
1172
 
@@ -1308,6 +1357,8 @@ class TransformerRunner:
1308
  self._record(f'{pfx}.ffn_down.weight', ff_mid)
1309
  ff_out = ff_mid @ down_w.T
1310
  hidden = hidden + ff_out
 
 
1311
 
1312
  return hidden
1313
 
 
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
+ 'expert_count': self.kv.get(f'{arch}.expert_count', 0),
170
+ 'expert_used_count': self.kv.get(f'{arch}.expert_used_count', 0),
171
  }
172
 
173
  def get_tensor_f32(self, name):
 
645
  imp_fu_p, cnt_fu_p = make_imp(f'{pfx}.ffn_up.weight', n_embd if ffn_up_w is not None else 0)
646
  imp_fd_p, cnt_fd_p = make_imp(f'{pfx}.ffn_down.weight', ffn_d if ffn_down_w is not None else 0)
647
 
648
+ # Call C function — entire layer in one call (FFN part will be NULL if MoE)
649
  lib.hexstate_forward_layer(
650
  h_ptr,
651
  norm_p,
 
671
  ctypes.c_int64(n_head), ctypes.c_int64(n_head_kv),
672
  ctypes.c_int64(head_dim), ctypes.c_float(eps))
673
 
674
+ # Read back importance for the tensors that WERE processed in C
675
  for name, arr, cnt in imp_refs:
676
  self.importance[name] = (arr.astype(np.float64), cnt.value)
677
 
678
+ # Handle MoE FFN if C code skipped it
679
+ if ffn_gate_w is None:
680
+ # Re-normalize for FFN
681
+ normed_ff = self._hpc_rms_norm(hidden, ffn_norm_w, eps)
682
+ hidden = self._forward_moe_ffn(hidden, normed_ff, pfx)
683
+
684
  # Force-free per-layer weight buffers (~1.4 GB) before next layer
685
  del refs, imp_refs
686
  import gc; gc.collect()
687
 
688
  return hidden
689
 
690
+ def _forward_moe_ffn(self, hidden, normed_ff, pfx):
691
+ """Python-side MoE FFN handling (supports packed and shared experts)."""
692
+ gate_inp_w = self._get_weight(f'{pfx}.ffn_gate_inp.weight')
693
+ if gate_inp_w is None:
694
+ return hidden
695
+
696
+ self._record(f'{pfx}.ffn_gate_inp.weight', normed_ff)
697
+ router_logits = normed_ff @ gate_inp_w.T
698
+ n_experts = router_logits.shape[-1]
699
+ probs = softmax(router_logits, axis=-1)
700
+ topk = self.cfg.get('expert_used_count', 2)
701
+ top_k_indices = np.argsort(probs, axis=-1)[:, -topk:]
702
+
703
+ ff_out = np.zeros_like(normed_ff)
704
+
705
+ # Check for packed experts (Qwen style)
706
+ p_gate = self._get_weight(f'{pfx}.ffn_gate_exps.weight')
707
+ p_up = self._get_weight(f'{pfx}.ffn_up_exps.weight')
708
+ p_down = self._get_weight(f'{pfx}.ffn_down_exps.weight')
709
+
710
+ for exp_id in range(n_experts):
711
+ if p_gate is not None:
712
+ ew_gate = p_gate[exp_id]
713
+ ew_up = p_up[exp_id]
714
+ ew_down = p_down[exp_id]
715
+ else:
716
+ ew_gate = self._get_weight(f'{pfx}.ffn_gate.{exp_id}.weight')
717
+ ew_up = self._get_weight(f'{pfx}.ffn_up.{exp_id}.weight')
718
+ ew_down = self._get_weight(f'{pfx}.ffn_down.{exp_id}.weight')
719
+
720
+ if ew_gate is None: continue
721
+
722
+ mask_exp = np.any(top_k_indices == exp_id, axis=-1)
723
+ if not np.any(mask_exp): continue
724
+
725
+ exp_input = normed_ff[mask_exp]
726
+
727
+ # Record importance
728
+ if p_gate is not None:
729
+ self._record(f'{pfx}.ffn_gate_exps.weight', exp_input)
730
+ self._record(f'{pfx}.ffn_up_exps.weight', exp_input)
731
+ else:
732
+ self._record(f'{pfx}.ffn_gate.{exp_id}.weight', exp_input)
733
+ self._record(f'{pfx}.ffn_up.{exp_id}.weight', exp_input)
734
+
735
+ g = self.act_fn(exp_input @ ew_gate.T)
736
+ u = exp_input @ ew_up.T
737
+ mid = g * u
738
+
739
+ if p_gate is not None:
740
+ self._record(f'{pfx}.ffn_down_exps.weight', mid)
741
+ else:
742
+ self._record(f'{pfx}.ffn_down.{exp_id}.weight', mid)
743
+
744
+ exp_out = mid @ ew_down.T
745
+ indices = np.where(mask_exp)[0]
746
+ for i, tidx in enumerate(indices):
747
+ w = probs[tidx, exp_id]
748
+ ff_out[tidx] += w * exp_out[i]
749
+
750
+ # Shared experts (Qwen style)
751
+ sh_gate = self._get_weight(f'{pfx}.ffn_gate_shexp.weight')
752
+ if sh_gate is not None:
753
+ sh_up = self._get_weight(f'{pfx}.ffn_up_shexp.weight')
754
+ sh_down = self._get_weight(f'{pfx}.ffn_down_shexp.weight')
755
+ self._record(f'{pfx}.ffn_gate_shexp.weight', normed_ff)
756
+ self._record(f'{pfx}.ffn_up_shexp.weight', normed_ff)
757
+ g = self.act_fn(normed_ff @ sh_gate.T)
758
+ u = normed_ff @ sh_up.T
759
+ mid = g * u
760
+ self._record(f'{pfx}.ffn_down_shexp.weight', mid)
761
+ ff_out += mid @ sh_down.T
762
+
763
+ return hidden + ff_out
764
+
765
  def _hpc_rms_norm(self, x, weight, eps):
766
  """RMS norm via HPC C library, falling back to numpy."""
767
  if self._hpc_lib and x.flags['C_CONTIGUOUS']:
 
1138
  hidden = hidden + ff_out
1139
  else:
1140
  # MoE path
1141
+ hidden = self._forward_moe_ffn(hidden, normed_ff, pfx)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1142
 
1143
  return hidden
1144
 
 
1214
  self._record(f'{pfx}.ffn_down.weight', ff_mid)
1215
  ff_out = ff_mid @ down_w.T
1216
  hidden = hidden + ff_out
1217
+ else:
1218
+ hidden = self._forward_moe_ffn(hidden, normed_ff, pfx)
1219
 
1220
  return hidden
1221
 
 
1357
  self._record(f'{pfx}.ffn_down.weight', ff_mid)
1358
  ff_out = ff_mid @ down_w.T
1359
  hidden = hidden + ff_out
1360
+ else:
1361
+ hidden = self._forward_moe_ffn(hidden, normed_ff, pfx)
1362
 
1363
  return hidden
1364
 
hexstate_quantize.c CHANGED
@@ -4252,16 +4252,16 @@ static void hpc_read_importance(HPCGraph *g, const float *x, int64_t dim,
4252
  */
4253
  static void hpc_matmul_graph(const float *x, const float *weight, float *out,
4254
  float *importance, int64_t *count,
4255
- int64_t M, int64_t K, int64_t N)
4256
  {
4257
  /* Build HPCGraph over input columns for importance */
4258
  int64_t stride = (K > 512) ? K / 512 : 1;
4259
  int64_t n_sites = (K + stride - 1) / stride;
4260
  HPCGraph *g = hpc_create(n_sites);
 
4261
 
4262
- if (g && importance) {
4263
  /* Compute per-column energies */
4264
- float *col_energy = (float *)calloc(K, sizeof(float));
4265
  #pragma omp parallel for schedule(static)
4266
  for (int64_t j = 0; j < K; j++) {
4267
  float s = 0.0f;
@@ -4307,28 +4307,37 @@ static void hpc_matmul_graph(const float *x, const float *weight, float *out,
4307
  importance[j] += col_energy[j] * (float)boost;
4308
  }
4309
  if (count) *count += M;
4310
-
4311
- free(col_energy);
4312
- hpc_destroy(g);
4313
  }
4314
 
4315
- /* Matmul: out = x @ W.T — OpenMP over rows */
4316
  #pragma omp parallel for schedule(static)
4317
  for (int64_t i = 0; i < M; i++) {
4318
  const float *xi = x + i * K;
4319
  float *oi = out + i * N;
4320
- for (int64_t n = 0; n < N; n++) {
4321
- const float *wn = weight + n * K;
4322
- float dot = 0.0f;
4323
- for (int64_t k = 0; k < K; k++)
4324
- dot += xi[k] * wn[k];
4325
- oi[n] = dot;
 
 
 
 
 
 
 
 
 
4326
  }
4327
  }
 
 
 
4328
  }
4329
 
4330
  /* ── Helper: RMS norm (OpenMP) ── */
4331
- static void hpc_rms_norm(const float *x, const float *w, float *out,
4332
  int64_t seq, int64_t dim, float eps)
4333
  {
4334
  #pragma omp parallel for schedule(static)
@@ -4408,7 +4417,7 @@ void hexstate_forward_layer(
4408
  if (!normed) return;
4409
 
4410
  /* ══════════════ Phase 1: Attention Norm ══════════════ */
4411
- hpc_rms_norm(hidden, norm_w, normed, seq_len, n_embd, eps);
4412
 
4413
  /* ══════════════ Phase 2: QKV Projection via HPC Graph ══════════════ */
4414
  float *attn_out = (float *)calloc(seq_len * n_embd, sizeof(float));
@@ -4421,7 +4430,7 @@ void hexstate_forward_layer(
4421
 
4422
  /* Graph-based matmul: importance via HPCGraph marginals */
4423
  hpc_matmul_graph(normed, qkv_w, qkv, imp_qkv, cnt_qkv,
4424
- seq_len, n_embd, qkv_dim);
4425
 
4426
  /* Split Q, K, V */
4427
  int64_t q_total = n_head * head_dim;
@@ -4444,8 +4453,10 @@ void hexstate_forward_layer(
4444
  HPCGraph *attn_graph = hpc_create(n_head);
4445
  float *S = (float *)calloc(n_head * head_dim * head_dim, sizeof(float));
4446
  float *z_acc = (float *)calloc(n_head * head_dim, sizeof(float));
 
 
4447
 
4448
- if (attn_graph && S && z_acc) {
4449
  for (int64_t t = 0; t < seq_len; t++) {
4450
  /* Extract Q/K/V for this timestep (handle strided layout) */
4451
  float *qt_base = qkv + t * qkv_dim;
@@ -4519,15 +4530,14 @@ void hexstate_forward_layer(
4519
  den += qf[d] * zh[d];
4520
  float inv_den = 1.0f / den;
4521
 
4522
- /* Write to attn_out at position [t, h*head_dim ... ] */
4523
- float *ao = attn_out + t * n_embd;
4524
  for (int64_t d2 = 0; d2 < head_dim; d2++) {
4525
  float num = 0.0f;
4526
  for (int64_t d1 = 0; d1 < head_dim; d1++)
4527
  num += qf[d1] * Sh[d1 * head_dim + d2];
4528
- /* Accumulate into attn_out (multiple heads write here) */
4529
- if (h * head_dim + d2 < n_embd)
4530
- ao[h * head_dim + d2] = num * inv_den;
4531
  }
4532
  }
4533
 
@@ -4539,25 +4549,25 @@ void hexstate_forward_layer(
4539
 
4540
  /* Gate projection if present */
4541
  if (gate_w && gate_rows > 0) {
4542
- /* attn_out is [seq, n_head*head_dim], gate_w is [n_embd, n_head*head_dim] */
4543
- /* gate_rows may be larger than n_embd, allocate exactly what we need */
4544
- float *gated = (float *)malloc(seq_len * gate_rows * sizeof(float));
4545
  if (gated) {
4546
- hpc_matmul_graph(attn_out, gate_w, gated, imp_gate, cnt_gate,
4547
- seq_len, n_head * head_dim, gate_rows);
4548
-
4549
- int64_t copy_dim = (gate_rows > n_embd) ? n_embd : gate_rows;
4550
- /* Must copy row-by-row since strides may differ */
4551
- #pragma omp parallel for schedule(static)
4552
- for (int64_t i = 0; i < seq_len; i++) {
4553
- memcpy(attn_out + i * n_embd, gated + i * gate_rows, copy_dim * sizeof(float));
4554
- if (copy_dim < n_embd) {
4555
- memset(attn_out + i * n_embd + copy_dim, 0, (n_embd - copy_dim) * sizeof(float));
4556
- }
4557
  }
4558
  free(gated);
4559
  }
 
 
 
 
 
4560
  }
 
4561
 
4562
  if (attn_graph) hpc_destroy(attn_graph);
4563
  free(S); free(z_acc); free(qkv);
@@ -4568,23 +4578,25 @@ void hexstate_forward_layer(
4568
  float *K_buf = (float *)malloc(seq_len * k_dim * sizeof(float));
4569
  float *V_buf = (float *)malloc(seq_len * v_dim * sizeof(float));
4570
  if (!Q || !K_buf || !V_buf) {
4571
- free(Q); free(K_buf); free(V_buf);
4572
  free(normed); free(attn_out);
4573
  return;
4574
  }
4575
 
4576
- hpc_matmul_graph(normed, q_w, Q, imp_q, cnt_q, seq_len, n_embd, q_dim);
4577
- hpc_matmul_graph(normed, k_w, K_buf, imp_k, cnt_k, seq_len, n_embd, k_dim);
4578
- hpc_matmul_graph(normed, v_w, V_buf, imp_v, cnt_v, seq_len, n_embd, v_dim);
4579
 
4580
  /* Same HPC attention as above but with separate Q/K/V buffers */
4581
  int64_t hd_q = q_dim / n_head;
4582
  int64_t hd_kv = k_dim / n_head_kv;
 
4583
  HPCGraph *attn_graph = hpc_create(n_head);
4584
  float *S = (float *)calloc(n_head * hd_kv * hd_kv, sizeof(float));
4585
  float *z_acc = (float *)calloc(n_head * hd_kv, sizeof(float));
 
4586
 
4587
- if (attn_graph && S && z_acc) {
4588
  for (int64_t t = 0; t < seq_len; t++) {
4589
  /* Encode heads into graph */
4590
  for (int64_t h = 0; h < n_head; h++) {
@@ -4635,15 +4647,14 @@ void hexstate_forward_layer(
4635
  den += qf * zh[d];
4636
  }
4637
  float inv_den = 1.0f / den;
4638
- float *ao = attn_out + t * n_embd;
4639
  for (int64_t d2 = 0; d2 < hd_kv; d2++) {
4640
  float num = 0.0f;
4641
  for (int64_t d1 = 0; d1 < feat; d1++) {
4642
  float qf = (qh[d1] > 0 ? qh[d1] : 0) + 1e-6f;
4643
  num += qf * Sh[d1*hd_kv+d2];
4644
  }
4645
- if (h*hd_kv+d2 < n_embd)
4646
- ao[h*hd_kv+d2] = num * inv_den;
4647
  }
4648
  }
4649
  if (t > 0 && t % 64 == 0)
@@ -4653,16 +4664,36 @@ void hexstate_forward_layer(
4653
 
4654
  /* Output projection */
4655
  if (o_w && o_cols > 0) {
4656
- int64_t attn_dim = n_head * hd_kv;
4657
- if (attn_dim > n_embd) attn_dim = n_embd;
 
 
 
 
 
 
 
 
 
 
 
 
 
4658
  float *projected = (float *)calloc(seq_len * n_embd, sizeof(float));
4659
  if (projected) {
4660
- hpc_matmul_graph(attn_out, o_w, projected, imp_o, cnt_o,
4661
- seq_len, o_cols, n_embd);
4662
  memcpy(attn_out, projected, seq_len * n_embd * sizeof(float));
4663
  free(projected);
4664
  }
 
 
 
 
 
 
4665
  }
 
4666
 
4667
  if (attn_graph) hpc_destroy(attn_graph);
4668
  free(S); free(z_acc);
@@ -4682,13 +4713,13 @@ void hexstate_forward_layer(
4682
  float *up_out = (float *)malloc(seq_len * ffn_dim * sizeof(float));
4683
 
4684
  if (normed_ff && gate_out && up_out) {
4685
- hpc_rms_norm(hidden, ffn_norm_w, normed_ff, seq_len, n_embd, eps);
4686
 
4687
  /* Graph-based matmul for FFN with importance */
4688
  hpc_matmul_graph(normed_ff, ffn_gate_w, gate_out,
4689
- imp_ffn_gate, cnt_ffn_gate, seq_len, n_embd, ffn_dim);
4690
  hpc_matmul_graph(normed_ff, ffn_up_w, up_out,
4691
- imp_ffn_up, cnt_ffn_up, seq_len, n_embd, ffn_dim);
4692
 
4693
  /* SiLU(gate) * up */
4694
  hpc_silu(gate_out, seq_len * ffn_dim);
@@ -4697,16 +4728,16 @@ void hexstate_forward_layer(
4697
  gate_out[i] *= up_out[i];
4698
 
4699
  /* Down projection: graph-based importance recording */
4700
- float *ff_out = (float *)malloc(seq_len * n_embd * sizeof(float));
4701
- if (ff_out) {
4702
- hpc_matmul_graph(gate_out, ffn_down_w, ff_out,
4703
  imp_ffn_down, cnt_ffn_down,
4704
- seq_len, ffn_dim, n_embd);
4705
  /* Residual add */
4706
  #pragma omp parallel for schedule(static)
4707
  for (int64_t i = 0; i < total; i++)
4708
- hidden[i] += ff_out[i];
4709
- free(ff_out);
4710
  }
4711
  }
4712
 
@@ -4717,6 +4748,7 @@ void hexstate_forward_layer(
4717
  free(attn_out);
4718
  }
4719
 
 
4720
  #ifndef HEXSTATE_LIBRARY
4721
  /* ═══════════════════════════════════════════════════════════════════════════
4722
  * MAIN
 
4252
  */
4253
  static void hpc_matmul_graph(const float *x, const float *weight, float *out,
4254
  float *importance, int64_t *count,
4255
+ int64_t M, int64_t K, int64_t N, int trans_w)
4256
  {
4257
  /* Build HPCGraph over input columns for importance */
4258
  int64_t stride = (K > 512) ? K / 512 : 1;
4259
  int64_t n_sites = (K + stride - 1) / stride;
4260
  HPCGraph *g = hpc_create(n_sites);
4261
+ float *col_energy = (float *)calloc(K, sizeof(float));
4262
 
4263
+ if (g && col_energy) {
4264
  /* Compute per-column energies */
 
4265
  #pragma omp parallel for schedule(static)
4266
  for (int64_t j = 0; j < K; j++) {
4267
  float s = 0.0f;
 
4307
  importance[j] += col_energy[j] * (float)boost;
4308
  }
4309
  if (count) *count += M;
 
 
 
4310
  }
4311
 
4312
+ /* Matmul: out = x @ W.T (trans_w=0) or x @ W (trans_w=1) */
4313
  #pragma omp parallel for schedule(static)
4314
  for (int64_t i = 0; i < M; i++) {
4315
  const float *xi = x + i * K;
4316
  float *oi = out + i * N;
4317
+ if (trans_w) {
4318
+ for (int64_t n = 0; n < N; n++) {
4319
+ float dot = 0.0f;
4320
+ for (int64_t k = 0; k < K; k++)
4321
+ dot += xi[k] * weight[k * N + n];
4322
+ oi[n] = dot;
4323
+ }
4324
+ } else {
4325
+ for (int64_t n = 0; n < N; n++) {
4326
+ const float *wn = weight + n * K;
4327
+ float dot = 0.0f;
4328
+ for (int64_t k = 0; k < K; k++)
4329
+ dot += xi[k] * wn[k];
4330
+ oi[n] = dot;
4331
+ }
4332
  }
4333
  }
4334
+
4335
+ if (col_energy) free(col_energy);
4336
+ if (g) hpc_destroy(g);
4337
  }
4338
 
4339
  /* ── Helper: RMS norm (OpenMP) ── */
4340
+ void hexstate_rms_norm(const float *x, const float *w, float *out,
4341
  int64_t seq, int64_t dim, float eps)
4342
  {
4343
  #pragma omp parallel for schedule(static)
 
4417
  if (!normed) return;
4418
 
4419
  /* ══════════════ Phase 1: Attention Norm ══════════════ */
4420
+ hexstate_rms_norm(hidden, norm_w, normed, seq_len, n_embd, eps);
4421
 
4422
  /* ══════════════ Phase 2: QKV Projection via HPC Graph ══════════════ */
4423
  float *attn_out = (float *)calloc(seq_len * n_embd, sizeof(float));
 
4430
 
4431
  /* Graph-based matmul: importance via HPCGraph marginals */
4432
  hpc_matmul_graph(normed, qkv_w, qkv, imp_qkv, cnt_qkv,
4433
+ seq_len, n_embd, qkv_dim, 0);
4434
 
4435
  /* Split Q, K, V */
4436
  int64_t q_total = n_head * head_dim;
 
4453
  HPCGraph *attn_graph = hpc_create(n_head);
4454
  float *S = (float *)calloc(n_head * head_dim * head_dim, sizeof(float));
4455
  float *z_acc = (float *)calloc(n_head * head_dim, sizeof(float));
4456
+ int64_t inner_dim = n_head * head_dim;
4457
+ float *attn_inner = (float *)calloc(seq_len * inner_dim, sizeof(float));
4458
 
4459
+ if (attn_graph && S && z_acc && attn_inner) {
4460
  for (int64_t t = 0; t < seq_len; t++) {
4461
  /* Extract Q/K/V for this timestep (handle strided layout) */
4462
  float *qt_base = qkv + t * qkv_dim;
 
4530
  den += qf[d] * zh[d];
4531
  float inv_den = 1.0f / den;
4532
 
4533
+ /* Write to attn_inner at position [t, h*head_dim ... ] */
4534
+ float *ao = attn_inner + t * inner_dim;
4535
  for (int64_t d2 = 0; d2 < head_dim; d2++) {
4536
  float num = 0.0f;
4537
  for (int64_t d1 = 0; d1 < head_dim; d1++)
4538
  num += qf[d1] * Sh[d1 * head_dim + d2];
4539
+ /* Accumulate into attn_inner (multiple heads write here) */
4540
+ ao[h * head_dim + d2] = num * inv_den;
 
4541
  }
4542
  }
4543
 
 
4549
 
4550
  /* Gate projection if present */
4551
  if (gate_w && gate_rows > 0) {
4552
+ int trans_w = (gate_rows == inner_dim) ? 1 : 0;
4553
+ int64_t N_out = trans_w ? n_embd : gate_rows;
4554
+ float *gated = (float *)malloc(seq_len * N_out * sizeof(float));
4555
  if (gated) {
4556
+ hpc_matmul_graph(attn_inner, gate_w, gated, imp_gate, cnt_gate,
4557
+ seq_len, inner_dim, N_out, trans_w);
4558
+ for (int64_t t = 0; t < seq_len; t++) {
4559
+ int64_t copy_dim = N_out < n_embd ? N_out : n_embd;
4560
+ memcpy(attn_out + t * n_embd, gated + t * N_out, copy_dim * sizeof(float));
 
 
 
 
 
 
4561
  }
4562
  free(gated);
4563
  }
4564
+ } else {
4565
+ for (int64_t t = 0; t < seq_len; t++) {
4566
+ int64_t copy_dim = inner_dim < n_embd ? inner_dim : n_embd;
4567
+ memcpy(attn_out + t * n_embd, attn_inner + t * inner_dim, copy_dim * sizeof(float));
4568
+ }
4569
  }
4570
+ if (attn_inner) free(attn_inner);
4571
 
4572
  if (attn_graph) hpc_destroy(attn_graph);
4573
  free(S); free(z_acc); free(qkv);
 
4578
  float *K_buf = (float *)malloc(seq_len * k_dim * sizeof(float));
4579
  float *V_buf = (float *)malloc(seq_len * v_dim * sizeof(float));
4580
  if (!Q || !K_buf || !V_buf) {
4581
+ if(Q) free(Q); if(K_buf) free(K_buf); if(V_buf) free(V_buf);
4582
  free(normed); free(attn_out);
4583
  return;
4584
  }
4585
 
4586
+ hpc_matmul_graph(normed, q_w, Q, imp_q, cnt_q, seq_len, n_embd, q_dim, 0);
4587
+ hpc_matmul_graph(normed, k_w, K_buf, imp_k, cnt_k, seq_len, n_embd, k_dim, 0);
4588
+ hpc_matmul_graph(normed, v_w, V_buf, imp_v, cnt_v, seq_len, n_embd, v_dim, 0);
4589
 
4590
  /* Same HPC attention as above but with separate Q/K/V buffers */
4591
  int64_t hd_q = q_dim / n_head;
4592
  int64_t hd_kv = k_dim / n_head_kv;
4593
+ int64_t inner_dim = n_head * hd_kv;
4594
  HPCGraph *attn_graph = hpc_create(n_head);
4595
  float *S = (float *)calloc(n_head * hd_kv * hd_kv, sizeof(float));
4596
  float *z_acc = (float *)calloc(n_head * hd_kv, sizeof(float));
4597
+ float *attn_inner = (float *)calloc(seq_len * inner_dim, sizeof(float));
4598
 
4599
+ if (attn_graph && S && z_acc && attn_inner) {
4600
  for (int64_t t = 0; t < seq_len; t++) {
4601
  /* Encode heads into graph */
4602
  for (int64_t h = 0; h < n_head; h++) {
 
4647
  den += qf * zh[d];
4648
  }
4649
  float inv_den = 1.0f / den;
4650
+ float *ao = attn_inner + t * inner_dim;
4651
  for (int64_t d2 = 0; d2 < hd_kv; d2++) {
4652
  float num = 0.0f;
4653
  for (int64_t d1 = 0; d1 < feat; d1++) {
4654
  float qf = (qh[d1] > 0 ? qh[d1] : 0) + 1e-6f;
4655
  num += qf * Sh[d1*hd_kv+d2];
4656
  }
4657
+ ao[h*hd_kv+d2] = num * inv_den;
 
4658
  }
4659
  }
4660
  if (t > 0 && t % 64 == 0)
 
4664
 
4665
  /* Output projection */
4666
  if (o_w && o_cols > 0) {
4667
+ float *proj_in = attn_inner;
4668
+ int free_proj_in = 0;
4669
+ if (inner_dim != o_cols) {
4670
+ proj_in = (float *)calloc(seq_len * o_cols, sizeof(float));
4671
+ if (proj_in) {
4672
+ for (int64_t t = 0; t < seq_len; t++) {
4673
+ int64_t copy_dim = inner_dim < o_cols ? inner_dim : o_cols;
4674
+ memcpy(proj_in + t * o_cols, attn_inner + t * inner_dim, copy_dim * sizeof(float));
4675
+ }
4676
+ free_proj_in = 1;
4677
+ } else {
4678
+ proj_in = attn_inner;
4679
+ }
4680
+ }
4681
+
4682
  float *projected = (float *)calloc(seq_len * n_embd, sizeof(float));
4683
  if (projected) {
4684
+ hpc_matmul_graph(proj_in, o_w, projected, imp_o, cnt_o,
4685
+ seq_len, o_cols, n_embd, 0);
4686
  memcpy(attn_out, projected, seq_len * n_embd * sizeof(float));
4687
  free(projected);
4688
  }
4689
+ if (free_proj_in && proj_in != attn_inner) free(proj_in);
4690
+ } else {
4691
+ for (int64_t t = 0; t < seq_len; t++) {
4692
+ int64_t copy_dim = inner_dim < n_embd ? inner_dim : n_embd;
4693
+ memcpy(attn_out + t * n_embd, attn_inner + t * inner_dim, copy_dim * sizeof(float));
4694
+ }
4695
  }
4696
+ if (attn_inner) free(attn_inner);
4697
 
4698
  if (attn_graph) hpc_destroy(attn_graph);
4699
  free(S); free(z_acc);
 
4713
  float *up_out = (float *)malloc(seq_len * ffn_dim * sizeof(float));
4714
 
4715
  if (normed_ff && gate_out && up_out) {
4716
+ hexstate_rms_norm(hidden, ffn_norm_w, normed_ff, seq_len, n_embd, eps);
4717
 
4718
  /* Graph-based matmul for FFN with importance */
4719
  hpc_matmul_graph(normed_ff, ffn_gate_w, gate_out,
4720
+ imp_ffn_gate, cnt_ffn_gate, seq_len, n_embd, ffn_dim, 0);
4721
  hpc_matmul_graph(normed_ff, ffn_up_w, up_out,
4722
+ imp_ffn_up, cnt_ffn_up, seq_len, n_embd, ffn_dim, 0);
4723
 
4724
  /* SiLU(gate) * up */
4725
  hpc_silu(gate_out, seq_len * ffn_dim);
 
4728
  gate_out[i] *= up_out[i];
4729
 
4730
  /* Down projection: graph-based importance recording */
4731
+ float *ff_out_buf = (float *)malloc(seq_len * n_embd * sizeof(float));
4732
+ if (ff_out_buf) {
4733
+ hpc_matmul_graph(gate_out, ffn_down_w, ff_out_buf,
4734
  imp_ffn_down, cnt_ffn_down,
4735
+ seq_len, ffn_dim, n_embd, 0);
4736
  /* Residual add */
4737
  #pragma omp parallel for schedule(static)
4738
  for (int64_t i = 0; i < total; i++)
4739
+ hidden[i] += ff_out_buf[i];
4740
+ free(ff_out_buf);
4741
  }
4742
  }
4743
 
 
4748
  free(attn_out);
4749
  }
4750
 
4751
+
4752
  #ifndef HEXSTATE_LIBRARY
4753
  /* ═══════════════════════════════════════════════════════════════════════════
4754
  * MAIN
hpc_forward_merged.c CHANGED
@@ -75,16 +75,16 @@ static void hpc_read_importance(HPCGraph *g, const float *x, int64_t dim,
75
  */
76
  static void hpc_matmul_graph(const float *x, const float *weight, float *out,
77
  float *importance, int64_t *count,
78
- int64_t M, int64_t K, int64_t N)
79
  {
80
  /* Build HPCGraph over input columns for importance */
81
  int64_t stride = (K > 512) ? K / 512 : 1;
82
  int64_t n_sites = (K + stride - 1) / stride;
83
  HPCGraph *g = hpc_create(n_sites);
 
84
 
85
- if (g && importance) {
86
  /* Compute per-column energies */
87
- float *col_energy = (float *)calloc(K, sizeof(float));
88
  #pragma omp parallel for schedule(static)
89
  for (int64_t j = 0; j < K; j++) {
90
  float s = 0.0f;
@@ -130,24 +130,33 @@ static void hpc_matmul_graph(const float *x, const float *weight, float *out,
130
  importance[j] += col_energy[j] * (float)boost;
131
  }
132
  if (count) *count += M;
133
-
134
- free(col_energy);
135
- hpc_destroy(g);
136
  }
137
 
138
- /* Matmul: out = x @ W.T — OpenMP over rows */
139
  #pragma omp parallel for schedule(static)
140
  for (int64_t i = 0; i < M; i++) {
141
  const float *xi = x + i * K;
142
  float *oi = out + i * N;
143
- for (int64_t n = 0; n < N; n++) {
144
- const float *wn = weight + n * K;
145
- float dot = 0.0f;
146
- for (int64_t k = 0; k < K; k++)
147
- dot += xi[k] * wn[k];
148
- oi[n] = dot;
 
 
 
 
 
 
 
 
 
149
  }
150
  }
 
 
 
151
  }
152
 
153
  /* ── Helper: RMS norm (OpenMP) ── */
@@ -243,8 +252,8 @@ void hexstate_forward_layer(
243
  if (!qkv) { free(normed); free(attn_out); return; }
244
 
245
  /* Graph-based matmul: importance via HPCGraph marginals */
246
- hpc_matmul_graph(normed, qkv_w, qkv, imp_qkv, cnt_qkv,
247
- seq_len, n_embd, qkv_dim);
248
 
249
  /* Split Q, K, V */
250
  int64_t q_total = n_head * head_dim;
@@ -363,14 +372,15 @@ void hexstate_forward_layer(
363
 
364
  /* Gate projection if present */
365
  if (gate_w && gate_rows > 0) {
366
- /* attn_inner is [seq, n_head*head_dim], gate_w is [gate_rows, n_head*head_dim] */
367
- float *gated = (float *)malloc(seq_len * n_embd * sizeof(float));
 
368
  if (gated) {
369
- hpc_matmul_graph(attn_inner, gate_w, gated, imp_gate, cnt_gate,
370
- seq_len, inner_dim, gate_rows);
371
  for (int64_t t = 0; t < seq_len; t++) {
372
- int64_t copy_dim = gate_rows < n_embd ? gate_rows : n_embd;
373
- memcpy(attn_out + t * n_embd, gated + t * gate_rows, copy_dim * sizeof(float));
374
  }
375
  free(gated);
376
  }
@@ -391,14 +401,14 @@ void hexstate_forward_layer(
391
  float *K_buf = (float *)malloc(seq_len * k_dim * sizeof(float));
392
  float *V_buf = (float *)malloc(seq_len * v_dim * sizeof(float));
393
  if (!Q || !K_buf || !V_buf) {
394
- free(Q); free(K_buf); free(V_buf);
395
  free(normed); free(attn_out);
396
  return;
397
  }
398
 
399
- hpc_matmul_graph(normed, q_w, Q, imp_q, cnt_q, seq_len, n_embd, q_dim);
400
- hpc_matmul_graph(normed, k_w, K_buf, imp_k, cnt_k, seq_len, n_embd, k_dim);
401
- hpc_matmul_graph(normed, v_w, V_buf, imp_v, cnt_v, seq_len, n_embd, v_dim);
402
 
403
  /* Same HPC attention as above but with separate Q/K/V buffers */
404
  int64_t hd_q = q_dim / n_head;
@@ -495,7 +505,7 @@ void hexstate_forward_layer(
495
  float *projected = (float *)calloc(seq_len * n_embd, sizeof(float));
496
  if (projected) {
497
  hpc_matmul_graph(proj_in, o_w, projected, imp_o, cnt_o,
498
- seq_len, o_cols, n_embd);
499
  memcpy(attn_out, projected, seq_len * n_embd * sizeof(float));
500
  free(projected);
501
  }
@@ -530,9 +540,9 @@ void hexstate_forward_layer(
530
 
531
  /* Graph-based matmul for FFN with importance */
532
  hpc_matmul_graph(normed_ff, ffn_gate_w, gate_out,
533
- imp_ffn_gate, cnt_ffn_gate, seq_len, n_embd, ffn_dim);
534
  hpc_matmul_graph(normed_ff, ffn_up_w, up_out,
535
- imp_ffn_up, cnt_ffn_up, seq_len, n_embd, ffn_dim);
536
 
537
  /* SiLU(gate) * up */
538
  hpc_silu(gate_out, seq_len * ffn_dim);
@@ -541,16 +551,16 @@ void hexstate_forward_layer(
541
  gate_out[i] *= up_out[i];
542
 
543
  /* Down projection: graph-based importance recording */
544
- float *ff_out = (float *)malloc(seq_len * n_embd * sizeof(float));
545
- if (ff_out) {
546
- hpc_matmul_graph(gate_out, ffn_down_w, ff_out,
547
  imp_ffn_down, cnt_ffn_down,
548
- seq_len, ffn_dim, n_embd);
549
  /* Residual add */
550
  #pragma omp parallel for schedule(static)
551
  for (int64_t i = 0; i < total; i++)
552
- hidden[i] += ff_out[i];
553
- free(ff_out);
554
  }
555
  }
556
 
 
75
  */
76
  static void hpc_matmul_graph(const float *x, const float *weight, float *out,
77
  float *importance, int64_t *count,
78
+ int64_t M, int64_t K, int64_t N, int trans_w)
79
  {
80
  /* Build HPCGraph over input columns for importance */
81
  int64_t stride = (K > 512) ? K / 512 : 1;
82
  int64_t n_sites = (K + stride - 1) / stride;
83
  HPCGraph *g = hpc_create(n_sites);
84
+ float *col_energy = (float *)calloc(K, sizeof(float));
85
 
86
+ if (g && col_energy) {
87
  /* Compute per-column energies */
 
88
  #pragma omp parallel for schedule(static)
89
  for (int64_t j = 0; j < K; j++) {
90
  float s = 0.0f;
 
130
  importance[j] += col_energy[j] * (float)boost;
131
  }
132
  if (count) *count += M;
 
 
 
133
  }
134
 
135
+ /* Matmul: out = x @ W.T (trans_w=0) or x @ W (trans_w=1) */
136
  #pragma omp parallel for schedule(static)
137
  for (int64_t i = 0; i < M; i++) {
138
  const float *xi = x + i * K;
139
  float *oi = out + i * N;
140
+ if (trans_w) {
141
+ for (int64_t n = 0; n < N; n++) {
142
+ float dot = 0.0f;
143
+ for (int64_t k = 0; k < K; k++)
144
+ dot += xi[k] * weight[k * N + n];
145
+ oi[n] = dot;
146
+ }
147
+ } else {
148
+ for (int64_t n = 0; n < N; n++) {
149
+ const float *wn = weight + n * K;
150
+ float dot = 0.0f;
151
+ for (int64_t k = 0; k < K; k++)
152
+ dot += xi[k] * wn[k];
153
+ oi[n] = dot;
154
+ }
155
  }
156
  }
157
+
158
+ if (col_energy) free(col_energy);
159
+ if (g) hpc_destroy(g);
160
  }
161
 
162
  /* ── Helper: RMS norm (OpenMP) ── */
 
252
  if (!qkv) { free(normed); free(attn_out); return; }
253
 
254
  /* Graph-based matmul: importance via HPCGraph marginals */
255
+ printf("matmul qkv M=%ld K=%ld N=%ld\n", (long)seq_len, (long)n_embd, (long)qkv_dim); fflush(stdout); hpc_matmul_graph(normed, qkv_w, qkv, imp_qkv, cnt_qkv,
256
+ seq_len, n_embd, qkv_dim, 0);
257
 
258
  /* Split Q, K, V */
259
  int64_t q_total = n_head * head_dim;
 
372
 
373
  /* Gate projection if present */
374
  if (gate_w && gate_rows > 0) {
375
+ int trans_w = (gate_rows == inner_dim) ? 1 : 0;
376
+ int64_t N_out = trans_w ? n_embd : gate_rows;
377
+ float *gated = (float *)malloc(seq_len * N_out * sizeof(float));
378
  if (gated) {
379
+ printf("matmul gate M=%ld K=%ld N=%ld trans=%d\n", (long)seq_len, (long)inner_dim, (long)N_out, trans_w); fflush(stdout); hpc_matmul_graph(attn_inner, gate_w, gated, imp_gate, cnt_gate,
380
+ seq_len, inner_dim, N_out, trans_w);
381
  for (int64_t t = 0; t < seq_len; t++) {
382
+ int64_t copy_dim = N_out < n_embd ? N_out : n_embd;
383
+ memcpy(attn_out + t * n_embd, gated + t * N_out, copy_dim * sizeof(float));
384
  }
385
  free(gated);
386
  }
 
401
  float *K_buf = (float *)malloc(seq_len * k_dim * sizeof(float));
402
  float *V_buf = (float *)malloc(seq_len * v_dim * sizeof(float));
403
  if (!Q || !K_buf || !V_buf) {
404
+ if(Q) free(Q); if(K_buf) free(K_buf); if(V_buf) free(V_buf);
405
  free(normed); free(attn_out);
406
  return;
407
  }
408
 
409
+ hpc_matmul_graph(normed, q_w, Q, imp_q, cnt_q, seq_len, n_embd, q_dim, 0);
410
+ hpc_matmul_graph(normed, k_w, K_buf, imp_k, cnt_k, seq_len, n_embd, k_dim, 0);
411
+ hpc_matmul_graph(normed, v_w, V_buf, imp_v, cnt_v, seq_len, n_embd, v_dim, 0);
412
 
413
  /* Same HPC attention as above but with separate Q/K/V buffers */
414
  int64_t hd_q = q_dim / n_head;
 
505
  float *projected = (float *)calloc(seq_len * n_embd, sizeof(float));
506
  if (projected) {
507
  hpc_matmul_graph(proj_in, o_w, projected, imp_o, cnt_o,
508
+ seq_len, o_cols, n_embd, 0);
509
  memcpy(attn_out, projected, seq_len * n_embd * sizeof(float));
510
  free(projected);
511
  }
 
540
 
541
  /* Graph-based matmul for FFN with importance */
542
  hpc_matmul_graph(normed_ff, ffn_gate_w, gate_out,
543
+ imp_ffn_gate, cnt_ffn_gate, seq_len, n_embd, ffn_dim, 0);
544
  hpc_matmul_graph(normed_ff, ffn_up_w, up_out,
545
+ imp_ffn_up, cnt_ffn_up, seq_len, n_embd, ffn_dim, 0);
546
 
547
  /* SiLU(gate) * up */
548
  hpc_silu(gate_out, seq_len * ffn_dim);
 
551
  gate_out[i] *= up_out[i];
552
 
553
  /* Down projection: graph-based importance recording */
554
+ float *ff_out_buf = (float *)malloc(seq_len * n_embd * sizeof(float));
555
+ if (ff_out_buf) {
556
+ hpc_matmul_graph(gate_out, ffn_down_w, ff_out_buf,
557
  imp_ffn_down, cnt_ffn_down,
558
+ seq_len, ffn_dim, n_embd, 0);
559
  /* Residual add */
560
  #pragma omp parallel for schedule(static)
561
  for (int64_t i = 0; i < total; i++)
562
+ hidden[i] += ff_out_buf[i];
563
+ free(ff_out_buf);
564
  }
565
  }
566