Download colab_bundle/modules/bitnet_v2_engine.py from CrashOverrideX/Quillan-Ronin: direct link, hf CLI and curl.
- Browser
- Download file 19.4 kB
-
https://huggingface.co/CrashOverrideX/Quillan-Ronin/resolve/main/colab_bundle/modules/bitnet_v2_engine.py
- Command line
-
hf download hf://CrashOverrideX/Quillan-Ronin/colab_bundle/modules/bitnet_v2_engine.py
-
curl -L -o bitnet_v2_engine.py https://huggingface.co/CrashOverrideX/Quillan-Ronin/resolve/main/colab_bundle/modules/bitnet_v2_engine.py
19.4 kB
| """ | |
| BitNet v2: Native 4-bit Activations with Hadamard Transformation for 1-bit LLMs | |
| (arXiv:2504.18415v2, Hongyu Wang*, Shuming Ma*, Furu Wei - Microsoft Research & UCAS). | |
| Mathematical Foundations & Invariants: | |
| -------------------------------------- | |
| 1. 1.58-bit Weights + Native 4-bit Activations: | |
| Replaces previous 8-bit activation bottlenecks in BitNet b1.58 and hybrid sparsification | |
| in BitNet a4.8, unlocking hardware-accelerated 4-bit tensor arithmetic (e.g. GB200 NVFP4 / INT4). | |
| 2. H-BitLinear with Online Hadamard Transformation (Eq. 3, 4, 7): | |
| Addresses severe activation outlier channels in intermediate projections (Wo in attention, | |
| Wdown in FFN). Applies an orthogonal Walsh-Hadamard transformation Hm prior to quantization: | |
| Hm = (1 / sqrt(2)) * [[H_{m-1}, H_{m-1}], | |
| [H_{m-1}, -H_{m-1}]], H0 = [1] | |
| Xr = Hadamard(LN(X)) | |
| Orthogonality: Hm = Hm^T, Hm * Hm = I. | |
| Grad backprop (Eq. 8): dL/dX = Hadamard(dL/d(Hadamard(X))). | |
| Reduces activation kurtosis and peak outlier magnitude, reshaping sharp intermediate | |
| distributions into Gaussian-like distributions suitable for native INT4 quantization. | |
| 3. Ternary Weight Quantization (Eq. 1, 2): | |
| Per-tensor absmean quantization into {-1, 0, 1}: | |
| Qw(W) = alpha * RoundClip(W / (alpha + eps), -1, 1), alpha = mean(|W|) | |
| 4. Dual Activation Quantization (Eq. 5, 6): | |
| - 8-bit Activations (Absmax): | |
| Q_INT8(X) = (gamma / 127) * RoundClip((127 / (gamma + eps)) * X, -128, 127), gamma = max(|X|) | |
| - 4-bit Activations (Absmean with sqrt(7) scale): | |
| Q_INT4(X) = (beta / sqrt(7)) * RoundClip((sqrt(7) / (beta + eps)) * X, -8, 7), beta = mean(|X|) | |
| 5. Low-Bit Attention & KV Cache (Section 3.1, Tables 2 & 3): | |
| Supports 4-bit and 3-bit KV cache with 8-bit BOS token protection. | |
| """ | |
| import math | |
| from typing import Dict, Any, Optional, Tuple | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| def fast_hadamard_transform(x: torch.Tensor) -> torch.Tensor: | |
| """ | |
| Fast Walsh-Hadamard Transform (FWHT) along the last dimension. | |
| Satisfies Hm = (1 / sqrt(2)) * [[H_{m-1}, H_{m-1}], [H_{m-1}, -H_{m-1}]], H0 = 1. | |
| Symmetric and orthogonal: H = H^T and H * H = I (O(n log n) complexity). | |
| """ | |
| orig_shape = x.shape | |
| n = orig_shape[-1] | |
| if (n & (n - 1)) != 0 or n <= 0: | |
| raise ValueError(f"Hadamard transform dimension {n} must be a power of 2.") | |
| res = x.clone().to(dtype=torch.float32) | |
| h = 1 | |
| sqrt2_inv = 1.0 / math.sqrt(2.0) | |
| while h < n: | |
| res = res.view(-1, n // (2 * h), 2, h) | |
| u = res[:, :, 0, :].clone() | |
| v = res[:, :, 1, :].clone() | |
| res[:, :, 0, :] = (u + v) * sqrt2_inv | |
| res[:, :, 1, :] = (u - v) * sqrt2_inv | |
| h *= 2 | |
| return res.view(orig_shape).to(dtype=x.dtype) | |
| class HadamardTransformFunction(torch.autograd.Function): | |
| """ | |
| Autograd function for online Hadamard transformation. | |
| Since Hm is orthogonal and symmetric, the backward pass is exact: | |
| dL/dX = Hadamard(dL/d(Hadamard(X))) (Paper Eq. 8). | |
| """ | |
| def forward(ctx, x: torch.Tensor) -> torch.Tensor: | |
| return fast_hadamard_transform(x) | |
| def backward(ctx, grad_output: torch.Tensor) -> torch.Tensor: | |
| return fast_hadamard_transform(grad_output) | |
| def hadamard_transform(x: torch.Tensor) -> torch.Tensor: | |
| return HadamardTransformFunction.apply(x) | |
| class WeightQuantTernarySTE(torch.autograd.Function): | |
| """ | |
| Ternary weight quantization using absmean scaling: | |
| Qw(W) = alpha * RoundClip(W / (alpha + eps), -1, 1), alpha = mean(|W|) | |
| Straight-Through Estimator (STE) passes gradients directly to latent weights. | |
| """ | |
| def forward(ctx, w: torch.Tensor, eps: float = 1e-7) -> torch.Tensor: | |
| alpha = torch.mean(torch.abs(w)) | |
| scale = alpha + eps | |
| w_scaled = w / scale | |
| w_q = torch.clamp(torch.round(w_scaled), -1.0, 1.0) | |
| return w_q * alpha | |
| def backward(ctx, grad_output: torch.Tensor) -> Tuple[torch.Tensor, None]: | |
| return grad_output.clone(), None | |
| def quantize_weight_ternary(w: torch.Tensor, eps: float = 1e-7) -> torch.Tensor: | |
| return WeightQuantTernarySTE.apply(w, eps) | |
| class ActQuantINT8STE(torch.autograd.Function): | |
| """ | |
| 8-bit activation quantization using per-token absmax (Paper Eq. 5): | |
| Q_INT8(X) = (gamma / 127) * RoundClip((127 / (gamma + eps)) * X, -128, 127) | |
| gamma = max(|X|) along last dimension. | |
| """ | |
| def forward(ctx, x: torch.Tensor, eps: float = 1e-7) -> torch.Tensor: | |
| gamma = torch.amax(torch.abs(x), dim=-1, keepdim=True) | |
| scale = gamma + eps | |
| x_scaled = (127.0 / scale) * x | |
| x_q = torch.clamp(torch.round(x_scaled), -128.0, 127.0) | |
| return (scale / 127.0) * x_q | |
| def backward(ctx, grad_output: torch.Tensor) -> Tuple[torch.Tensor, None]: | |
| return grad_output.clone(), None | |
| def quantize_act_int8(x: torch.Tensor, eps: float = 1e-7) -> torch.Tensor: | |
| return ActQuantINT8STE.apply(x, eps) | |
| class ActQuantINT4STE(torch.autograd.Function): | |
| """ | |
| Native 4-bit activation quantization using per-token absmean (Paper Eq. 6): | |
| Q_INT4(X) = (beta / sqrt(7)) * RoundClip((sqrt(7) / (beta + eps)) * X, -8, 7) | |
| beta = mean(|X|) along last dimension. | |
| """ | |
| def forward(ctx, x: torch.Tensor, eps: float = 1e-7) -> torch.Tensor: | |
| beta = torch.mean(torch.abs(x), dim=-1, keepdim=True) | |
| scale = beta + eps | |
| sqrt7 = math.sqrt(7.0) | |
| x_scaled = (sqrt7 / scale) * x | |
| x_q = torch.clamp(torch.round(x_scaled), -8.0, 7.0) | |
| return (scale / sqrt7) * x_q | |
| def backward(ctx, grad_output: torch.Tensor) -> Tuple[torch.Tensor, None]: | |
| return grad_output.clone(), None | |
| def quantize_act_int4(x: torch.Tensor, eps: float = 1e-7) -> torch.Tensor: | |
| return ActQuantINT4STE.apply(x, eps) | |
| class BitLinearV2(nn.Module): | |
| """ | |
| Standard BitLinear layer for inputs with natural Gaussian-like distributions | |
| (e.g. Wqkv, Wup, Wgate in BitNet v2). | |
| - RMSNorm on inputs | |
| - INT8 or INT4 activation quantization | |
| - Absmean ternary weights | |
| """ | |
| def __init__(self, in_features: int, out_features: int, act_mode: str = "int4", eps: float = 1e-7): | |
| super().__init__() | |
| self.in_features = in_features | |
| self.out_features = out_features | |
| self.act_mode = act_mode.lower() | |
| self.eps = eps | |
| self.weight = nn.Parameter(torch.randn(out_features, in_features) * (1.0 / math.sqrt(in_features))) | |
| self.norm = nn.RMSNorm(in_features, eps=eps) | |
| def set_activation_mode(self, mode: str): | |
| assert mode.lower() in ("int8", "int4", "fp16", "fp32") | |
| self.act_mode = mode.lower() | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| # RMSNorm | |
| x_norm = self.norm(x) | |
| # Activation Quantization | |
| if self.act_mode == "int8": | |
| x_q = quantize_act_int8(x_norm, self.eps) | |
| elif self.act_mode == "int4": | |
| x_q = quantize_act_int4(x_norm, self.eps) | |
| else: | |
| x_q = x_norm | |
| # Weight Quantization | |
| w_q = quantize_weight_ternary(self.weight, self.eps) | |
| return F.linear(x_q, w_q) | |
| class HBitLinear(nn.Module): | |
| """ | |
| H-BitLinear layer for intermediate representations with severe outlier channels | |
| (Wo in Attention, Wdown in FFN, Paper Eq. 7). | |
| - RMSNorm | |
| - Online Hadamard transformation: Xr = Hadamard(RMSNorm(X)) | |
| - INT8 or INT4 activation quantization on Gaussianized representation | |
| - Absmean ternary weights | |
| """ | |
| def __init__(self, in_features: int, out_features: int, act_mode: str = "int4", eps: float = 1e-7): | |
| super().__init__() | |
| if (in_features & (in_features - 1)) != 0 or in_features <= 0: | |
| raise ValueError(f"H-BitLinear in_features ({in_features}) must be a power of 2.") | |
| self.in_features = in_features | |
| self.out_features = out_features | |
| self.act_mode = act_mode.lower() | |
| self.eps = eps | |
| self.weight = nn.Parameter(torch.randn(out_features, in_features) * (1.0 / math.sqrt(in_features))) | |
| self.norm = nn.RMSNorm(in_features, eps=eps) | |
| def set_activation_mode(self, mode: str): | |
| assert mode.lower() in ("int8", "int4", "fp16", "fp32") | |
| self.act_mode = mode.lower() | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| # 1. Normalization | |
| x_norm = self.norm(x) | |
| # 2. Online Hadamard transformation (Eq. 3, 4, 7) | |
| x_hadamard = hadamard_transform(x_norm) | |
| # 3. Low-bit Activation Quantization (Eq. 5, 6) | |
| if self.act_mode == "int8": | |
| x_q = quantize_act_int8(x_hadamard, self.eps) | |
| elif self.act_mode == "int4": | |
| x_q = quantize_act_int4(x_hadamard, self.eps) | |
| else: | |
| x_q = x_hadamard | |
| # 4. Ternary Weight Quantization & Linear Projection | |
| w_q = quantize_weight_ternary(self.weight, self.eps) | |
| return F.linear(x_q, w_q) | |
| class BitNetV2Attention(nn.Module): | |
| """ | |
| Multi-Head Attention module for BitNet v2: | |
| - Wq, Wk, Wv projections using BitLinearV2 (no Hadamard needed, Gaussian inputs). | |
| - Wo projection using HBitLinear (Hadamard transform suppresses attention output outliers). | |
| - Post-RoPE low-bit KV Cache quantization (4-bit or 3-bit) with 8-bit BOS token retention. | |
| """ | |
| def __init__( | |
| self, | |
| embed_dim: int, | |
| num_heads: int, | |
| act_mode: str = "int4", | |
| kv_cache_bits: Optional[int] = 4, | |
| eps: float = 1e-7 | |
| ): | |
| super().__init__() | |
| assert embed_dim % num_heads == 0, "embed_dim must be divisible by num_heads" | |
| self.embed_dim = embed_dim | |
| self.num_heads = num_heads | |
| self.head_dim = embed_dim // num_heads | |
| self.act_mode = act_mode | |
| self.kv_cache_bits = kv_cache_bits | |
| self.eps = eps | |
| self.q_proj = BitLinearV2(embed_dim, embed_dim, act_mode=act_mode, eps=eps) | |
| self.k_proj = BitLinearV2(embed_dim, embed_dim, act_mode=act_mode, eps=eps) | |
| self.v_proj = BitLinearV2(embed_dim, embed_dim, act_mode=act_mode, eps=eps) | |
| # Output projection MUST use H-BitLinear | |
| self.out_proj = HBitLinear(embed_dim, embed_dim, act_mode=act_mode, eps=eps) | |
| def set_activation_mode(self, mode: str): | |
| self.act_mode = mode | |
| self.q_proj.set_activation_mode(mode) | |
| self.k_proj.set_activation_mode(mode) | |
| self.v_proj.set_activation_mode(mode) | |
| self.out_proj.set_activation_mode(mode) | |
| def _quantize_kv_head(self, tensor: torch.Tensor, bits: int) -> torch.Tensor: | |
| """Quantizes key/value states with BOS token (index 0) preserved at 8-bit.""" | |
| B, H, S, D = tensor.shape | |
| if S == 0 or bits is None or bits >= 16: | |
| return tensor | |
| # 8-bit for BOS (index 0) | |
| bos = tensor[:, :, :1, :] | |
| bos_q = quantize_act_int8(bos, self.eps) | |
| if S == 1: | |
| return bos_q | |
| # Remaining tokens quantized to target bits (e.g. 4-bit or 3-bit) | |
| rem = tensor[:, :, 1:, :] | |
| if bits == 4: | |
| rem_q = quantize_act_int4(rem, self.eps) | |
| elif bits == 3: | |
| # 3-bit quantization: [-4, 3] clip with per-token scale | |
| gamma = torch.amax(torch.abs(rem), dim=-1, keepdim=True) + self.eps | |
| scaled = (3.0 / gamma) * rem | |
| clipped = torch.clamp(torch.round(scaled), -4.0, 3.0) | |
| rem_q = (gamma / 3.0) * clipped | |
| else: | |
| rem_q = quantize_act_int8(rem, self.eps) | |
| return torch.cat([bos_q, rem_q], dim=2) | |
| def forward( | |
| self, | |
| x: torch.Tensor, | |
| mask: Optional[torch.Tensor] = None | |
| ) -> Tuple[torch.Tensor, torch.Tensor]: | |
| B, S, D = x.shape | |
| q = self.q_proj(x).view(B, S, self.num_heads, self.head_dim).transpose(1, 2) | |
| k = self.k_proj(x).view(B, S, self.num_heads, self.head_dim).transpose(1, 2) | |
| v = self.v_proj(x).view(B, S, self.num_heads, self.head_dim).transpose(1, 2) | |
| # Quantize KV cache if specified (with 8-bit BOS token protection) | |
| if self.kv_cache_bits is not None: | |
| k = self._quantize_kv_head(k, self.kv_cache_bits) | |
| v = self._quantize_kv_head(v, self.kv_cache_bits) | |
| # Attention calculation | |
| scores = torch.matmul(q, k.transpose(-1, -2)) / math.sqrt(self.head_dim) | |
| if mask is not None: | |
| scores = scores + mask | |
| attn_weights = F.softmax(scores, dim=-1) | |
| context = torch.matmul(attn_weights, v) | |
| # Reshape context back to (B, S, D) | |
| context = context.transpose(1, 2).contiguous().view(B, S, D) | |
| out = self.out_proj(context) | |
| return out, attn_weights | |
| class BitNetV2FFN(nn.Module): | |
| """ | |
| SwiGLU Feed-Forward Network for BitNet v2: | |
| - Wgate and Wup use BitLinearV2 (Gaussian inputs). | |
| - Activation: Swish(x * Wgate) * (x * Wup). | |
| - Wdown uses HBitLinear (Hadamard transform suppresses SwiGLU outlier channels). | |
| """ | |
| def __init__( | |
| self, | |
| embed_dim: int, | |
| intermediate_dim: int, | |
| act_mode: str = "int4", | |
| eps: float = 1e-7 | |
| ): | |
| super().__init__() | |
| if (intermediate_dim & (intermediate_dim - 1)) != 0 or intermediate_dim <= 0: | |
| raise ValueError(f"intermediate_dim ({intermediate_dim}) must be a power of 2 for H-BitLinear.") | |
| self.embed_dim = embed_dim | |
| self.intermediate_dim = intermediate_dim | |
| self.act_mode = act_mode | |
| self.eps = eps | |
| self.gate_proj = BitLinearV2(embed_dim, intermediate_dim, act_mode=act_mode, eps=eps) | |
| self.up_proj = BitLinearV2(embed_dim, intermediate_dim, act_mode=act_mode, eps=eps) | |
| # Down projection MUST use H-BitLinear | |
| self.down_proj = HBitLinear(intermediate_dim, embed_dim, act_mode=act_mode, eps=eps) | |
| def set_activation_mode(self, mode: str): | |
| self.act_mode = mode | |
| self.gate_proj.set_activation_mode(mode) | |
| self.up_proj.set_activation_mode(mode) | |
| self.down_proj.set_activation_mode(mode) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| gate = F.silu(self.gate_proj(x)) | |
| up = self.up_proj(x) | |
| inter = gate * up | |
| return self.down_proj(inter) | |
| class BitNetV2TransformerBlock(nn.Module): | |
| """ | |
| BitNet v2 Transformer Layer with RMSNorm residual connections, | |
| H-BitLinear at Wo and Wdown, and native INT4/INT8 activation support. | |
| """ | |
| def __init__( | |
| self, | |
| embed_dim: int, | |
| num_heads: int, | |
| intermediate_dim: int, | |
| act_mode: str = "int4", | |
| kv_cache_bits: Optional[int] = 4, | |
| eps: float = 1e-7 | |
| ): | |
| super().__init__() | |
| self.attn = BitNetV2Attention( | |
| embed_dim=embed_dim, | |
| num_heads=num_heads, | |
| act_mode=act_mode, | |
| kv_cache_bits=kv_cache_bits, | |
| eps=eps | |
| ) | |
| self.ffn = BitNetV2FFN( | |
| embed_dim=embed_dim, | |
| intermediate_dim=intermediate_dim, | |
| act_mode=act_mode, | |
| eps=eps | |
| ) | |
| def set_activation_mode(self, mode: str): | |
| self.attn.set_activation_mode(mode) | |
| self.ffn.set_activation_mode(mode) | |
| def forward( | |
| self, | |
| x: torch.Tensor, | |
| mask: Optional[torch.Tensor] = None | |
| ) -> torch.Tensor: | |
| attn_out, _ = self.attn(x, mask=mask) | |
| x = x + attn_out | |
| ffn_out = self.ffn(x) | |
| x = x + ffn_out | |
| return x | |
| class BitNetV2Model(nn.Module): | |
| """ | |
| Full BitNet v2 Model implementing LLaMA-like architecture with native 4-bit activations | |
| and online Hadamard transformation. | |
| """ | |
| def __init__( | |
| self, | |
| vocab_size: int, | |
| embed_dim: int, | |
| num_heads: int, | |
| intermediate_dim: int, | |
| num_layers: int, | |
| act_mode: str = "int4", | |
| kv_cache_bits: Optional[int] = 4, | |
| eps: float = 1e-7 | |
| ): | |
| super().__init__() | |
| self.vocab_size = vocab_size | |
| self.embed_dim = embed_dim | |
| self.num_layers = num_layers | |
| self.act_mode = act_mode | |
| self.tok_embeddings = nn.Embedding(vocab_size, embed_dim) | |
| self.layers = nn.ModuleList([ | |
| BitNetV2TransformerBlock( | |
| embed_dim=embed_dim, | |
| num_heads=num_heads, | |
| intermediate_dim=intermediate_dim, | |
| act_mode=act_mode, | |
| kv_cache_bits=kv_cache_bits, | |
| eps=eps | |
| ) | |
| for _ in range(num_layers) | |
| ]) | |
| self.final_norm = nn.RMSNorm(embed_dim, eps=eps) | |
| self.lm_head = nn.Linear(embed_dim, vocab_size, bias=False) | |
| def set_activation_mode(self, mode: str): | |
| self.act_mode = mode | |
| for layer in self.layers: | |
| layer.set_activation_mode(mode) | |
| def forward(self, input_ids: torch.Tensor, mask: Optional[torch.Tensor] = None) -> torch.Tensor: | |
| h = self.tok_embeddings(input_ids) | |
| for layer in self.layers: | |
| h = layer(h, mask=mask) | |
| h = self.final_norm(h) | |
| return self.lm_head(h) | |
| class OutlierDistributionProfiler: | |
| """ | |
| Analytical profiler verifying Paper 39 invariants: | |
| - Kurtosis and maximum outlier attenuation under Hadamard transformation | |
| - Transition from sharp outlier distributions to Gaussian-like distributions | |
| """ | |
| def compute_kurtosis(x: torch.Tensor) -> float: | |
| """Excess kurtosis of tensor (Gaussian has excess kurtosis = 0).""" | |
| x_flat = x.detach().flatten().float() | |
| mean = torch.mean(x_flat) | |
| var = torch.var(x_flat, unbiased=False) | |
| if var < 1e-12: | |
| return 0.0 | |
| m4 = torch.mean((x_flat - mean) ** 4) | |
| return (m4 / (var ** 2) - 3.0).item() | |
| def compute_outlier_ratio(x: torch.Tensor, threshold_sigma: float = 3.0) -> float: | |
| """Fraction of elements exceeding threshold_sigma standard deviations from mean.""" | |
| x_flat = x.detach().flatten().float() | |
| mean = torch.mean(x_flat) | |
| std = torch.std(x_flat) | |
| if std < 1e-12: | |
| return 0.0 | |
| outliers = torch.abs(x_flat - mean) > (threshold_sigma * std) | |
| return (torch.sum(outliers).float() / x_flat.numel()).item() | |
| def analyze_hadamard_effect(x_intermediate: torch.Tensor) -> Dict[str, Any]: | |
| """ | |
| Profiles activations before and after Hadamard transformation. | |
| Demonstrates reduction in peak activation and smoothing of outlier channels. | |
| """ | |
| x_had = fast_hadamard_transform(x_intermediate) | |
| peak_before = torch.max(torch.abs(x_intermediate)).item() | |
| peak_after = torch.max(torch.abs(x_had)).item() | |
| kurt_before = OutlierDistributionProfiler.compute_kurtosis(x_intermediate) | |
| kurt_after = OutlierDistributionProfiler.compute_kurtosis(x_had) | |
| return { | |
| "peak_before": peak_before, | |
| "peak_after": peak_after, | |
| "peak_reduction_ratio": peak_before / (peak_after + 1e-12), | |
| "kurtosis_before": kurt_before, | |
| "kurtosis_after": kurt_after, | |
| "gaussianized": abs(kurt_after) < abs(kurt_before) | |
| } | |