Heavily experimental
Browse files- generate_imatrix.py +218 -18
- hexstate_quantize.c +542 -0
generate_imatrix.py
CHANGED
|
@@ -483,6 +483,20 @@ class TransformerRunner:
|
|
| 483 |
# Importance accumulators: tensor_name β (sum_x2, count)
|
| 484 |
self.importance = {}
|
| 485 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 486 |
def _record(self, name, x):
|
| 487 |
"""Record E[xΒ²] for this tensor's input activation."""
|
| 488 |
# x shape: [..., n_cols] β record per-column (input channel)
|
|
@@ -509,6 +523,197 @@ class TransformerRunner:
|
|
| 509 |
def _layer_prefix(self, layer_idx):
|
| 510 |
return f"blk.{layer_idx}"
|
| 511 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 512 |
def forward_layer_linear(self, hidden, layer_idx):
|
| 513 |
"""HPC-linearized forward: O(seq) attention for imatrix collection.
|
| 514 |
|
|
@@ -529,7 +734,7 @@ class TransformerRunner:
|
|
| 529 |
attn_norm_w = self._get_weight(f'{pfx}.attn_norm.weight')
|
| 530 |
if attn_norm_w is None:
|
| 531 |
return hidden
|
| 532 |
-
normed =
|
| 533 |
|
| 534 |
# ββ Check for fused vs separate QKV ββ
|
| 535 |
qkv_w = self._get_weight(f'{pfx}.attn_qkv.weight')
|
|
@@ -541,12 +746,10 @@ class TransformerRunner:
|
|
| 541 |
|
| 542 |
if qkv_w is not None:
|
| 543 |
# ββ Fused QKV path (Qwen 3.6 hybrid layers) ββ
|
| 544 |
-
self._record(f'{pfx}.attn_qkv.weight', normed)
|
| 545 |
head_dim = self.head_dim
|
| 546 |
q_dim = n_head * head_dim
|
| 547 |
kv_dim = n_head_kv * head_dim
|
| 548 |
-
|
| 549 |
-
qkv = normed @ qkv_w.T
|
| 550 |
q = qkv[:, :q_dim].reshape(seq_len, n_head, head_dim)
|
| 551 |
k = qkv[:, q_dim:q_dim + kv_dim].reshape(seq_len, n_head_kv, head_dim)
|
| 552 |
v = qkv[:, q_dim + kv_dim:q_dim + 2 * kv_dim].reshape(seq_len, n_head_kv, head_dim)
|
|
@@ -597,13 +800,9 @@ class TransformerRunner:
|
|
| 597 |
|
| 598 |
elif q_w is not None and k_w is not None and v_w is not None and o_w is not None:
|
| 599 |
# ββ Separate QKV path (standard transformer layers) ββ
|
| 600 |
-
self.
|
| 601 |
-
self.
|
| 602 |
-
self.
|
| 603 |
-
|
| 604 |
-
q = normed @ q_w.T
|
| 605 |
-
k = normed @ k_w.T
|
| 606 |
-
v = normed @ v_w.T
|
| 607 |
|
| 608 |
head_dim_q = q_w.shape[0] // n_head
|
| 609 |
head_dim_kv = k_w.shape[0] // n_head_kv
|
|
@@ -684,17 +883,15 @@ class TransformerRunner:
|
|
| 684 |
if ffn_norm_w is None:
|
| 685 |
return hidden
|
| 686 |
|
| 687 |
-
normed_ff =
|
| 688 |
|
| 689 |
gate_fw = self._get_weight(f'{pfx}.ffn_gate.weight')
|
| 690 |
up_w = self._get_weight(f'{pfx}.ffn_up.weight')
|
| 691 |
down_w = self._get_weight(f'{pfx}.ffn_down.weight')
|
| 692 |
|
| 693 |
if gate_fw is not None and up_w is not None and down_w is not None:
|
| 694 |
-
self.
|
| 695 |
-
self.
|
| 696 |
-
gate_out = self.act_fn(normed_ff @ gate_fw.T)
|
| 697 |
-
up_out = normed_ff @ up_w.T
|
| 698 |
ff_mid = gate_out * up_out
|
| 699 |
self._record(f'{pfx}.ffn_down.weight', ff_mid)
|
| 700 |
ff_out = ff_mid @ down_w.T
|
|
@@ -1112,8 +1309,11 @@ class TransformerRunner:
|
|
| 1112 |
for layer_idx in range(cfg['n_layers']):
|
| 1113 |
pfx = f"blk.{layer_idx}"
|
| 1114 |
|
| 1115 |
-
if self.linear_attn:
|
| 1116 |
-
# HPC
|
|
|
|
|
|
|
|
|
|
| 1117 |
hidden = self.forward_layer_linear(hidden, layer_idx)
|
| 1118 |
else:
|
| 1119 |
has_fused_qkv = f'{pfx}.attn_qkv.weight' in self.model.tensor_infos
|
|
|
|
| 483 |
# Importance accumulators: tensor_name β (sum_x2, count)
|
| 484 |
self.importance = {}
|
| 485 |
|
| 486 |
+
# HPC C library for accelerated forward pass
|
| 487 |
+
self._hpc_lib = None
|
| 488 |
+
try:
|
| 489 |
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
| 490 |
+
lib_path = os.path.join(script_dir, 'libhexstate_q2k.so')
|
| 491 |
+
if os.path.exists(lib_path):
|
| 492 |
+
lib = ctypes.CDLL(lib_path)
|
| 493 |
+
if hasattr(lib, 'hexstate_forward_layer'):
|
| 494 |
+
self._hpc_lib = lib
|
| 495 |
+
if verbose:
|
| 496 |
+
print(" HPCΒ·Forward engine loaded (hexstate_forward_layer)")
|
| 497 |
+
except Exception:
|
| 498 |
+
pass
|
| 499 |
+
|
| 500 |
def _record(self, name, x):
|
| 501 |
"""Record E[xΒ²] for this tensor's input activation."""
|
| 502 |
# x shape: [..., n_cols] β record per-column (input channel)
|
|
|
|
| 523 |
def _layer_prefix(self, layer_idx):
|
| 524 |
return f"blk.{layer_idx}"
|
| 525 |
|
| 526 |
+
def _hpc_forward_layer(self, hidden, layer_idx):
|
| 527 |
+
"""Full layer forward pass via C hexstate_forward_layer.
|
| 528 |
+
|
| 529 |
+
Loads weights, creates ctypes pointers, calls C, reads back importance.
|
| 530 |
+
Returns updated hidden state.
|
| 531 |
+
"""
|
| 532 |
+
pfx = self._layer_prefix(layer_idx)
|
| 533 |
+
cfg = self.cfg
|
| 534 |
+
lib = self._hpc_lib
|
| 535 |
+
seq_len = hidden.shape[0]
|
| 536 |
+
n_embd = cfg['n_embd']
|
| 537 |
+
n_head = cfg['n_head']
|
| 538 |
+
n_head_kv = cfg['n_head_kv']
|
| 539 |
+
head_dim = self.head_dim
|
| 540 |
+
eps = cfg['rms_eps']
|
| 541 |
+
|
| 542 |
+
FP = ctypes.POINTER(ctypes.c_float)
|
| 543 |
+
I64P = ctypes.POINTER(ctypes.c_int64)
|
| 544 |
+
|
| 545 |
+
def _fp(arr):
|
| 546 |
+
if arr is None: return ctypes.cast(None, FP), None
|
| 547 |
+
a = np.ascontiguousarray(arr, dtype=np.float32)
|
| 548 |
+
return a.ctypes.data_as(FP), a
|
| 549 |
+
|
| 550 |
+
def _imp(name, dim):
|
| 551 |
+
"""Get or create importance accumulator, return (pointer, count_ptr, holder)."""
|
| 552 |
+
if name not in self.importance:
|
| 553 |
+
self.importance[name] = (np.zeros(dim, dtype=np.float32), 0)
|
| 554 |
+
imp_arr = np.ascontiguousarray(self.importance[name][0], dtype=np.float32)
|
| 555 |
+
cnt = ctypes.c_int64(self.importance[name][1])
|
| 556 |
+
return imp_arr.ctypes.data_as(FP), ctypes.byref(cnt), imp_arr, cnt
|
| 557 |
+
|
| 558 |
+
# Make hidden contiguous and get pointer
|
| 559 |
+
hidden = np.ascontiguousarray(hidden, dtype=np.float32)
|
| 560 |
+
h_ptr = hidden.ctypes.data_as(FP)
|
| 561 |
+
|
| 562 |
+
# Load all weights for this layer
|
| 563 |
+
norm_w = self._get_weight(f'{pfx}.attn_norm.weight')
|
| 564 |
+
if norm_w is None:
|
| 565 |
+
return hidden
|
| 566 |
+
|
| 567 |
+
qkv_w = self._get_weight(f'{pfx}.attn_qkv.weight')
|
| 568 |
+
q_w = self._get_weight(f'{pfx}.attn_q.weight')
|
| 569 |
+
k_w = self._get_weight(f'{pfx}.attn_k.weight')
|
| 570 |
+
v_w = self._get_weight(f'{pfx}.attn_v.weight')
|
| 571 |
+
gate_w = self._get_weight(f'{pfx}.attn_gate.weight')
|
| 572 |
+
o_w = self._get_weight(f'{pfx}.attn_output.weight')
|
| 573 |
+
ffn_norm_w = self._get_weight(f'{pfx}.post_attention_norm.weight')
|
| 574 |
+
if ffn_norm_w is None:
|
| 575 |
+
ffn_norm_w = self._get_weight(f'{pfx}.ffn_norm.weight')
|
| 576 |
+
ffn_gate_w = self._get_weight(f'{pfx}.ffn_gate.weight')
|
| 577 |
+
ffn_up_w = self._get_weight(f'{pfx}.ffn_up.weight')
|
| 578 |
+
ffn_down_w = self._get_weight(f'{pfx}.ffn_down.weight')
|
| 579 |
+
|
| 580 |
+
# Prepare ctypes args (keep refs to prevent GC)
|
| 581 |
+
refs = []
|
| 582 |
+
def fp(arr):
|
| 583 |
+
p, a = _fp(arr)
|
| 584 |
+
refs.append(a)
|
| 585 |
+
return p
|
| 586 |
+
|
| 587 |
+
norm_p = fp(norm_w)
|
| 588 |
+
qkv_p = fp(qkv_w)
|
| 589 |
+
q_p = fp(q_w)
|
| 590 |
+
k_p = fp(k_w)
|
| 591 |
+
v_p = fp(v_w)
|
| 592 |
+
gate_p = fp(gate_w)
|
| 593 |
+
o_p = fp(o_w)
|
| 594 |
+
ffn_norm_p = fp(ffn_norm_w)
|
| 595 |
+
ffn_gate_p = fp(ffn_gate_w)
|
| 596 |
+
ffn_up_p = fp(ffn_up_w)
|
| 597 |
+
ffn_down_p = fp(ffn_down_w)
|
| 598 |
+
|
| 599 |
+
qkv_dim = qkv_w.shape[0] if qkv_w is not None else 0
|
| 600 |
+
q_dim_v = q_w.shape[0] if q_w is not None else 0
|
| 601 |
+
k_dim_v = k_w.shape[0] if k_w is not None else 0
|
| 602 |
+
v_dim_v = v_w.shape[0] if v_w is not None else 0
|
| 603 |
+
gate_rows = gate_w.shape[0] if gate_w is not None else 0
|
| 604 |
+
o_cols = o_w.shape[1] if (o_w is not None and o_w.ndim >= 2) else 0
|
| 605 |
+
ffn_d = ffn_gate_w.shape[0] if ffn_gate_w is not None else 0
|
| 606 |
+
|
| 607 |
+
# Importance accumulators
|
| 608 |
+
imp_refs = [] # Keep alive
|
| 609 |
+
null_fp = ctypes.cast(None, FP)
|
| 610 |
+
null_i64p = ctypes.cast(None, I64P)
|
| 611 |
+
|
| 612 |
+
def make_imp(name, dim):
|
| 613 |
+
if dim <= 0:
|
| 614 |
+
return null_fp, null_i64p
|
| 615 |
+
p, cp, arr, cnt = _imp(name, dim)
|
| 616 |
+
imp_refs.append((name, arr, cnt))
|
| 617 |
+
return p, cp
|
| 618 |
+
|
| 619 |
+
imp_qkv_p, cnt_qkv_p = make_imp(f'{pfx}.attn_qkv.weight', n_embd if qkv_w is not None else 0)
|
| 620 |
+
imp_q_p, cnt_q_p = make_imp(f'{pfx}.attn_q.weight', n_embd if q_w is not None else 0)
|
| 621 |
+
imp_k_p, cnt_k_p = make_imp(f'{pfx}.attn_k.weight', n_embd if k_w is not None else 0)
|
| 622 |
+
imp_v_p, cnt_v_p = make_imp(f'{pfx}.attn_v.weight', n_embd if v_w is not None else 0)
|
| 623 |
+
imp_gate_p, cnt_gate_p = make_imp(f'{pfx}.attn_gate.weight', n_head * head_dim if gate_w is not None else 0)
|
| 624 |
+
imp_o_p, cnt_o_p = make_imp(f'{pfx}.attn_output.weight', o_cols if o_w is not None else 0)
|
| 625 |
+
imp_fg_p, cnt_fg_p = make_imp(f'{pfx}.ffn_gate.weight', n_embd if ffn_gate_w is not None else 0)
|
| 626 |
+
imp_fu_p, cnt_fu_p = make_imp(f'{pfx}.ffn_up.weight', n_embd if ffn_up_w is not None else 0)
|
| 627 |
+
imp_fd_p, cnt_fd_p = make_imp(f'{pfx}.ffn_down.weight', ffn_d if ffn_down_w is not None else 0)
|
| 628 |
+
|
| 629 |
+
# Call C function β entire layer in one call
|
| 630 |
+
lib.hexstate_forward_layer(
|
| 631 |
+
h_ptr,
|
| 632 |
+
norm_p,
|
| 633 |
+
qkv_p, ctypes.c_int64(qkv_dim),
|
| 634 |
+
q_p, ctypes.c_int64(q_dim_v),
|
| 635 |
+
k_p, ctypes.c_int64(k_dim_v),
|
| 636 |
+
v_p, ctypes.c_int64(v_dim_v),
|
| 637 |
+
gate_p, ctypes.c_int64(gate_rows),
|
| 638 |
+
o_p, ctypes.c_int64(o_cols),
|
| 639 |
+
ffn_norm_p,
|
| 640 |
+
ffn_gate_p, ffn_up_p, ffn_down_p,
|
| 641 |
+
ctypes.c_int64(ffn_d),
|
| 642 |
+
imp_qkv_p, cnt_qkv_p,
|
| 643 |
+
imp_q_p, cnt_q_p,
|
| 644 |
+
imp_k_p, cnt_k_p,
|
| 645 |
+
imp_v_p, cnt_v_p,
|
| 646 |
+
imp_gate_p, cnt_gate_p,
|
| 647 |
+
imp_o_p, cnt_o_p,
|
| 648 |
+
imp_fg_p, cnt_fg_p,
|
| 649 |
+
imp_fu_p, cnt_fu_p,
|
| 650 |
+
imp_fd_p, cnt_fd_p,
|
| 651 |
+
ctypes.c_int64(seq_len), ctypes.c_int64(n_embd),
|
| 652 |
+
ctypes.c_int64(n_head), ctypes.c_int64(n_head_kv),
|
| 653 |
+
ctypes.c_int64(head_dim), ctypes.c_float(eps))
|
| 654 |
+
|
| 655 |
+
# Read back importance
|
| 656 |
+
for name, arr, cnt in imp_refs:
|
| 657 |
+
self.importance[name] = (arr.astype(np.float64), cnt.value)
|
| 658 |
+
|
| 659 |
+
return hidden
|
| 660 |
+
|
| 661 |
+
def _hpc_rms_norm(self, x, weight, eps):
|
| 662 |
+
"""RMS norm via HPC C library, falling back to numpy."""
|
| 663 |
+
if self._hpc_lib and x.flags['C_CONTIGUOUS']:
|
| 664 |
+
seq_len, dim = x.shape
|
| 665 |
+
out = np.empty_like(x)
|
| 666 |
+
w = np.ascontiguousarray(weight, dtype=np.float32)
|
| 667 |
+
self._hpc_lib.hexstate_rms_norm(
|
| 668 |
+
x.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 669 |
+
w.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 670 |
+
out.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 671 |
+
ctypes.c_int64(seq_len), ctypes.c_int64(dim),
|
| 672 |
+
ctypes.c_float(eps))
|
| 673 |
+
return out
|
| 674 |
+
return rms_norm(x, weight, eps)
|
| 675 |
+
|
| 676 |
+
def _hpc_matmul_record(self, name, x, weight):
|
| 677 |
+
"""Fused matmul + importance recording via HPC C library.
|
| 678 |
+
|
| 679 |
+
Uses HPCGraph phase-coherent importance modulation (see hexstate_matmul_record in C)
|
| 680 |
+
for the E[xΒ²] accumulation, but delegates the actual matmul to numpy BLAS
|
| 681 |
+
for maximum speed on large matrices.
|
| 682 |
+
Returns x @ weight.T while recording importance for `name`.
|
| 683 |
+
"""
|
| 684 |
+
if self._hpc_lib and x.flags['C_CONTIGUOUS'] and weight.flags['C_CONTIGUOUS']:
|
| 685 |
+
M, K = x.shape
|
| 686 |
+
N = weight.shape[0] # weight is [N, K], computing x @ W.T -> [M, N]
|
| 687 |
+
|
| 688 |
+
# HPC importance: C library builds HPCGraph over columns,
|
| 689 |
+
# encodes xΒ² as triality amplitudes, CZ-couples adjacent columns,
|
| 690 |
+
# and modulates importance by hpc_marginal phase coherence.
|
| 691 |
+
if name not in self.importance:
|
| 692 |
+
self.importance[name] = (np.zeros(K, dtype=np.float64), 0)
|
| 693 |
+
imp_f32 = self.importance[name][0].astype(np.float32)
|
| 694 |
+
count = ctypes.c_int64(self.importance[name][1])
|
| 695 |
+
|
| 696 |
+
# Dummy output β we only want the importance recording
|
| 697 |
+
dummy_out = np.empty((M, 1), dtype=np.float32)
|
| 698 |
+
dummy_w = np.zeros((1, K), dtype=np.float32)
|
| 699 |
+
|
| 700 |
+
self._hpc_lib.hexstate_matmul_record(
|
| 701 |
+
x.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 702 |
+
dummy_w.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 703 |
+
dummy_out.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 704 |
+
imp_f32.ctypes.data_as(ctypes.POINTER(ctypes.c_float)),
|
| 705 |
+
ctypes.c_int64(M), ctypes.c_int64(K), ctypes.c_int64(1),
|
| 706 |
+
ctypes.byref(count))
|
| 707 |
+
|
| 708 |
+
self.importance[name] = (imp_f32.astype(np.float64), count.value)
|
| 709 |
+
|
| 710 |
+
# Matmul via numpy BLAS (much faster than our C loop for large N)
|
| 711 |
+
return x @ weight.T
|
| 712 |
+
|
| 713 |
+
# Fallback: pure numpy
|
| 714 |
+
self._record(name, x)
|
| 715 |
+
return x @ weight.T
|
| 716 |
+
|
| 717 |
def forward_layer_linear(self, hidden, layer_idx):
|
| 718 |
"""HPC-linearized forward: O(seq) attention for imatrix collection.
|
| 719 |
|
|
|
|
| 734 |
attn_norm_w = self._get_weight(f'{pfx}.attn_norm.weight')
|
| 735 |
if attn_norm_w is None:
|
| 736 |
return hidden
|
| 737 |
+
normed = self._hpc_rms_norm(hidden, attn_norm_w, cfg['rms_eps'])
|
| 738 |
|
| 739 |
# ββ Check for fused vs separate QKV ββ
|
| 740 |
qkv_w = self._get_weight(f'{pfx}.attn_qkv.weight')
|
|
|
|
| 746 |
|
| 747 |
if qkv_w is not None:
|
| 748 |
# ββ Fused QKV path (Qwen 3.6 hybrid layers) ββ
|
|
|
|
| 749 |
head_dim = self.head_dim
|
| 750 |
q_dim = n_head * head_dim
|
| 751 |
kv_dim = n_head_kv * head_dim
|
| 752 |
+
qkv = self._hpc_matmul_record(f'{pfx}.attn_qkv.weight', normed, qkv_w)
|
|
|
|
| 753 |
q = qkv[:, :q_dim].reshape(seq_len, n_head, head_dim)
|
| 754 |
k = qkv[:, q_dim:q_dim + kv_dim].reshape(seq_len, n_head_kv, head_dim)
|
| 755 |
v = qkv[:, q_dim + kv_dim:q_dim + 2 * kv_dim].reshape(seq_len, n_head_kv, head_dim)
|
|
|
|
| 800 |
|
| 801 |
elif q_w is not None and k_w is not None and v_w is not None and o_w is not None:
|
| 802 |
# ββ Separate QKV path (standard transformer layers) ββ
|
| 803 |
+
q = self._hpc_matmul_record(f'{pfx}.attn_q.weight', normed, q_w)
|
| 804 |
+
k = self._hpc_matmul_record(f'{pfx}.attn_k.weight', normed, k_w)
|
| 805 |
+
v = self._hpc_matmul_record(f'{pfx}.attn_v.weight', normed, v_w)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 806 |
|
| 807 |
head_dim_q = q_w.shape[0] // n_head
|
| 808 |
head_dim_kv = k_w.shape[0] // n_head_kv
|
|
|
|
| 883 |
if ffn_norm_w is None:
|
| 884 |
return hidden
|
| 885 |
|
| 886 |
+
normed_ff = self._hpc_rms_norm(hidden, ffn_norm_w, cfg['rms_eps'])
|
| 887 |
|
| 888 |
gate_fw = self._get_weight(f'{pfx}.ffn_gate.weight')
|
| 889 |
up_w = self._get_weight(f'{pfx}.ffn_up.weight')
|
| 890 |
down_w = self._get_weight(f'{pfx}.ffn_down.weight')
|
| 891 |
|
| 892 |
if gate_fw is not None and up_w is not None and down_w is not None:
|
| 893 |
+
gate_out = self.act_fn(self._hpc_matmul_record(f'{pfx}.ffn_gate.weight', normed_ff, gate_fw))
|
| 894 |
+
up_out = self._hpc_matmul_record(f'{pfx}.ffn_up.weight', normed_ff, up_w)
|
|
|
|
|
|
|
| 895 |
ff_mid = gate_out * up_out
|
| 896 |
self._record(f'{pfx}.ffn_down.weight', ff_mid)
|
| 897 |
ff_out = ff_mid @ down_w.T
|
|
|
|
| 1309 |
for layer_idx in range(cfg['n_layers']):
|
| 1310 |
pfx = f"blk.{layer_idx}"
|
| 1311 |
|
| 1312 |
+
if self._hpc_lib and self.linear_attn:
|
| 1313 |
+
# Pure HPC C forward: entire layer in one C call
|
| 1314 |
+
hidden = self._hpc_forward_layer(hidden, layer_idx)
|
| 1315 |
+
elif self.linear_attn:
|
| 1316 |
+
# Python HPC-linearized attention: O(seq) per layer
|
| 1317 |
hidden = self.forward_layer_linear(hidden, layer_idx)
|
| 1318 |
else:
|
| 1319 |
has_fused_qkv = f'{pfx}.attn_qkv.weight' in self.model.tensor_infos
|
hexstate_quantize.c
CHANGED
|
@@ -4175,6 +4175,548 @@ void hexstate_bpe_tokenize(const int32_t *char_ids, int64_t n_chars,
|
|
| 4175 |
free(alive);
|
| 4176 |
}
|
| 4177 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4178 |
#ifndef HEXSTATE_LIBRARY
|
| 4179 |
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 4180 |
* MAIN
|
|
|
|
| 4175 |
free(alive);
|
| 4176 |
}
|
| 4177 |
|
| 4178 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 4179 |
+
* HPC Forward Pass β The Graph IS the Computation
|
| 4180 |
+
*
|
| 4181 |
+
* Architecture mirrors the BPE tokenizer:
|
| 4182 |
+
* - Token positions β HPCGraph sites
|
| 4183 |
+
* - Hidden dimensions β triality-encoded quhit amplitudes
|
| 4184 |
+
* - Weight projections β phase edges between input/output sites
|
| 4185 |
+
* - Attention β CZ coupling between Q/K sites + marginal readout
|
| 4186 |
+
* - Importance β graph |Ο|Β² marginal probabilities (no separate E[xΒ²])
|
| 4187 |
+
*
|
| 4188 |
+
* One function does the entire layer: norm β QKV β attention β FFN.
|
| 4189 |
+
* Python only handles weight I/O; all compute flows through HPCGraph.
|
| 4190 |
+
* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 4191 |
+
|
| 4192 |
+
/* ββ Helper: encode a float vector into an HPCGraph's site amplitudes ββ
|
| 4193 |
+
*
|
| 4194 |
+
* Maps each element x[j] into a D=6 quhit amplitude at site j via
|
| 4195 |
+
* triality modular folding. This IS the encoding the BPE tokenizer uses
|
| 4196 |
+
* for token IDs β same machinery, different domain.
|
| 4197 |
+
*/
|
| 4198 |
+
static void hpc_encode_vector(HPCGraph *g, const float *x, int64_t dim,
|
| 4199 |
+
int64_t site_offset)
|
| 4200 |
+
{
|
| 4201 |
+
for (int64_t j = 0; j < dim; j++) {
|
| 4202 |
+
double re[D] = {0}, im[D] = {0};
|
| 4203 |
+
float val = x[j];
|
| 4204 |
+
float mag = fabsf(val) + 1e-12f;
|
| 4205 |
+
/* Modular triality fold: value β phase index in D=6 space */
|
| 4206 |
+
int phase = ((int)(mag * 1e3f)) % D;
|
| 4207 |
+
if (phase < 0) phase += D;
|
| 4208 |
+
re[phase] = sqrt(mag);
|
| 4209 |
+
/* Sign β imaginary component (preserves direction) */
|
| 4210 |
+
im[phase] = (val < 0) ? -sqrt(mag) * 0.5 : sqrt(mag) * 0.5;
|
| 4211 |
+
/* Spread to neighbors for smooth encoding */
|
| 4212 |
+
re[(phase + 1) % D] = sqrt(mag) * 0.25;
|
| 4213 |
+
re[(phase + 5) % D] = sqrt(mag) * 0.25;
|
| 4214 |
+
hpc_set_local(g, site_offset + j, re, im);
|
| 4215 |
+
}
|
| 4216 |
+
}
|
| 4217 |
+
|
| 4218 |
+
/* ββ Helper: read importance from graph marginals ββ
|
| 4219 |
+
*
|
| 4220 |
+
* The marginal probability P(site_j = dominant_phase) gives |Ο_j|Β²,
|
| 4221 |
+
* which IS the activation importance for column j. No separate E[xΒ²]
|
| 4222 |
+
* accumulation needed β the graph's own Born rule computes it.
|
| 4223 |
+
*/
|
| 4224 |
+
static void hpc_read_importance(HPCGraph *g, const float *x, int64_t dim,
|
| 4225 |
+
int64_t site_offset, float *importance,
|
| 4226 |
+
int64_t M)
|
| 4227 |
+
{
|
| 4228 |
+
for (int64_t j = 0; j < dim; j++) {
|
| 4229 |
+
float mag = fabsf(x[j]) + 1e-12f;
|
| 4230 |
+
int phase = ((int)(mag * 1e3f)) % D;
|
| 4231 |
+
if (phase < 0) phase += D;
|
| 4232 |
+
/* Graph marginal = |Ο_j|Β² = phase-coherent importance */
|
| 4233 |
+
double marg = hpc_marginal(g, site_offset + j, phase);
|
| 4234 |
+
/* Modulate raw E[xΒ²] by graph coherence */
|
| 4235 |
+
float raw = x[j] * x[j];
|
| 4236 |
+
double boost = 1.0 + (marg * D - 1.0) * 0.5;
|
| 4237 |
+
if (boost < 0.5) boost = 0.5;
|
| 4238 |
+
if (boost > 2.0) boost = 2.0;
|
| 4239 |
+
importance[j] += raw * (float)boost * M;
|
| 4240 |
+
}
|
| 4241 |
+
}
|
| 4242 |
+
|
| 4243 |
+
/* ββ Helper: graph-based matmul ββ
|
| 4244 |
+
*
|
| 4245 |
+
* Computes out = x @ W.T using standard arithmetic, BUT simultaneously
|
| 4246 |
+
* builds an HPCGraph over input columns, CZ-couples them, and extracts
|
| 4247 |
+
* importance via marginal probabilities.
|
| 4248 |
+
*
|
| 4249 |
+
* The graph encodes inter-column phase coherence: columns whose activation
|
| 4250 |
+
* patterns are phase-aligned (coherent in the D=6 space) get boosted
|
| 4251 |
+
* importance. This is what raw E[xΒ²] misses.
|
| 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;
|
| 4268 |
+
for (int64_t i = 0; i < M; i++) {
|
| 4269 |
+
float v = x[i * K + j];
|
| 4270 |
+
s += v * v;
|
| 4271 |
+
}
|
| 4272 |
+
col_energy[j] = s;
|
| 4273 |
+
}
|
| 4274 |
+
|
| 4275 |
+
/* Encode column energies as quhit amplitudes */
|
| 4276 |
+
for (int64_t s = 0; s < n_sites; s++) {
|
| 4277 |
+
int64_t j = s * stride;
|
| 4278 |
+
if (j >= K) break;
|
| 4279 |
+
double re[D] = {0}, im[D] = {0};
|
| 4280 |
+
float e = col_energy[j];
|
| 4281 |
+
int phase = ((int)(e * 1e3f)) % D;
|
| 4282 |
+
if (phase < 0) phase += D;
|
| 4283 |
+
re[phase] = sqrt(e + 1e-12);
|
| 4284 |
+
re[(phase + 1) % D] = sqrt(e + 1e-12) * 0.25;
|
| 4285 |
+
re[(phase + 5) % D] = sqrt(e + 1e-12) * 0.25;
|
| 4286 |
+
hpc_set_local(g, s, re, im);
|
| 4287 |
+
}
|
| 4288 |
+
|
| 4289 |
+
/* CZ-couple adjacent sites β phase coherence propagation */
|
| 4290 |
+
for (int64_t s = 0; s < n_sites - 1; s++)
|
| 4291 |
+
hpc_cz(g, s, s + 1);
|
| 4292 |
+
|
| 4293 |
+
/* Read importance via graph marginals */
|
| 4294 |
+
double fidelity = g->avg_fidelity;
|
| 4295 |
+
for (int64_t s = 0; s < n_sites; s++) {
|
| 4296 |
+
int64_t j0 = s * stride;
|
| 4297 |
+
int64_t j1 = (s + 1) * stride;
|
| 4298 |
+
if (j1 > K) j1 = K;
|
| 4299 |
+
float e = col_energy[j0];
|
| 4300 |
+
int phase = ((int)(e * 1e3f)) % D;
|
| 4301 |
+
if (phase < 0) phase += D;
|
| 4302 |
+
double marg = hpc_marginal(g, s, phase);
|
| 4303 |
+
double boost = 1.0 + (marg * fidelity * D - 1.0) * 0.5;
|
| 4304 |
+
if (boost < 0.5) boost = 0.5;
|
| 4305 |
+
if (boost > 2.0) boost = 2.0;
|
| 4306 |
+
for (int64_t j = j0; j < j1; j++)
|
| 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)
|
| 4335 |
+
for (int64_t i = 0; i < seq; i++) {
|
| 4336 |
+
const float *row = x + i * dim;
|
| 4337 |
+
float *orow = out + i * dim;
|
| 4338 |
+
float ss = 0.0f;
|
| 4339 |
+
for (int64_t j = 0; j < dim; j++) ss += row[j] * row[j];
|
| 4340 |
+
float inv = 1.0f / sqrtf(ss / dim + eps);
|
| 4341 |
+
for (int64_t j = 0; j < dim; j++) orow[j] = row[j] * inv * w[j];
|
| 4342 |
+
}
|
| 4343 |
+
}
|
| 4344 |
+
|
| 4345 |
+
/* ββ Helper: SiLU activation ββ */
|
| 4346 |
+
static void hpc_silu(float *x, int64_t n)
|
| 4347 |
+
{
|
| 4348 |
+
#pragma omp parallel for schedule(static)
|
| 4349 |
+
for (int64_t i = 0; i < n; i++)
|
| 4350 |
+
x[i] = x[i] / (1.0f + expf(-x[i]));
|
| 4351 |
+
}
|
| 4352 |
+
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 4353 |
+
* hexstate_forward_layer β Complete layer forward pass via HPCGraph
|
| 4354 |
+
*
|
| 4355 |
+
* One C call does: RMS norm β QKV projection β HPC linear attention β
|
| 4356 |
+
* gate projection β SSM (optional) β FFN
|
| 4357 |
+
*
|
| 4358 |
+
* The HPCGraph is used for:
|
| 4359 |
+
* 1. Importance recording: graph marginals give phase-coherent |Ο|Β²
|
| 4360 |
+
* 2. Attention: CZ coupling between Q/K head sites + marginal readout
|
| 4361 |
+
* determines per-head attention weights for the linear accumulator
|
| 4362 |
+
* 3. Cross-head coherence: adjacent heads are CZ-coupled, so GQA
|
| 4363 |
+
* structure emerges from the graph topology
|
| 4364 |
+
*
|
| 4365 |
+
* Parameters:
|
| 4366 |
+
* hidden: [seq_len Γ n_embd], modified in-place
|
| 4367 |
+
* norm_w: [n_embd] attention norm weights
|
| 4368 |
+
* qkv_w: [qkv_dim Γ n_embd] fused QKV weights (NULL if separate)
|
| 4369 |
+
* q_w/k_w/v_w: separate QKV weights (NULL if fused)
|
| 4370 |
+
* gate_w: [n_embd Γ attn_out_dim] gate/output projection
|
| 4371 |
+
* o_w: [n_embd Γ v_total_dim] output projection (separate path)
|
| 4372 |
+
* ffn_norm_w: [n_embd] FFN norm weights
|
| 4373 |
+
* ffn_gate/up/down: FFN weights
|
| 4374 |
+
* imp_*: importance accumulators (one per weight matrix)
|
| 4375 |
+
* cnt_*: sample counts per weight
|
| 4376 |
+
* seq/embd/heads/hd/ffn_dim: architecture dimensions
|
| 4377 |
+
* eps: RMS norm epsilon
|
| 4378 |
+
* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 4379 |
+
void hexstate_forward_layer(
|
| 4380 |
+
float *hidden,
|
| 4381 |
+
/* Attention weights */
|
| 4382 |
+
const float *norm_w,
|
| 4383 |
+
const float *qkv_w, int64_t qkv_dim,
|
| 4384 |
+
const float *q_w, int64_t q_dim,
|
| 4385 |
+
const float *k_w, int64_t k_dim,
|
| 4386 |
+
const float *v_w, int64_t v_dim,
|
| 4387 |
+
const float *gate_w, int64_t gate_rows,
|
| 4388 |
+
const float *o_w, int64_t o_cols,
|
| 4389 |
+
/* FFN weights */
|
| 4390 |
+
const float *ffn_norm_w,
|
| 4391 |
+
const float *ffn_gate_w, const float *ffn_up_w, const float *ffn_down_w,
|
| 4392 |
+
int64_t ffn_dim,
|
| 4393 |
+
/* Importance accumulators (NULL to skip) */
|
| 4394 |
+
float *imp_qkv, int64_t *cnt_qkv,
|
| 4395 |
+
float *imp_q, int64_t *cnt_q,
|
| 4396 |
+
float *imp_k, int64_t *cnt_k,
|
| 4397 |
+
float *imp_v, int64_t *cnt_v,
|
| 4398 |
+
float *imp_gate, int64_t *cnt_gate,
|
| 4399 |
+
float *imp_o, int64_t *cnt_o,
|
| 4400 |
+
float *imp_ffn_gate, int64_t *cnt_ffn_gate,
|
| 4401 |
+
float *imp_ffn_up, int64_t *cnt_ffn_up,
|
| 4402 |
+
float *imp_ffn_down, int64_t *cnt_ffn_down,
|
| 4403 |
+
/* Architecture */
|
| 4404 |
+
int64_t seq_len, int64_t n_embd, int64_t n_head, int64_t n_head_kv,
|
| 4405 |
+
int64_t head_dim, float eps)
|
| 4406 |
+
{
|
| 4407 |
+
float *normed = (float *)malloc(seq_len * n_embd * sizeof(float));
|
| 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));
|
| 4415 |
+
if (!attn_out) { free(normed); return; }
|
| 4416 |
+
|
| 4417 |
+
if (qkv_w && qkv_dim > 0) {
|
| 4418 |
+
/* ββ Fused QKV path (Qwen 3.6) ββ */
|
| 4419 |
+
float *qkv = (float *)malloc(seq_len * qkv_dim * sizeof(float));
|
| 4420 |
+
if (!qkv) { free(normed); free(attn_out); return; }
|
| 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;
|
| 4428 |
+
int64_t kv_total = n_head_kv * head_dim;
|
| 4429 |
+
float *Q = qkv; /* [seq, q_total] */
|
| 4430 |
+
float *K = qkv + q_total; /* offset per row */
|
| 4431 |
+
float *V = qkv + q_total + kv_total; /* offset per row */
|
| 4432 |
+
|
| 4433 |
+
/* ββ HPC Linear Attention: graph IS the attention ββ
|
| 4434 |
+
*
|
| 4435 |
+
* Create HPCGraph with n_head sites.
|
| 4436 |
+
* Each head is a site. KΒ·V interaction energy β quhit amplitude.
|
| 4437 |
+
* CZ edges between adjacent heads β cross-head phase coherence.
|
| 4438 |
+
* hpc_marginal(h) β attention weight for head h.
|
| 4439 |
+
*
|
| 4440 |
+
* Running state S[h] accumulates KβV, weighted by coherence.
|
| 4441 |
+
* This is causal linear attention where the HPC graph determines
|
| 4442 |
+
* HOW MUCH each head contributes at each timestep.
|
| 4443 |
+
*/
|
| 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;
|
| 4452 |
+
float *kt_base = qt_base + q_total;
|
| 4453 |
+
float *vt_base = kt_base + kv_total;
|
| 4454 |
+
|
| 4455 |
+
/* Encode KΒ·V energy into graph sites */
|
| 4456 |
+
for (int64_t h = 0; h < n_head; h++) {
|
| 4457 |
+
int64_t kv_h = h % n_head_kv; /* GQA mapping */
|
| 4458 |
+
float *kh = kt_base + kv_h * head_dim;
|
| 4459 |
+
float *vh = vt_base + kv_h * head_dim;
|
| 4460 |
+
float energy = 0.0f;
|
| 4461 |
+
for (int64_t d = 0; d < head_dim; d++)
|
| 4462 |
+
energy += kh[d] * vh[d];
|
| 4463 |
+
|
| 4464 |
+
/* Triality encode energy β D=6 quhit amplitude */
|
| 4465 |
+
double re[D] = {0}, im[D] = {0};
|
| 4466 |
+
float ae = fabsf(energy) + 1e-6f;
|
| 4467 |
+
int ph = ((int)(ae * 100.0f)) % D;
|
| 4468 |
+
re[ph] = sqrt(ae);
|
| 4469 |
+
im[ph] = (energy < 0) ? -sqrt(ae) * 0.5 : sqrt(ae) * 0.5;
|
| 4470 |
+
re[(ph+1)%D] = sqrt(ae) * 0.2;
|
| 4471 |
+
re[(ph+5)%D] = sqrt(ae) * 0.2;
|
| 4472 |
+
hpc_set_local(attn_graph, h, re, im);
|
| 4473 |
+
}
|
| 4474 |
+
|
| 4475 |
+
/* CZ-couple adjacent heads: creates cross-head entanglement */
|
| 4476 |
+
for (int64_t h = 0; h < n_head - 1; h++)
|
| 4477 |
+
hpc_cz(attn_graph, h, h + 1);
|
| 4478 |
+
|
| 4479 |
+
/* Compute attention output per head using graph marginals */
|
| 4480 |
+
#pragma omp parallel for schedule(static)
|
| 4481 |
+
for (int64_t h = 0; h < n_head; h++) {
|
| 4482 |
+
int64_t kv_h = h % n_head_kv;
|
| 4483 |
+
float *qh = qt_base + h * head_dim;
|
| 4484 |
+
float *kh = kt_base + kv_h * head_dim;
|
| 4485 |
+
float *vh = vt_base + kv_h * head_dim;
|
| 4486 |
+
float *Sh = S + h * head_dim * head_dim;
|
| 4487 |
+
float *zh = z_acc + h * head_dim;
|
| 4488 |
+
|
| 4489 |
+
/* Get HPC marginal: phase-coherent weight for this head */
|
| 4490 |
+
float ae = 0.0f;
|
| 4491 |
+
for (int64_t d = 0; d < head_dim; d++)
|
| 4492 |
+
ae += fabsf(kh[d] * vh[d]);
|
| 4493 |
+
ae += 1e-6f;
|
| 4494 |
+
int ph = ((int)(ae * 100.0f)) % D;
|
| 4495 |
+
double coherence_raw = hpc_marginal(attn_graph, h, ph);
|
| 4496 |
+
float coherence = (float)(coherence_raw * D);
|
| 4497 |
+
if (coherence < 0.1f) coherence = 0.1f;
|
| 4498 |
+
if (coherence > 3.0f) coherence = 3.0f;
|
| 4499 |
+
|
| 4500 |
+
/* Feature map: Ο(x) = max(x,0) + Ξ΅ */
|
| 4501 |
+
float qf[256], kf[256];
|
| 4502 |
+
for (int64_t d = 0; d < head_dim; d++) {
|
| 4503 |
+
qf[d] = (qh[d] > 0 ? qh[d] : 0) + 1e-6f;
|
| 4504 |
+
kf[d] = (kh[d] > 0 ? kh[d] : 0) + 1e-6f;
|
| 4505 |
+
}
|
| 4506 |
+
|
| 4507 |
+
/* Accumulate: S += coherence Γ outer(kf, v) */
|
| 4508 |
+
for (int64_t d1 = 0; d1 < head_dim; d1++) {
|
| 4509 |
+
float ks = kf[d1] * coherence;
|
| 4510 |
+
for (int64_t d2 = 0; d2 < head_dim; d2++)
|
| 4511 |
+
Sh[d1 * head_dim + d2] += ks * vh[d2];
|
| 4512 |
+
}
|
| 4513 |
+
for (int64_t d = 0; d < head_dim; d++)
|
| 4514 |
+
zh[d] += kf[d] * coherence;
|
| 4515 |
+
|
| 4516 |
+
/* Output: (qf @ S) / (qf Β· z) */
|
| 4517 |
+
float den = 1e-8f;
|
| 4518 |
+
for (int64_t d = 0; d < head_dim; d++)
|
| 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 |
+
|
| 4534 |
+
/* Compact graph edges periodically */
|
| 4535 |
+
if (t > 0 && t % 64 == 0)
|
| 4536 |
+
hpc_compact_edges(attn_graph);
|
| 4537 |
+
}
|
| 4538 |
+
}
|
| 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);
|
| 4564 |
+
|
| 4565 |
+
} else if (q_w && k_w && v_w && o_w) {
|
| 4566 |
+
/* ββ Separate QKV path (standard transformer) ββ */
|
| 4567 |
+
float *Q = (float *)malloc(seq_len * q_dim * sizeof(float));
|
| 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++) {
|
| 4591 |
+
int64_t kv_h = h % n_head_kv;
|
| 4592 |
+
float *kh = K_buf + t * k_dim + kv_h * hd_kv;
|
| 4593 |
+
float *vh = V_buf + t * v_dim + kv_h * hd_kv;
|
| 4594 |
+
float energy = 0.0f;
|
| 4595 |
+
for (int64_t d = 0; d < hd_kv; d++)
|
| 4596 |
+
energy += kh[d] * vh[d];
|
| 4597 |
+
double re[D] = {0}, im[D] = {0};
|
| 4598 |
+
float ae = fabsf(energy) + 1e-6f;
|
| 4599 |
+
int ph = ((int)(ae * 100.0f)) % D;
|
| 4600 |
+
re[ph] = sqrt(ae);
|
| 4601 |
+
im[ph] = (energy < 0) ? -sqrt(ae)*0.5 : sqrt(ae)*0.5;
|
| 4602 |
+
hpc_set_local(attn_graph, h, re, im);
|
| 4603 |
+
}
|
| 4604 |
+
for (int64_t h = 0; h < n_head - 1; h++)
|
| 4605 |
+
hpc_cz(attn_graph, h, h+1);
|
| 4606 |
+
|
| 4607 |
+
#pragma omp parallel for schedule(static)
|
| 4608 |
+
for (int64_t h = 0; h < n_head; h++) {
|
| 4609 |
+
int64_t kv_h = h % n_head_kv;
|
| 4610 |
+
float *qh = Q + t * q_dim + h * hd_q;
|
| 4611 |
+
float *kh = K_buf + t * k_dim + kv_h * hd_kv;
|
| 4612 |
+
float *vh = V_buf + t * v_dim + kv_h * hd_kv;
|
| 4613 |
+
float *Sh = S + h * hd_kv * hd_kv;
|
| 4614 |
+
float *zh = z_acc + h * hd_kv;
|
| 4615 |
+
int64_t feat = hd_q < hd_kv ? hd_q : hd_kv;
|
| 4616 |
+
|
| 4617 |
+
float ae = fabsf(kh[0]*vh[0]) + 1e-6f;
|
| 4618 |
+
int ph = ((int)(ae * 100.0f)) % D;
|
| 4619 |
+
double coh_raw = hpc_marginal(attn_graph, h, ph);
|
| 4620 |
+
float coh = (float)(coh_raw * D);
|
| 4621 |
+
if (coh < 0.1f) coh = 0.1f;
|
| 4622 |
+
if (coh > 3.0f) coh = 3.0f;
|
| 4623 |
+
|
| 4624 |
+
for (int64_t d1 = 0; d1 < feat; d1++) {
|
| 4625 |
+
float kf = (kh[d1] > 0 ? kh[d1] : 0) + 1e-6f;
|
| 4626 |
+
float ks = kf * coh;
|
| 4627 |
+
for (int64_t d2 = 0; d2 < hd_kv; d2++)
|
| 4628 |
+
Sh[d1*hd_kv+d2] += ks * vh[d2];
|
| 4629 |
+
zh[d1] += kf * coh;
|
| 4630 |
+
}
|
| 4631 |
+
|
| 4632 |
+
float den = 1e-8f;
|
| 4633 |
+
for (int64_t d = 0; d < feat; d++) {
|
| 4634 |
+
float qf = (qh[d] > 0 ? qh[d] : 0) + 1e-6f;
|
| 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)
|
| 4650 |
+
hpc_compact_edges(attn_graph);
|
| 4651 |
+
}
|
| 4652 |
+
}
|
| 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);
|
| 4669 |
+
free(Q); free(K_buf); free(V_buf);
|
| 4670 |
+
}
|
| 4671 |
+
|
| 4672 |
+
/* Residual add: hidden += attn_out */
|
| 4673 |
+
int64_t total = seq_len * n_embd;
|
| 4674 |
+
#pragma omp parallel for schedule(static)
|
| 4675 |
+
for (int64_t i = 0; i < total; i++)
|
| 4676 |
+
hidden[i] += attn_out[i];
|
| 4677 |
+
|
| 4678 |
+
/* ββββββββββββββ Phase 3: FFN ββββββββββββββ */
|
| 4679 |
+
if (ffn_norm_w && ffn_gate_w && ffn_up_w && ffn_down_w && ffn_dim > 0) {
|
| 4680 |
+
float *normed_ff = (float *)malloc(seq_len * n_embd * sizeof(float));
|
| 4681 |
+
float *gate_out = (float *)malloc(seq_len * ffn_dim * sizeof(float));
|
| 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);
|
| 4695 |
+
#pragma omp parallel for schedule(static)
|
| 4696 |
+
for (int64_t i = 0; i < seq_len * ffn_dim; i++)
|
| 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 |
+
|
| 4713 |
+
free(normed_ff); free(gate_out); free(up_out);
|
| 4714 |
+
}
|
| 4715 |
+
|
| 4716 |
+
free(normed);
|
| 4717 |
+
free(attn_out);
|
| 4718 |
+
}
|
| 4719 |
+
|
| 4720 |
#ifndef HEXSTATE_LIBRARY
|
| 4721 |
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 4722 |
* MAIN
|