| |
| """ |
| HExState Importance Matrix Generator β HPC-Enhanced iMatrix from GGUF |
| |
| Runs transformer forward passes over calibration text to collect per-channel |
| E[xΒ²] activation statistics, then uses HPC triality BP to propagate importance |
| across layers. Outputs llama.cpp-compatible .dat imatrix files. |
| |
| Usage: |
| python3 generate_imatrix.py model.gguf calibration.txt -o imatrix.dat |
| """ |
|
|
| import struct |
| import sys |
| import os |
| import time |
| import mmap |
| import ctypes |
| import numpy as np |
| from collections import OrderedDict |
|
|
| |
| GGUF_MAGIC = 0x46554747 |
| ALIGNMENT = 32 |
| QK_K = 256 |
| QK4_0 = 32 |
| QK8_0 = 32 |
|
|
| GGML_TYPE_F32 = 0 |
| GGML_TYPE_F16 = 1 |
| GGML_TYPE_Q4_0 = 2 |
| GGML_TYPE_Q8_0 = 8 |
| GGML_TYPE_Q2_K = 10 |
| GGML_TYPE_BF16 = 30 |
|
|
| TYPE_BLOCK_SIZE = { |
| 0: 1, 1: 1, 2: 32, 3: 32, 6: 32, 7: 32, |
| 8: 32, 9: 32, 10: 256, 11: 256, 12: 256, |
| 13: 256, 14: 256, 15: 256, 30: 1, |
| } |
| TYPE_BLOCK_BYTES = { |
| 0: 4, 1: 2, 2: 18, 3: 20, 6: 20, 7: 22, |
| 8: 34, 9: 36, 10: 84, 11: 110, 12: 144, |
| 13: 176, 14: 210, 15: 292, 30: 2, |
| } |
| TYPE_NAME = { |
| 0: "F32", 1: "F16", 2: "Q4_0", 8: "Q8_0", 10: "Q2_K", 30: "BF16", |
| } |
|
|
|
|
| |
|
|
| def align_offset(offset): |
| return (offset + ALIGNMENT - 1) & ~(ALIGNMENT - 1) |
|
|
| def read_string(f): |
| slen = struct.unpack('<Q', f.read(8))[0] |
| return f.read(slen).decode('utf-8', errors='replace') |
|
|
| def read_kv_value(f, vtype): |
| """Read and return a KV value.""" |
| if vtype == 0: return struct.unpack('<B', f.read(1))[0] |
| elif vtype == 1: return struct.unpack('<b', f.read(1))[0] |
| elif vtype == 2: return struct.unpack('<H', f.read(2))[0] |
| elif vtype == 3: return struct.unpack('<h', f.read(2))[0] |
| elif vtype == 4: return struct.unpack('<I', f.read(4))[0] |
| elif vtype == 5: return struct.unpack('<i', f.read(4))[0] |
| elif vtype == 6: return struct.unpack('<f', f.read(4))[0] |
| elif vtype == 7: return bool(struct.unpack('<B', f.read(1))[0]) |
| elif vtype == 8: return read_string(f) |
| elif vtype == 9: |
| arr_type = struct.unpack('<I', f.read(4))[0] |
| arr_len = struct.unpack('<Q', f.read(8))[0] |
| return [read_kv_value(f, arr_type) for _ in range(arr_len)] |
| elif vtype == 10: return struct.unpack('<Q', f.read(8))[0] |
| elif vtype == 11: return struct.unpack('<q', f.read(8))[0] |
| elif vtype == 12: return struct.unpack('<d', f.read(8))[0] |
| else: |
| raise ValueError(f"Unknown KV type {vtype}") |
|
|
|
|
| class GGUFModel: |
| """Loads a GGUF model with mmap'd tensor access.""" |
|
|
| def __init__(self, path): |
| self.path = path |
| self.file_size = os.path.getsize(path) |
| self.kv = {} |
| self.tensor_infos = OrderedDict() |
| self.data_offset = 0 |
|
|
| self._f = open(path, 'rb') |
| self._mm = mmap.mmap(self._f.fileno(), 0, access=mmap.ACCESS_READ) |
| self._parse_header() |
|
|
| def _parse_header(self): |
| f = self._f |
| f.seek(0) |
| magic = struct.unpack('<I', f.read(4))[0] |
| assert magic == GGUF_MAGIC, f"Bad GGUF magic: 0x{magic:08X}" |
| version = struct.unpack('<I', f.read(4))[0] |
| n_tensors = struct.unpack('<Q', f.read(8))[0] |
| n_kv = struct.unpack('<Q', f.read(8))[0] |
|
|
| |
| for _ in range(n_kv): |
| key = read_string(f) |
| vtype = struct.unpack('<I', f.read(4))[0] |
| value = read_kv_value(f, vtype) |
| self.kv[key] = value |
|
|
| |
| for _ in range(n_tensors): |
| name = read_string(f) |
| n_dims = struct.unpack('<I', f.read(4))[0] |
| dims = [struct.unpack('<Q', f.read(8))[0] for _ in range(n_dims)] |
| ttype = struct.unpack('<I', f.read(4))[0] |
| offset = struct.unpack('<Q', f.read(8))[0] |
| n_elements = 1 |
| for d in dims: |
| n_elements *= d |
| blk_sz = TYPE_BLOCK_SIZE.get(ttype, 1) |
| blk_bytes = TYPE_BLOCK_BYTES.get(ttype, 4) |
| n_blocks = (n_elements + blk_sz - 1) // blk_sz |
| data_size = n_blocks * blk_bytes |
| self.tensor_infos[name] = { |
| 'dims': dims, 'n_dims': n_dims, 'type': ttype, |
| 'offset': offset, 'n_elements': n_elements, |
| 'data_size': data_size, |
| } |
|
|
| self.data_offset = align_offset(f.tell()) |
|
|
| def get_arch(self): |
| arch = self.kv.get('general.architecture', 'gemma2') |
| return arch |
|
|
| def get_config(self): |
| arch = self.get_arch() |
| n_embd = self.kv.get(f'{arch}.embedding_length', 0) |
| n_head = self.kv.get(f'{arch}.attention.head_count', 0) |
| n_head_kv = self.kv.get(f'{arch}.attention.head_count_kv', 0) |
|
|
| |
| |
| |
| head_dim = 0 |
| gate_name = 'blk.0.attn_gate.weight' |
| if gate_name in self.tensor_infos: |
| |
| gate_cols = self.tensor_infos[gate_name]['dims'][1] |
| if n_head > 0: |
| head_dim = gate_cols // n_head |
| if head_dim == 0 and n_head > 0: |
| head_dim = n_embd // n_head |
|
|
| return { |
| 'arch': arch, |
| 'n_layers': self.kv.get(f'{arch}.block_count', 0), |
| 'n_embd': n_embd, |
| 'n_head': n_head, |
| 'n_head_kv': n_head_kv, |
| 'n_ff': self.kv.get(f'{arch}.feed_forward_length', 0), |
| 'vocab_size': self.kv.get(f'{arch}.vocab_size', 0), |
| 'rms_eps': self.kv.get(f'{arch}.attention.layer_norm_rms_epsilon', 1e-6), |
| 'rope_base': self.kv.get(f'{arch}.rope.freq_base', 10000.0), |
| 'swa_window': self.kv.get(f'{arch}.attention.sliding_window', 0), |
| 'head_dim': head_dim, |
| } |
|
|
| def get_tensor_f32(self, name): |
| """Load a tensor as float32, dequantizing if needed.""" |
| if name not in self.tensor_infos: |
| return None |
| ti = self.tensor_infos[name] |
| abs_offset = self.data_offset + ti['offset'] |
| raw = bytes(self._mm[abs_offset:abs_offset + ti['data_size']]) |
| return dequantize(raw, ti['type'], ti['n_elements']) |
|
|
| def get_tensor_shape(self, name): |
| """Return the shape of a tensor (GGUF stores reversed dims).""" |
| if name not in self.tensor_infos: |
| return None |
| dims = self.tensor_infos[name]['dims'] |
| |
| return tuple(reversed(dims)) |
|
|
| def close(self): |
| self._mm.close() |
| self._f.close() |
|
|
|
|
| |
|
|
| def dequantize(raw, ttype, n_elements): |
| """Dequantize raw bytes to float32 numpy array.""" |
| if ttype == GGML_TYPE_F32: |
| return np.frombuffer(raw, dtype=np.float32).copy() |
| elif ttype == GGML_TYPE_F16: |
| return np.frombuffer(raw, dtype=np.float16).astype(np.float32) |
| elif ttype == GGML_TYPE_BF16: |
| bf16 = np.frombuffer(raw, dtype=np.uint16) |
| return (bf16.astype(np.uint32) << 16).view(np.float32).copy() |
| elif ttype == GGML_TYPE_Q8_0: |
| return dequant_q8_0(raw, n_elements) |
| elif ttype == GGML_TYPE_Q4_0: |
| return dequant_q4_0(raw, n_elements) |
| elif ttype == GGML_TYPE_Q2_K: |
| return dequant_q2k(raw, n_elements) |
| else: |
| raise ValueError(f"Unsupported quant type {ttype} ({TYPE_NAME.get(ttype, '?')})") |
|
|
| def dequant_q8_0(raw, n_elements): |
| n_blocks = n_elements // QK8_0 |
| data = np.frombuffer(raw, dtype=np.uint8).reshape(n_blocks, 34) |
| d = data[:, 0:2].view(np.float16).astype(np.float32).reshape(n_blocks, 1) |
| qs = data[:, 2:34].view(np.int8).astype(np.float32) |
| return (d * qs).reshape(-1)[:n_elements] |
|
|
| def dequant_q4_0(raw, n_elements): |
| n_blocks = n_elements // QK4_0 |
| data = np.frombuffer(raw, dtype=np.uint8).reshape(n_blocks, 18) |
| d = data[:, 0:2].view(np.float16).astype(np.float32).reshape(n_blocks, 1) |
| qs = data[:, 2:18] |
| lo = (qs & 0xF).astype(np.float32) - 8.0 |
| hi = (qs >> 4).astype(np.float32) - 8.0 |
| x = np.concatenate([lo, hi], axis=1) |
| return (d * x).reshape(-1)[:n_elements] |
|
|
| def dequant_q2k(raw, n_elements): |
| n_blocks = n_elements // QK_K |
| data = np.frombuffer(raw, dtype=np.uint8).reshape(n_blocks, 84) |
| scales_packed = data[:, 0:16] |
| qs = data[:, 16:80] |
| d_fp16 = data[:, 80:82].view(np.float16).astype(np.float32).reshape(n_blocks) |
| dmin_fp16 = data[:, 82:84].view(np.float16).astype(np.float32).reshape(n_blocks) |
|
|
| result = np.zeros((n_blocks, QK_K), dtype=np.float32) |
| for blk in range(n_blocks): |
| d = d_fp16[blk] |
| dmin = dmin_fp16[blk] |
| for half in range(2): |
| for sub in range(4): |
| j = half * 8 + sub |
| sc = int(scales_packed[blk, j]) & 0xF |
| mn = int(scales_packed[blk, j]) >> 4 |
| d_sub = d * sc |
| m_sub = dmin * mn |
| for k in range(32): |
| qi_byte = int(qs[blk, half * 32 + k]) |
| q = (qi_byte >> (sub * 2)) & 3 |
| idx = half * 128 + sub * 32 + k |
| result[blk, idx] = d_sub * q - m_sub |
| return result.reshape(-1)[:n_elements] |
|
|
|
|
| |
|
|
| class SimpleTokenizer: |
| """Minimal BPE tokenizer from GGUF metadata, with HPC acceleration.""" |
|
|
| def __init__(self, model): |
| self.tokens = model.kv.get('tokenizer.ggml.tokens', []) |
| self.vocab_size = len(self.tokens) |
| merges_raw = model.kv.get('tokenizer.ggml.merges', []) |
| self.bos_id = model.kv.get('tokenizer.ggml.bos_token_id', 2) |
| self.eos_id = model.kv.get('tokenizer.ggml.eos_token_id', 1) |
|
|
| |
| self.token_to_id = {} |
| for i, t in enumerate(self.tokens): |
| if isinstance(t, str): |
| self.token_to_id[t] = i |
|
|
| |
| self.merges = {} |
| self._merge_list = [] |
| for i, m in enumerate(merges_raw): |
| if isinstance(m, str): |
| parts = m.split(' ', 1) |
| if len(parts) == 2: |
| self.merges[(parts[0], parts[1])] = i |
| |
| a_id = self.token_to_id.get(parts[0], -1) |
| b_id = self.token_to_id.get(parts[1], -1) |
| merged_tok = parts[0] + parts[1] |
| merged_id = self.token_to_id.get(merged_tok, -1) |
| if a_id >= 0 and b_id >= 0 and merged_id >= 0: |
| self._merge_list.append((a_id, b_id, merged_id, i)) |
|
|
| |
| self._hpc_lib = None |
| try: |
| script_dir = os.path.dirname(os.path.abspath(__file__)) |
| lib_path = os.path.join(script_dir, 'libhexstate_q2k.so') |
| if os.path.exists(lib_path): |
| lib = ctypes.CDLL(lib_path) |
| if hasattr(lib, 'hexstate_bpe_tokenize'): |
| self._hpc_lib = lib |
| print(f" HPCΒ·BPE engine loaded ({len(self._merge_list)} merge rules)") |
| else: |
| print(" HPC library found but missing hexstate_bpe_tokenize β rebuild needed") |
| except Exception as e: |
| print(f" HPCΒ·BPE not available: {e}") |
|
|
| def encode(self, text): |
| """Encode text to token IDs using BPE (HPC-accelerated when available).""" |
| if not text: |
| return [self.bos_id] |
|
|
| |
| text = text.replace(' ', 'β') |
| if not text.startswith('β'): |
| text = 'β' + text |
|
|
| |
| if self._hpc_lib and self._merge_list: |
| import time as _time |
| t0 = _time.time() |
| print(f" HPCΒ·BPE: tokenizing {len(text):,} chars...") |
|
|
| |
| char_ids = np.array( |
| [self.token_to_id.get(c, 0) for c in text], |
| dtype=np.int32) |
|
|
| |
| n_merges = len(self._merge_list) |
| |
| merge_buf = np.zeros(n_merges * 4, dtype=np.int32) |
| for idx, (a, b, m, r) in enumerate(self._merge_list): |
| merge_buf[idx * 4 + 0] = a |
| merge_buf[idx * 4 + 1] = b |
| merge_buf[idx * 4 + 2] = m |
| merge_buf[idx * 4 + 3] = r |
|
|
| |
| output_ids = np.zeros(len(char_ids), dtype=np.int32) |
| n_tokens = ctypes.c_int64(0) |
|
|
| self._hpc_lib.hexstate_bpe_tokenize( |
| char_ids.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)), |
| ctypes.c_int64(len(char_ids)), |
| merge_buf.ctypes.data_as(ctypes.c_void_p), |
| ctypes.c_int32(n_merges), |
| output_ids.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)), |
| ctypes.byref(n_tokens), |
| ctypes.c_int(1), |
| ) |
|
|
| elapsed = _time.time() - t0 |
| ids = [self.bos_id] + output_ids[:n_tokens.value].tolist() |
| print(f" HPCΒ·BPE: {len(text):,} chars β {n_tokens.value:,} tokens [{elapsed:.1f}s]") |
| return ids |
|
|
| |
| |
| tokens = list(text) |
|
|
| |
| initial_len = len(tokens) |
| pass_num = 0 |
| import time as _time |
| t0 = _time.time() |
| while len(tokens) > 1: |
| best_pair = None |
| best_rank = float('inf') |
| for i in range(len(tokens) - 1): |
| pair = (tokens[i], tokens[i + 1]) |
| rank = self.merges.get(pair, float('inf')) |
| if rank < best_rank: |
| best_rank = rank |
| best_pair = pair |
| if best_pair is None or best_rank == float('inf'): |
| break |
| |
| a, b = best_pair |
| prev_len = len(tokens) |
| new_tokens = [] |
| i = 0 |
| while i < len(tokens): |
| if i < len(tokens) - 1 and tokens[i] == a and tokens[i + 1] == b: |
| new_tokens.append(a + b) |
| i += 2 |
| else: |
| new_tokens.append(tokens[i]) |
| i += 1 |
| tokens = new_tokens |
| pass_num += 1 |
| if pass_num % 10 == 0: |
| elapsed = _time.time() - t0 |
| merged = prev_len - len(tokens) |
| sys.stdout.write( |
| f"\r BPE pass {pass_num}: {len(tokens):,} tokens " |
| f"(-{merged} merged, {len(tokens)/initial_len*100:.1f}%) " |
| f"[{elapsed:.1f}s] ") |
| sys.stdout.flush() |
| if pass_num >= 10: |
| elapsed = _time.time() - t0 |
| print(f"\r Tokenized: {pass_num} passes, {initial_len:,} chars β " |
| f"{len(tokens):,} tokens [{elapsed:.1f}s]" + " " * 30) |
|
|
| |
| ids = [self.bos_id] |
| for t in tokens: |
| tid = self.token_to_id.get(t, 0) |
| ids.append(tid) |
| return ids |
|
|
| def chunk_text(self, text, chunk_size=512): |
| """Encode text and split into fixed-length chunks.""" |
| ids = self.encode(text) |
| chunks = [] |
| for i in range(0, len(ids) - chunk_size, chunk_size // 2): |
| chunk = ids[i:i + chunk_size] |
| if len(chunk) == chunk_size: |
| chunks.append(np.array(chunk, dtype=np.int32)) |
| if not chunks and ids: |
| |
| padded = ids + [self.eos_id] * (chunk_size - len(ids)) |
| chunks.append(np.array(padded[:chunk_size], dtype=np.int32)) |
| return chunks |
|
|
|
|
| |
|
|
| def rms_norm(x, weight, eps=1e-6): |
| rms = np.sqrt(np.mean(x * x, axis=-1, keepdims=True) + eps) |
| return (x / rms) * weight |
|
|
| def rope_freqs(dim, seq_len, base=10000.0): |
| freqs = 1.0 / (base ** (np.arange(0, dim, 2, dtype=np.float32) / dim)) |
| t = np.arange(seq_len, dtype=np.float32) |
| freqs = np.outer(t, freqs) |
| return np.cos(freqs), np.sin(freqs) |
|
|
| def apply_rope(x, cos_f, sin_f): |
| |
| d2 = x.shape[-1] // 2 |
| x0 = x[..., :d2] |
| x1 = x[..., d2:] |
| cos_f = cos_f[:x.shape[0], :d2] |
| sin_f = sin_f[:x.shape[0], :d2] |
| if x.ndim == 3: |
| cos_f = cos_f[:, np.newaxis, :] |
| sin_f = sin_f[:, np.newaxis, :] |
| o0 = x0 * cos_f - x1 * sin_f |
| o1 = x1 * cos_f + x0 * sin_f |
| return np.concatenate([o0, o1], axis=-1) |
|
|
| def softmax(x, axis=-1): |
| x_max = np.max(x, axis=axis, keepdims=True) |
| e = np.exp(x - x_max) |
| return e / np.sum(e, axis=axis, keepdims=True) |
|
|
| def silu(x): |
| """SiLU / Swish activation β used by LLaMA, Mistral, Qwen, DeepSeek.""" |
| return x * (1.0 / (1.0 + np.exp(-np.clip(x, -88, 88)))) |
|
|
| def gelu(x): |
| """GELU activation β used by Gemma, GPT-2.""" |
| return 0.5 * x * (1.0 + np.tanh(np.sqrt(2.0 / np.pi) * (x + 0.044715 * x**3))) |
|
|
| |
| ACTIVATION_MAP = { |
| 'llama': silu, 'mistral': silu, 'qwen2': silu, 'qwen2moe': silu, |
| 'phi3': silu, 'falcon': silu, 'deepseek': silu, 'deepseek2': silu, |
| 'gemma': gelu, 'gemma2': gelu, 'gpt2': gelu, |
| } |
|
|
|
|
| class TransformerRunner: |
| """Minimal Gemma transformer for importance collection.""" |
|
|
| def __init__(self, model, config, verbose=False): |
| self.model = model |
| self.cfg = config |
| self.verbose = verbose |
| self.head_dim = config.get('head_dim', config['n_embd'] // config['n_head']) |
| self.act_fn = ACTIVATION_MAP.get(config['arch'], silu) |
|
|
| |
| self.importance = {} |
|
|
| def _record(self, name, x): |
| """Record E[xΒ²] for this tensor's input activation.""" |
| |
| x_flat = x.reshape(-1, x.shape[-1]) |
| x2 = np.sum(x_flat ** 2, axis=0) |
| if name in self.importance: |
| self.importance[name] = ( |
| self.importance[name][0] + x2, |
| self.importance[name][1] + x_flat.shape[0], |
| ) |
| else: |
| self.importance[name] = (x2.copy(), x_flat.shape[0]) |
|
|
| def _get_weight(self, name): |
| """Load weight, trying GGUF name patterns.""" |
| w = self.model.get_tensor_f32(name) |
| if w is None: |
| return None |
| shape = self.model.get_tensor_shape(name) |
| if shape and len(shape) >= 2: |
| return w.reshape(shape) |
| return w |
|
|
| def _layer_prefix(self, layer_idx): |
| return f"blk.{layer_idx}" |
|
|
| def forward_layer(self, hidden, layer_idx, cos_f, sin_f): |
| """Forward pass through one transformer layer. Returns new hidden state.""" |
| pfx = self._layer_prefix(layer_idx) |
| cfg = self.cfg |
| n_head = cfg['n_head'] |
| n_head_kv = cfg['n_head_kv'] |
| head_dim = self.head_dim |
| seq_len = hidden.shape[0] |
|
|
| |
| attn_norm_w = self._get_weight(f'{pfx}.attn_norm.weight') |
| if attn_norm_w is None: |
| return hidden |
|
|
| normed = rms_norm(hidden, attn_norm_w, cfg['rms_eps']) |
|
|
| |
| q_w = self._get_weight(f'{pfx}.attn_q.weight') |
| k_w = self._get_weight(f'{pfx}.attn_k.weight') |
| v_w = self._get_weight(f'{pfx}.attn_v.weight') |
| o_w = self._get_weight(f'{pfx}.attn_output.weight') |
|
|
| if q_w is None or k_w is None or v_w is None or o_w is None: |
| return hidden |
|
|
| self._record(f'{pfx}.attn_q.weight', normed) |
| self._record(f'{pfx}.attn_k.weight', normed) |
| self._record(f'{pfx}.attn_v.weight', normed) |
|
|
| q = normed @ q_w.T |
| k = normed @ k_w.T |
| v = normed @ v_w.T |
|
|
| q = q.reshape(seq_len, n_head, head_dim) |
| k = k.reshape(seq_len, n_head_kv, head_dim) |
| v = v.reshape(seq_len, n_head_kv, head_dim) |
|
|
| q = apply_rope(q, cos_f, sin_f) |
| k = apply_rope(k, cos_f, sin_f) |
|
|
| |
| if n_head_kv < n_head: |
| rep = n_head // n_head_kv |
| k = np.repeat(k, rep, axis=1) |
| v = np.repeat(v, rep, axis=1) |
|
|
| |
| q_t = q.transpose(1, 0, 2) |
| k_t = k.transpose(1, 0, 2) |
| v_t = v.transpose(1, 0, 2) |
|
|
| scale = 1.0 / np.sqrt(head_dim) |
| attn = np.matmul(q_t, k_t.transpose(0, 2, 1)) * scale |
|
|
| |
| mask = np.triu(np.full((seq_len, seq_len), -1e9, dtype=np.float32), k=1) |
| swa = cfg.get('swa_window', 0) |
| if swa and swa > 0: |
| for i in range(seq_len): |
| for j in range(0, max(0, i - swa)): |
| mask[i, j] = -1e9 |
| attn = attn + mask[np.newaxis, :, :] |
| attn = softmax(attn, axis=-1) |
|
|
| out = np.matmul(attn, v_t) |
| out = out.transpose(1, 0, 2).reshape(seq_len, -1) |
|
|
| self._record(f'{pfx}.attn_output.weight', out) |
| attn_out = out @ o_w.T |
|
|
| hidden = hidden + attn_out |
|
|
| |
| ffn_norm_w = self._get_weight(f'{pfx}.ffn_norm.weight') |
| if ffn_norm_w is None: |
| return hidden |
|
|
| normed_ff = rms_norm(hidden, ffn_norm_w, cfg['rms_eps']) |
|
|
| gate_w = self._get_weight(f'{pfx}.ffn_gate.weight') |
| up_w = self._get_weight(f'{pfx}.ffn_up.weight') |
| down_w = self._get_weight(f'{pfx}.ffn_down.weight') |
|
|
| if gate_w is not None and up_w is not None and down_w is not None: |
| self._record(f'{pfx}.ffn_gate.weight', normed_ff) |
| self._record(f'{pfx}.ffn_up.weight', normed_ff) |
|
|
| gate_out = self.act_fn(normed_ff @ gate_w.T) |
| up_out = normed_ff @ up_w.T |
| ff_mid = gate_out * up_out |
|
|
| self._record(f'{pfx}.ffn_down.weight', ff_mid) |
| ff_out = ff_mid @ down_w.T |
| hidden = hidden + ff_out |
| else: |
| |
| gate_inp_w = self._get_weight(f'{pfx}.ffn_gate_inp.weight') |
| if gate_inp_w is not None: |
| self._record(f'{pfx}.ffn_gate_inp.weight', normed_ff) |
| router_logits = normed_ff @ gate_inp_w.T |
| n_experts = router_logits.shape[-1] |
| probs = softmax(router_logits, axis=-1) |
| top2 = np.argsort(probs, axis=-1)[:, -2:] |
|
|
| ff_out = np.zeros_like(normed_ff) |
| for exp_id in range(n_experts): |
| ew_gate = self._get_weight(f'{pfx}.ffn_gate.{exp_id}.weight') |
| ew_up = self._get_weight(f'{pfx}.ffn_up.{exp_id}.weight') |
| ew_down = self._get_weight(f'{pfx}.ffn_down.{exp_id}.weight') |
| if ew_gate is None: |
| continue |
|
|
| mask_exp = np.any(top2 == exp_id, axis=-1) |
| if not np.any(mask_exp): |
| continue |
|
|
| exp_input = normed_ff[mask_exp] |
| self._record(f'{pfx}.ffn_gate.{exp_id}.weight', exp_input) |
| self._record(f'{pfx}.ffn_up.{exp_id}.weight', exp_input) |
|
|
| g = self.act_fn(exp_input @ ew_gate.T) |
| u = exp_input @ ew_up.T |
| mid = g * u |
| self._record(f'{pfx}.ffn_down.{exp_id}.weight', mid) |
|
|
| exp_out = mid @ ew_down.T |
| |
| for token_idx in np.where(mask_exp)[0]: |
| w = probs[token_idx, exp_id] |
| local_idx = np.sum(mask_exp[:token_idx]) |
| ff_out[token_idx] += w * exp_out[local_idx] |
|
|
| hidden = hidden + ff_out |
|
|
| return hidden |
|
|
| def forward_linear_attn_layer(self, hidden, layer_idx): |
| """Forward pass through a DeltaNet (gated linear attention) layer. |
| |
| Used by Qwen 3.5/3.6 for ~75% of layers. Records importance stats |
| for all SSM projection weights. |
| """ |
| pfx = self._layer_prefix(layer_idx) |
| cfg = self.cfg |
| seq_len = hidden.shape[0] |
|
|
| |
| attn_norm_w = self._get_weight(f'{pfx}.attn_norm.weight') |
| if attn_norm_w is None: |
| return hidden |
| normed = rms_norm(hidden, attn_norm_w, cfg['rms_eps']) |
|
|
| |
| qkv_w = self._get_weight(f'{pfx}.ssm_in_qkv.weight') |
| z_w = self._get_weight(f'{pfx}.ssm_in_z.weight') |
| a_w = self._get_weight(f'{pfx}.ssm_in_a.weight') |
| b_w = self._get_weight(f'{pfx}.ssm_in_b.weight') |
| out_w = self._get_weight(f'{pfx}.ssm_out.weight') |
|
|
| if qkv_w is None or out_w is None: |
| return hidden |
|
|
| |
| self._record(f'{pfx}.ssm_in_qkv.weight', normed) |
| if z_w is not None: |
| self._record(f'{pfx}.ssm_in_z.weight', normed) |
| if a_w is not None: |
| self._record(f'{pfx}.ssm_in_a.weight', normed) |
| if b_w is not None: |
| self._record(f'{pfx}.ssm_in_b.weight', normed) |
|
|
| |
| |
| |
| qkv = normed @ qkv_w.T |
|
|
| |
| |
| n_out = out_w.shape[1] if out_w.ndim >= 2 else hidden.shape[-1] |
| if qkv.shape[-1] >= n_out: |
| out_input = qkv[:, :n_out] |
| else: |
| out_input = qkv |
| self._record(f'{pfx}.ssm_out.weight', out_input) |
|
|
| attn_out = out_input @ out_w.T |
| hidden = hidden + attn_out |
|
|
| |
| ffn_norm_w = self._get_weight(f'{pfx}.ffn_norm.weight') |
| if ffn_norm_w is None: |
| return hidden |
|
|
| normed_ff = rms_norm(hidden, ffn_norm_w, cfg['rms_eps']) |
|
|
| gate_w = self._get_weight(f'{pfx}.ffn_gate.weight') |
| up_w = self._get_weight(f'{pfx}.ffn_up.weight') |
| down_w = self._get_weight(f'{pfx}.ffn_down.weight') |
|
|
| if gate_w is not None and up_w is not None and down_w is not None: |
| self._record(f'{pfx}.ffn_gate.weight', normed_ff) |
| self._record(f'{pfx}.ffn_up.weight', normed_ff) |
| gate_out = self.act_fn(normed_ff @ gate_w.T) |
| up_out = normed_ff @ up_w.T |
| ff_mid = gate_out * up_out |
| self._record(f'{pfx}.ffn_down.weight', ff_mid) |
| ff_out = ff_mid @ down_w.T |
| hidden = hidden + ff_out |
|
|
| return hidden |
|
|
| def forward_qwen35_layer(self, hidden, layer_idx, cos_f, sin_f): |
| """Forward pass through a Qwen 3.6 hybrid layer (attention + SSM). |
| |
| Qwen 3.6 uses: |
| - Fused attn_qkv.weight (Q+K+V in one tensor) |
| - attn_gate.weight (gated attention output, not attn_output) |
| - SSM tensors: ssm_alpha, ssm_beta, ssm_conv1d, ssm_out |
| - post_attention_norm.weight (instead of ffn_norm) |
| """ |
| pfx = self._layer_prefix(layer_idx) |
| cfg = self.cfg |
| n_head = cfg['n_head'] |
| n_head_kv = cfg['n_head_kv'] |
| head_dim = self.head_dim |
| seq_len = hidden.shape[0] |
|
|
| |
| attn_norm_w = self._get_weight(f'{pfx}.attn_norm.weight') |
| if attn_norm_w is None: |
| return hidden |
| normed = rms_norm(hidden, attn_norm_w, cfg['rms_eps']) |
|
|
| |
| qkv_w = self._get_weight(f'{pfx}.attn_qkv.weight') |
| gate_w = self._get_weight(f'{pfx}.attn_gate.weight') |
|
|
| attn_out_vec = np.zeros_like(hidden) |
| if qkv_w is not None: |
| self._record(f'{pfx}.attn_qkv.weight', normed) |
|
|
| qkv = normed @ qkv_w.T |
|
|
| |
| q_dim = n_head * head_dim |
| kv_dim = n_head_kv * head_dim |
| q = qkv[:, :q_dim].reshape(seq_len, n_head, head_dim) |
| k = qkv[:, q_dim:q_dim + kv_dim].reshape(seq_len, n_head_kv, head_dim) |
| v = qkv[:, q_dim + kv_dim:q_dim + 2 * kv_dim].reshape(seq_len, n_head_kv, head_dim) |
|
|
| |
| q = apply_rope(q, cos_f, sin_f) |
| k = apply_rope(k, cos_f, sin_f) |
|
|
| |
| if n_head_kv < n_head: |
| rep = n_head // n_head_kv |
| k = np.repeat(k, rep, axis=1) |
| v = np.repeat(v, rep, axis=1) |
|
|
| |
| q_t = q.transpose(1, 0, 2) |
| k_t = k.transpose(1, 0, 2) |
| v_t = v.transpose(1, 0, 2) |
|
|
| scale = 1.0 / np.sqrt(head_dim) |
| attn = np.matmul(q_t, k_t.transpose(0, 2, 1)) * scale |
|
|
| |
| mask = np.triu(np.full((seq_len, seq_len), -1e9, dtype=np.float32), k=1) |
| swa = cfg.get('swa_window', 0) |
| if swa and swa > 0: |
| for i in range(seq_len): |
| for j in range(0, max(0, i - swa)): |
| mask[i, j] = -1e9 |
| attn = attn + mask[np.newaxis, :, :] |
| attn = softmax(attn, axis=-1) |
|
|
| out = np.matmul(attn, v_t) |
| attn_result = out.transpose(1, 0, 2).reshape(seq_len, -1) |
|
|
| |
| if gate_w is not None: |
| self._record(f'{pfx}.attn_gate.weight', attn_result) |
| attn_out_vec = attn_result @ gate_w.T |
|
|
| |
| ssm_alpha_w = self._get_weight(f'{pfx}.ssm_alpha.weight') |
| ssm_beta_w = self._get_weight(f'{pfx}.ssm_beta.weight') |
| ssm_conv_w = self._get_weight(f'{pfx}.ssm_conv1d.weight') |
| ssm_out_w = self._get_weight(f'{pfx}.ssm_out.weight') |
|
|
| ssm_out_vec = np.zeros_like(hidden) |
| if ssm_alpha_w is not None: |
| self._record(f'{pfx}.ssm_alpha.weight', normed) |
| if ssm_beta_w is not None: |
| self._record(f'{pfx}.ssm_beta.weight', normed) |
| if ssm_conv_w is not None: |
| |
| if qkv_w is not None: |
| qkv_for_ssm = normed @ qkv_w.T |
| self._record(f'{pfx}.ssm_conv1d.weight', qkv_for_ssm) |
| if ssm_out_w is not None: |
| |
| ssm_proxy = normed[:, :ssm_out_w.shape[1]] if normed.shape[-1] >= ssm_out_w.shape[1] else normed |
| self._record(f'{pfx}.ssm_out.weight', ssm_proxy) |
| ssm_out_vec = ssm_proxy @ ssm_out_w.T |
|
|
| |
| hidden = hidden + attn_out_vec + ssm_out_vec |
|
|
| |
| ffn_norm_w = self._get_weight(f'{pfx}.post_attention_norm.weight') |
| if ffn_norm_w is None: |
| ffn_norm_w = self._get_weight(f'{pfx}.ffn_norm.weight') |
| if ffn_norm_w is None: |
| return hidden |
|
|
| normed_ff = rms_norm(hidden, ffn_norm_w, cfg['rms_eps']) |
|
|
| gate_fw = self._get_weight(f'{pfx}.ffn_gate.weight') |
| up_w = self._get_weight(f'{pfx}.ffn_up.weight') |
| down_w = self._get_weight(f'{pfx}.ffn_down.weight') |
|
|
| if gate_fw is not None and up_w is not None and down_w is not None: |
| self._record(f'{pfx}.ffn_gate.weight', normed_ff) |
| self._record(f'{pfx}.ffn_up.weight', normed_ff) |
| gate_out = self.act_fn(normed_ff @ gate_fw.T) |
| up_out = normed_ff @ up_w.T |
| ff_mid = gate_out * up_out |
| self._record(f'{pfx}.ffn_down.weight', ff_mid) |
| ff_out = ff_mid @ down_w.T |
| hidden = hidden + ff_out |
|
|
| return hidden |
|
|
| def forward(self, token_ids): |
| """Full forward pass, collecting importance statistics.""" |
| cfg = self.cfg |
| seq_len = len(token_ids) |
|
|
| |
| embed_w = self._get_weight('token_embd.weight') |
| if embed_w is None: |
| raise RuntimeError("Missing token_embd.weight") |
|
|
| hidden = embed_w[token_ids] |
|
|
| |
| cos_f, sin_f = rope_freqs(self.head_dim, seq_len, cfg['rope_base']) |
|
|
| |
| for layer_idx in range(cfg['n_layers']): |
| pfx = f"blk.{layer_idx}" |
| has_fused_qkv = f'{pfx}.attn_qkv.weight' in self.model.tensor_infos |
| has_separate_q = f'{pfx}.attn_q.weight' in self.model.tensor_infos |
| has_linear_attn = f'{pfx}.ssm_in_qkv.weight' in self.model.tensor_infos |
|
|
| if has_fused_qkv: |
| |
| hidden = self.forward_qwen35_layer(hidden, layer_idx, cos_f, sin_f) |
| elif has_linear_attn and not has_separate_q: |
| |
| hidden = self.forward_linear_attn_layer(hidden, layer_idx) |
| else: |
| |
| hidden = self.forward_layer(hidden, layer_idx, cos_f, sin_f) |
| if self.verbose and (layer_idx + 1) % 4 == 0: |
| print(f" Layer {layer_idx + 1}/{cfg['n_layers']}", end='\r') |
|
|
| |
| output_w = self._get_weight('output.weight') |
| if output_w is not None: |
| self._record('output.weight', hidden) |
|
|
| return hidden |
|
|
|
|
| |
|
|
| def hpc_propagate_importance(importance_dict, n_layers, verbose=False): |
| """Use HPC-inspired BP to propagate importance across layers. |
| |
| Each layer's raw E[xΒ²] statistics are smoothed via cross-layer coupling |
| through the residual stream. Layers with high importance AND high-importance |
| neighbors get boosted; isolated spikes get damped. |
| """ |
| |
| layer_energies = np.zeros(n_layers, dtype=np.float64) |
| layer_tensor_count = np.zeros(n_layers, dtype=np.int32) |
|
|
| for name, (sum_x2, count) in importance_dict.items(): |
| parts = name.split('.') |
| if len(parts) >= 2 and parts[0] == 'blk': |
| try: |
| layer_idx = int(parts[1]) |
| if 0 <= layer_idx < n_layers: |
| mean_imp = np.mean(sum_x2 / max(count, 1)) |
| layer_energies[layer_idx] += mean_imp |
| layer_tensor_count[layer_idx] += 1 |
| except ValueError: |
| pass |
|
|
| for i in range(n_layers): |
| if layer_tensor_count[i] > 0: |
| layer_energies[i] /= layer_tensor_count[i] |
|
|
| if np.max(layer_energies) < 1e-30: |
| return importance_dict |
|
|
| layer_energies /= np.max(layer_energies) |
|
|
| |
| multipliers = np.ones(n_layers, dtype=np.float64) |
| temperature = 0.5 |
|
|
| for _ in range(50): |
| new_mult = np.ones(n_layers, dtype=np.float64) |
| for i in range(n_layers): |
| e_self = layer_energies[i] |
| e_nbr = 0.0 |
| n_nbr = 0 |
| if i > 0: |
| e_nbr += layer_energies[i-1] * multipliers[i-1] |
| n_nbr += 1 |
| if i < n_layers - 1: |
| e_nbr += layer_energies[i+1] * multipliers[i+1] |
| n_nbr += 1 |
| if n_nbr > 0: |
| e_nbr /= n_nbr |
| new_mult[i] = np.exp((e_self + 0.3 * e_nbr) / temperature) |
|
|
| mean_m = np.mean(new_mult) |
| if mean_m > 1e-30: |
| new_mult /= mean_m |
| multipliers = 0.7 * multipliers + 0.3 * new_mult |
|
|
| if verbose: |
| print(f"\n HPC layer multipliers (first 8): " |
| f"{' '.join(f'{m:.3f}' for m in multipliers[:8])}...") |
| print(f" Range: [{np.min(multipliers):.3f}, {np.max(multipliers):.3f}]") |
|
|
| adjusted = {} |
| for name, (sum_x2, count) in importance_dict.items(): |
| parts = name.split('.') |
| if len(parts) >= 2 and parts[0] == 'blk': |
| try: |
| layer_idx = int(parts[1]) |
| if 0 <= layer_idx < n_layers: |
| adjusted[name] = (sum_x2 * multipliers[layer_idx], count) |
| continue |
| except ValueError: |
| pass |
| adjusted[name] = (sum_x2, count) |
|
|
| return adjusted |
|
|
|
|
| |
|
|
| def write_imatrix(path, importance_dict): |
| """Write llama.cpp-compatible legacy binary imatrix file.""" |
| entries = [] |
| for name, (sum_x2, count) in sorted(importance_dict.items()): |
| values = sum_x2.astype(np.float32) |
| entries.append((name, values, int(count))) |
|
|
| with open(path, 'wb') as f: |
| f.write(struct.pack('<i', len(entries))) |
| for name, values, n_samples in entries: |
| name_bytes = name.encode('utf-8') |
| f.write(struct.pack('<i', len(name_bytes))) |
| f.write(name_bytes) |
| f.write(struct.pack('<i', len(values))) |
| f.write(struct.pack('<i', n_samples)) |
| f.write(values.tobytes()) |
|
|
| return len(entries) |
|
|
|
|
| |
|
|
| def main(): |
| import argparse |
| parser = argparse.ArgumentParser( |
| description='HExState iMatrix Generator β HPC-enhanced importance matrix from GGUF') |
| parser.add_argument('model', help='Input GGUF model file') |
| parser.add_argument('calibration', help='Calibration text file') |
| parser.add_argument('-o', '--output', default='imatrix.dat', |
| help='Output imatrix file (default: imatrix.dat)') |
| parser.add_argument('--chunks', type=int, default=100, |
| help='Number of token chunks to process (default: 100)') |
| parser.add_argument('--chunk-size', type=int, default=512, |
| help='Tokens per chunk (default: 512)') |
| parser.add_argument('--no-hpc', action='store_true', |
| help='Disable HPC cross-layer propagation') |
| parser.add_argument('--verbose', action='store_true', |
| help='Per-layer statistics') |
| args = parser.parse_args() |
|
|
| print() |
| print(" ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") |
| print(" β HExState Importance Matrix Generator β") |
| print(" β HPC-Enhanced E[xΒ²] Collection from GGUF β") |
| print(" ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") |
| print() |
|
|
| start_time = time.time() |
|
|
| |
| print(f" Loading model: {args.model}") |
| model = GGUFModel(args.model) |
| config = model.get_config() |
|
|
| print(f" Architecture: {config['arch']}") |
| print(f" Layers: {config['n_layers']}") |
| print(f" Hidden: {config['n_embd']}") |
| print(f" Heads: {config['n_head']} (KV: {config['n_head_kv']})") |
| print(f" FFN: {config['n_ff']}") |
| print(f" Vocab: {config['vocab_size']}") |
| print(f" Tensors: {len(model.tensor_infos)}") |
| print() |
|
|
| |
| print(" Loading tokenizer from GGUF metadata...") |
| tokenizer = SimpleTokenizer(model) |
| print(f" Vocab size: {tokenizer.vocab_size}") |
| print() |
|
|
| |
| print(f" Loading calibration data: {args.calibration}") |
| with open(args.calibration, 'r', encoding='utf-8', errors='replace') as f: |
| cal_text = f.read() |
| print(f" Text length: {len(cal_text):,} chars") |
|
|
| |
| print(f" Tokenizing ({args.chunk_size} tokens/chunk, {args.chunks} chunks max)...") |
| chunks = tokenizer.chunk_text(cal_text, args.chunk_size) |
| if len(chunks) > args.chunks: |
| chunks = chunks[:args.chunks] |
| print(f" Prepared {len(chunks)} chunks") |
| print() |
|
|
| |
| print(" Running forward passes...") |
| runner = TransformerRunner(model, config, verbose=args.verbose) |
|
|
| for i, chunk in enumerate(chunks): |
| elapsed = time.time() - start_time |
| eta = elapsed / max(i, 1) * (len(chunks) - i) if i > 0 else 0 |
| pct = (i + 1) / len(chunks) * 100 |
| bw = 40 |
| filled = int(bw * (i + 1) / len(chunks)) |
| bar = 'β' * filled + 'β' * (bw - filled) |
| sys.stdout.write( |
| f"\r [{bar}] {pct:5.1f}% ({i+1}/{len(chunks)}) " |
| f"{elapsed:.0f}s ETA:{eta:.0f}s") |
| sys.stdout.flush() |
|
|
| try: |
| runner.forward(chunk) |
| except Exception as e: |
| print(f"\n WARNING: Chunk {i} failed: {e}") |
| continue |
|
|
| print(f"\n Collected importance for {len(runner.importance)} tensors") |
| print() |
|
|
| |
| if not args.no_hpc: |
| print(" Running HPC cross-layer importance propagation...") |
| importance = hpc_propagate_importance( |
| runner.importance, config['n_layers'], verbose=args.verbose) |
| else: |
| importance = runner.importance |
|
|
| |
| print(f"\n Writing imatrix: {args.output}") |
| n_entries = write_imatrix(args.output, importance) |
|
|
| elapsed = time.time() - start_time |
| out_size = os.path.getsize(args.output) |
|
|
| print() |
| print(" ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") |
| print(" β IMATRIX GENERATION COMPLETE β") |
| print(" β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£") |
| print(f" β Tensor entries: {n_entries:<42d} β") |
| print(f" β Chunks processed: {len(chunks):<42d} β") |
| print(f" β Output size: {out_size:>11,} bytes ({out_size/1024:.1f} KB)" |
| f"{' '*(25-len(f'{out_size/1024:.1f}'))}β") |
| print(f" β Total time: {elapsed:>38.1f} sec β") |
| print(" ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") |
| print() |
| print(f" Output: {args.output}") |
| print() |
|
|
| model.close() |
|
|
|
|
| if __name__ == '__main__': |
| main() |
|
|