Experimental
Browse files- generate_imatrix.py +110 -5
generate_imatrix.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
-
|
| 4 |
|
| 5 |
Runs transformer forward passes over calibration text to collect per-channel
|
| 6 |
E[xΒ²] activation statistics, then uses HPC triality BP to propagate importance
|
|
@@ -147,6 +147,7 @@ class GGUFModel:
|
|
| 147 |
'vocab_size': self.kv.get(f'{arch}.vocab_size', 0),
|
| 148 |
'rms_eps': self.kv.get(f'{arch}.attention.layer_norm_rms_epsilon', 1e-6),
|
| 149 |
'rope_base': self.kv.get(f'{arch}.rope.freq_base', 10000.0),
|
|
|
|
| 150 |
}
|
| 151 |
|
| 152 |
def get_tensor_f32(self, name):
|
|
@@ -342,9 +343,21 @@ def softmax(x, axis=-1):
|
|
| 342 |
e = np.exp(x - x_max)
|
| 343 |
return e / np.sum(e, axis=axis, keepdims=True)
|
| 344 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 345 |
def gelu(x):
|
|
|
|
| 346 |
return 0.5 * x * (1.0 + np.tanh(np.sqrt(2.0 / np.pi) * (x + 0.044715 * x**3)))
|
| 347 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 348 |
|
| 349 |
class TransformerRunner:
|
| 350 |
"""Minimal Gemma transformer for importance collection."""
|
|
@@ -354,6 +367,7 @@ class TransformerRunner:
|
|
| 354 |
self.cfg = config
|
| 355 |
self.verbose = verbose
|
| 356 |
self.head_dim = config['n_embd'] // config['n_head']
|
|
|
|
| 357 |
|
| 358 |
# Importance accumulators: tensor_name β (sum_x2, count)
|
| 359 |
self.importance = {}
|
|
@@ -438,8 +452,16 @@ class TransformerRunner:
|
|
| 438 |
scale = 1.0 / np.sqrt(head_dim)
|
| 439 |
attn = np.matmul(q_t, k_t.transpose(0, 2, 1)) * scale # [n_head, seq, seq]
|
| 440 |
|
| 441 |
-
# Causal mask
|
| 442 |
mask = np.triu(np.full((seq_len, seq_len), -1e9, dtype=np.float32), k=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 443 |
attn = attn + mask[np.newaxis, :, :]
|
| 444 |
attn = softmax(attn, axis=-1)
|
| 445 |
|
|
@@ -466,7 +488,7 @@ class TransformerRunner:
|
|
| 466 |
self._record(f'{pfx}.ffn_gate.weight', normed_ff)
|
| 467 |
self._record(f'{pfx}.ffn_up.weight', normed_ff)
|
| 468 |
|
| 469 |
-
gate_out =
|
| 470 |
up_out = normed_ff @ up_w.T
|
| 471 |
ff_mid = gate_out * up_out
|
| 472 |
|
|
@@ -499,7 +521,7 @@ class TransformerRunner:
|
|
| 499 |
self._record(f'{pfx}.ffn_gate.{exp_id}.weight', exp_input)
|
| 500 |
self._record(f'{pfx}.ffn_up.{exp_id}.weight', exp_input)
|
| 501 |
|
| 502 |
-
g =
|
| 503 |
u = exp_input @ ew_up.T
|
| 504 |
mid = g * u
|
| 505 |
self._record(f'{pfx}.ffn_down.{exp_id}.weight', mid)
|
|
@@ -515,6 +537,81 @@ class TransformerRunner:
|
|
| 515 |
|
| 516 |
return hidden
|
| 517 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 518 |
def forward(self, token_ids):
|
| 519 |
"""Full forward pass, collecting importance statistics."""
|
| 520 |
cfg = self.cfg
|
|
@@ -532,7 +629,15 @@ class TransformerRunner:
|
|
| 532 |
|
| 533 |
# Process each layer
|
| 534 |
for layer_idx in range(cfg['n_layers']):
|
| 535 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 536 |
if self.verbose and (layer_idx + 1) % 4 == 0:
|
| 537 |
print(f" Layer {layer_idx + 1}/{cfg['n_layers']}", end='\r')
|
| 538 |
|
|
|
|
| 1 |
#!/usr/bin/env python3
|
| 2 |
"""
|
| 3 |
+
HexState Importance Matrix Generator β HPC-Enhanced iMatrix from GGUF
|
| 4 |
|
| 5 |
Runs transformer forward passes over calibration text to collect per-channel
|
| 6 |
E[xΒ²] activation statistics, then uses HPC triality BP to propagate importance
|
|
|
|
| 147 |
'vocab_size': self.kv.get(f'{arch}.vocab_size', 0),
|
| 148 |
'rms_eps': self.kv.get(f'{arch}.attention.layer_norm_rms_epsilon', 1e-6),
|
| 149 |
'rope_base': self.kv.get(f'{arch}.rope.freq_base', 10000.0),
|
| 150 |
+
'swa_window': self.kv.get(f'{arch}.attention.sliding_window', 0),
|
| 151 |
}
|
| 152 |
|
| 153 |
def get_tensor_f32(self, name):
|
|
|
|
| 343 |
e = np.exp(x - x_max)
|
| 344 |
return e / np.sum(e, axis=axis, keepdims=True)
|
| 345 |
|
| 346 |
+
def silu(x):
|
| 347 |
+
"""SiLU / Swish activation β used by LLaMA, Mistral, Qwen, DeepSeek."""
|
| 348 |
+
return x * (1.0 / (1.0 + np.exp(-np.clip(x, -88, 88))))
|
| 349 |
+
|
| 350 |
def gelu(x):
|
| 351 |
+
"""GELU activation β used by Gemma, GPT-2."""
|
| 352 |
return 0.5 * x * (1.0 + np.tanh(np.sqrt(2.0 / np.pi) * (x + 0.044715 * x**3)))
|
| 353 |
|
| 354 |
+
# Architecture β activation function mapping
|
| 355 |
+
ACTIVATION_MAP = {
|
| 356 |
+
'llama': silu, 'mistral': silu, 'qwen2': silu, 'qwen2moe': silu,
|
| 357 |
+
'phi3': silu, 'falcon': silu, 'deepseek': silu, 'deepseek2': silu,
|
| 358 |
+
'gemma': gelu, 'gemma2': gelu, 'gpt2': gelu,
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
|
| 362 |
class TransformerRunner:
|
| 363 |
"""Minimal Gemma transformer for importance collection."""
|
|
|
|
| 367 |
self.cfg = config
|
| 368 |
self.verbose = verbose
|
| 369 |
self.head_dim = config['n_embd'] // config['n_head']
|
| 370 |
+
self.act_fn = ACTIVATION_MAP.get(config['arch'], silu)
|
| 371 |
|
| 372 |
# Importance accumulators: tensor_name β (sum_x2, count)
|
| 373 |
self.importance = {}
|
|
|
|
| 452 |
scale = 1.0 / np.sqrt(head_dim)
|
| 453 |
attn = np.matmul(q_t, k_t.transpose(0, 2, 1)) * scale # [n_head, seq, seq]
|
| 454 |
|
| 455 |
+
# Causal mask (with optional sliding window)
|
| 456 |
mask = np.triu(np.full((seq_len, seq_len), -1e9, dtype=np.float32), k=1)
|
| 457 |
+
swa = cfg.get('swa_window', 0)
|
| 458 |
+
if swa and swa > 0:
|
| 459 |
+
# Sliding window: mask out positions beyond the window
|
| 460 |
+
for i in range(seq_len):
|
| 461 |
+
for j in range(max(0, i - swa), i):
|
| 462 |
+
pass # already 0 (visible)
|
| 463 |
+
for j in range(0, max(0, i - swa)):
|
| 464 |
+
mask[i, j] = -1e9
|
| 465 |
attn = attn + mask[np.newaxis, :, :]
|
| 466 |
attn = softmax(attn, axis=-1)
|
| 467 |
|
|
|
|
| 488 |
self._record(f'{pfx}.ffn_gate.weight', normed_ff)
|
| 489 |
self._record(f'{pfx}.ffn_up.weight', normed_ff)
|
| 490 |
|
| 491 |
+
gate_out = self.act_fn(normed_ff @ gate_w.T)
|
| 492 |
up_out = normed_ff @ up_w.T
|
| 493 |
ff_mid = gate_out * up_out
|
| 494 |
|
|
|
|
| 521 |
self._record(f'{pfx}.ffn_gate.{exp_id}.weight', exp_input)
|
| 522 |
self._record(f'{pfx}.ffn_up.{exp_id}.weight', exp_input)
|
| 523 |
|
| 524 |
+
g = self.act_fn(exp_input @ ew_gate.T)
|
| 525 |
u = exp_input @ ew_up.T
|
| 526 |
mid = g * u
|
| 527 |
self._record(f'{pfx}.ffn_down.{exp_id}.weight', mid)
|
|
|
|
| 537 |
|
| 538 |
return hidden
|
| 539 |
|
| 540 |
+
def forward_linear_attn_layer(self, hidden, layer_idx):
|
| 541 |
+
"""Forward pass through a DeltaNet (gated linear attention) layer.
|
| 542 |
+
|
| 543 |
+
Used by Qwen 3.5/3.6 for ~75% of layers. Records importance stats
|
| 544 |
+
for all SSM projection weights.
|
| 545 |
+
"""
|
| 546 |
+
pfx = self._layer_prefix(layer_idx)
|
| 547 |
+
cfg = self.cfg
|
| 548 |
+
seq_len = hidden.shape[0]
|
| 549 |
+
|
| 550 |
+
# ββ Attention norm ββ
|
| 551 |
+
attn_norm_w = self._get_weight(f'{pfx}.attn_norm.weight')
|
| 552 |
+
if attn_norm_w is None:
|
| 553 |
+
return hidden
|
| 554 |
+
normed = rms_norm(hidden, attn_norm_w, cfg['rms_eps'])
|
| 555 |
+
|
| 556 |
+
# ββ DeltaNet projections ββ
|
| 557 |
+
qkv_w = self._get_weight(f'{pfx}.ssm_in_qkv.weight')
|
| 558 |
+
z_w = self._get_weight(f'{pfx}.ssm_in_z.weight')
|
| 559 |
+
a_w = self._get_weight(f'{pfx}.ssm_in_a.weight')
|
| 560 |
+
b_w = self._get_weight(f'{pfx}.ssm_in_b.weight')
|
| 561 |
+
out_w = self._get_weight(f'{pfx}.ssm_out.weight')
|
| 562 |
+
|
| 563 |
+
if qkv_w is None or out_w is None:
|
| 564 |
+
return hidden
|
| 565 |
+
|
| 566 |
+
# Record importance on input activations
|
| 567 |
+
self._record(f'{pfx}.ssm_in_qkv.weight', normed)
|
| 568 |
+
if z_w is not None:
|
| 569 |
+
self._record(f'{pfx}.ssm_in_z.weight', normed)
|
| 570 |
+
if a_w is not None:
|
| 571 |
+
self._record(f'{pfx}.ssm_in_a.weight', normed)
|
| 572 |
+
if b_w is not None:
|
| 573 |
+
self._record(f'{pfx}.ssm_in_b.weight', normed)
|
| 574 |
+
|
| 575 |
+
# Approximate forward: project through QKV and output
|
| 576 |
+
# (Full DeltaNet recurrence is complex; for importance collection
|
| 577 |
+
# we just need the activation magnitudes at each projection)
|
| 578 |
+
qkv = normed @ qkv_w.T
|
| 579 |
+
|
| 580 |
+
# For importance: record output projection input
|
| 581 |
+
# Use qkv as a proxy for the recurrent state output
|
| 582 |
+
n_out = out_w.shape[1] if out_w.ndim >= 2 else hidden.shape[-1]
|
| 583 |
+
if qkv.shape[-1] >= n_out:
|
| 584 |
+
out_input = qkv[:, :n_out]
|
| 585 |
+
else:
|
| 586 |
+
out_input = qkv
|
| 587 |
+
self._record(f'{pfx}.ssm_out.weight', out_input)
|
| 588 |
+
|
| 589 |
+
attn_out = out_input @ out_w.T
|
| 590 |
+
hidden = hidden + attn_out
|
| 591 |
+
|
| 592 |
+
# ββ FFN (same as standard transformer) ββ
|
| 593 |
+
ffn_norm_w = self._get_weight(f'{pfx}.ffn_norm.weight')
|
| 594 |
+
if ffn_norm_w is None:
|
| 595 |
+
return hidden
|
| 596 |
+
|
| 597 |
+
normed_ff = rms_norm(hidden, ffn_norm_w, cfg['rms_eps'])
|
| 598 |
+
|
| 599 |
+
gate_w = self._get_weight(f'{pfx}.ffn_gate.weight')
|
| 600 |
+
up_w = self._get_weight(f'{pfx}.ffn_up.weight')
|
| 601 |
+
down_w = self._get_weight(f'{pfx}.ffn_down.weight')
|
| 602 |
+
|
| 603 |
+
if gate_w is not None and up_w is not None and down_w is not None:
|
| 604 |
+
self._record(f'{pfx}.ffn_gate.weight', normed_ff)
|
| 605 |
+
self._record(f'{pfx}.ffn_up.weight', normed_ff)
|
| 606 |
+
gate_out = self.act_fn(normed_ff @ gate_w.T)
|
| 607 |
+
up_out = normed_ff @ up_w.T
|
| 608 |
+
ff_mid = gate_out * up_out
|
| 609 |
+
self._record(f'{pfx}.ffn_down.weight', ff_mid)
|
| 610 |
+
ff_out = ff_mid @ down_w.T
|
| 611 |
+
hidden = hidden + ff_out
|
| 612 |
+
|
| 613 |
+
return hidden
|
| 614 |
+
|
| 615 |
def forward(self, token_ids):
|
| 616 |
"""Full forward pass, collecting importance statistics."""
|
| 617 |
cfg = self.cfg
|
|
|
|
| 629 |
|
| 630 |
# Process each layer
|
| 631 |
for layer_idx in range(cfg['n_layers']):
|
| 632 |
+
# Check if this layer has DeltaNet tensors (Qwen 3.6 hybrid)
|
| 633 |
+
pfx = f"blk.{layer_idx}"
|
| 634 |
+
has_linear_attn = f'{pfx}.ssm_in_qkv.weight' in self.model.tensor_infos
|
| 635 |
+
has_full_attn = f'{pfx}.attn_q.weight' in self.model.tensor_infos
|
| 636 |
+
|
| 637 |
+
if has_linear_attn and not has_full_attn:
|
| 638 |
+
hidden = self.forward_linear_attn_layer(hidden, layer_idx)
|
| 639 |
+
else:
|
| 640 |
+
hidden = self.forward_layer(hidden, layer_idx, cos_f, sin_f)
|
| 641 |
if self.verbose and (layer_idx + 1) % 4 == 0:
|
| 642 |
print(f" Layer {layer_idx + 1}/{cfg['n_layers']}", end='\r')
|
| 643 |
|