Instructions to use arcticoneai/gemma-1bit with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use arcticoneai/gemma-1bit with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="arcticoneai/gemma-1bit")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("arcticoneai/gemma-1bit", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use arcticoneai/gemma-1bit with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "arcticoneai/gemma-1bit" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "arcticoneai/gemma-1bit", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/arcticoneai/gemma-1bit
- SGLang
How to use arcticoneai/gemma-1bit with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "arcticoneai/gemma-1bit" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "arcticoneai/gemma-1bit", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "arcticoneai/gemma-1bit" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "arcticoneai/gemma-1bit", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use arcticoneai/gemma-1bit with Docker Model Runner:
docker model run hf.co/arcticoneai/gemma-1bit
license: mit
base_model:
- google/gemma-4-31B-it
pipeline_tag: image-text-to-text
tags:
- llm
- transformers
1-Bit Quantisation for LLMs: DeepSeek-V4 Pro & Gemma 4 31B IT
Gemma 4 31B — Experimental 1-bit Quantization
Status (August 2026): Proof-of-concept.
True 1-bit packed weights (Gemma 4 31B IT) + Adaptive Mask approach (DeepSeek-V4 Pro).
What works right now
- Model packed into ~3.5 GB GGUF
- Structure successfully verified on Pixel 4 XL (6 GB RAM) via Termux + patched
ik_llama.cpp - Detailed per-layer R² analysis available
What does not work well yet
- Real text generation quality is significantly degraded (error accumulation across layers)
- Full correct inference on Android/iPhone is not stable
- Real-generation R² is much lower than weight-level / synthetic R²
This is research / experimental work, not a production-ready model.
GitHub (setup + patches): https://github.com/elliotlib/quant-1bit
Contact: bogunusov@gmail.com | X: @liberal17th
Looking for collaboration: compute, custom 1-bit kernels, or joint research.
Part 1: DeepSeek-V4 Pro — Adaptive Mask V2
1.1.1 Running on android
How run on android: Repository on GitHub
1.1 What We Are Approximating
DeepSeek-V4 Pro is a Mixture-of-Experts (MoE) model with the following architecture:
| Parameter | Value |
|---|---|
| Hidden Size | 6,144 |
| Attention Heads | 48 |
| KV Heads | 8 (GQA) |
| Intermediate Size | 16,384 |
| MoE Intermediate Size | 2,048 |
| Number of Experts | 256 (1 shared + 256 routed) |
| Top-k Routed | 6 |
| Top-k Total | 7 |
| Layers | 61 |
| Vocabulary | 129,280 |
| Max Position Embeddings | 163,840 |
| RoPE Theta | 10,000 |
| RMSNorm Epsilon | 1e-6 |
| MLA (Multi-Head Latent Attention) | Enabled |
| Q LoRA Rank | 1,536 |
| KV LoRA Rank | 512 |
| V Head Dimension | 128 |
| QK NoPE Head Dim | 128 |
| QK RoPE Head Dim | 64 |
| Compressor Dim | 512 |
| Compressor Gate Dim | 7,168 |
| HC Attention Dim | 24 |
| HC FFN Dim | 24 |
| FFN Gate Dim | 384 |
| Head Dim | 128 |
The model uses Multi-Head Latent Attention (MLA) — a compressed attention mechanism where Q, K, V projections are decomposed into low-rank matrices (q_a_proj, q_b_proj, kv_a_proj, kv_b_proj, q_down_proj, q_up_proj). This adds complexity because weight matrices are no longer simple [out_dim, in_dim] projections but involve compressed latent representations.
1.2 The Core Problem
We want to approximate every floating-point weight tensor in the model using a representation that uses effectively 1 bit per weight (or close to it), while preserving the model's output distribution during text generation. The challenge is that:
- A 1-bit weight has only 2 states: +scale or -scale
- LLM weights are normally distributed with mean ≈ 0 and small std
- Simply thresholding at zero destroys the fine-grained magnitude information that the model learned during training
- The approximation must preserve not just the weight values, but their behavior under matrix multiplication with real input activations
1.3 Technical Approach: Adaptive Mask V2
The method does NOT use SVD, quantization grids, or codebooks. Instead, it uses an iterative refinement process based on structured group scalars and adaptive block-wise masking.
Step-by-Step Algorithm
Step 1: Normalization
W_mean = mean(W)
W_std = std(W) + 1e-8
W_norm = (W - W_mean) / W_std
This centers the weights and normalizes variance, making the subsequent masking scale-invariant.
Step 2: Block-wise Energy Analysis The weight matrix is divided into non-overlapping blocks (default 8×8 or 15×15). For a matrix of shape [rows, cols]:
pad_rows = (block_size - rows % block_size) % block_size
pad_cols = (block_size - cols % block_size) % block_size
W_padded = pad(W_norm, (0, pad_cols, 0, pad_rows))
num_row_blocks = padded_rows // block_size
num_col_blocks = padded_cols // block_size
W_blocks = W_padded.reshape(num_row_blocks, block_size, num_col_blocks, block_size)
block_energy = sum(abs(W_blocks), dim=(1, 3)) # Sum of absolute values per block
Step 3: Adaptive Mask Selection Based on the layer type, a coverage ratio is selected:
| Layer Type | Base Ratio | Large Tensor (>10M) Adjustment |
|---|---|---|
| Embedding | 95% | -5% → 90% |
| LM Head | 95% | -5% → 90% |
| Norm (RMSNorm) | 99% | No adjustment |
| Attention Projection | 88% | -5% → 83% |
| MLA Projection | 88% | -5% → 83% |
| Router | 90% | -5% → 85% |
| FFN Gate | 82% | -5% → 77% |
| FFN Linear | 82% | -5% → 77% |
| Compressor Gate | 88% | -5% → 83% |
| Compressor WKV | 88% | -5% → 83% |
| Compressor APE | 88% | -5% → 83% |
| HC Function | 85% | -5% → 80% |
| Generic Linear | 85% | -5% → 80% |
| Generic 1D | 95% | No adjustment |
| Generic ND | 85% | -5% → 80% |
The top-k blocks by energy are selected, where k = total_blocks × coverage_ratio.
Step 4: Multi-Pass Scalar Refinement (8-15 passes) This is the core innovation. Instead of storing individual weights, we store group scalars that reconstruct the weights:
For each pass:
For each group of 64 rows:
W_group = current_residual[start:end]
mask_group = adaptive_mask[start:end]
# Positive scalar: mean of positive masked elements
pos_mask = (W_group > 0) * mask_group
s_plus = sum(W_group * pos_mask) / (sum(pos_mask) + 1e-8)
# Negative scalar: mean of negative masked elements
neg_mask = (W_group < 0) * mask_group
s_minus = sum(W_group * neg_mask) / (sum(neg_mask) + 1e-8)
# Reconstruct this group
reconstruction += pos_mask * s_plus + neg_mask * s_minus
# Compute residual for next pass
residual = W_norm - reconstruction
current_residual = residual * adaptive_mask
# Adaptively shrink coverage for next pass (focus on hardest elements)
if not last_pass:
current_ratio = max(initial_ratio * (0.95^pass_idx), 0.50)
recompute mask on |residual| with new ratio
Step 5: Denormalization and Residual Bias
W_recon = reconstruction * W_std + W_mean
# For elements NOT covered by mask, add mean residual bias
uncovered_mask = (mask < 0.5)
residual_mean = sum((W_orig - W_recon) * uncovered_mask) / sum(uncovered_mask)
W_recon += residual_mean * uncovered_mask
Step 6: Real Generation R² Check This is critical: we don't just compare W_orig vs W_recon elementwise. Instead:
- Download real token embeddings from the model's embedding layer
- Generate random token sequences
- Run forward passes through the actual layer operation (linear, rmsnorm, embedding)
- Compare output activations: R² = 1 - SS_res / SS_tot
1.4 What Gets Stored (The "Compressed" Representation)
For each tensor, we store:
- Global norm params: W_mean, W_std (2 floats)
- Scalar layers: For each of 8 passes, for each of N groups: (s_plus, s_minus) — stored as flat list
- Mask metadata: The actual mask is NOT stored; it's recomputed from the stored scalars and norm params during reconstruction
- Coverage ratio: The actual ratio used
This is NOT true 1-bit storage — it's a structured scalar approximation. The theoretical compression is extreme because we store ~2×num_groups×num_passes scalars instead of millions of weights.
1.5 Results on Layer 0 (14 Tensors)
| Rank | Tensor Key | Layer Type | Shape | R² (Real Gen) | Mask Coverage |
|---|---|---|---|---|---|
| 1 | layers.0.ffn_norm.weight | norm | [7,168] | 0.9999 | 99.0% |
| 2 | layers.0.attn.q_norm.weight | norm | [1,536] | 0.9998 | 99.0% |
| 3 | layers.0.attn.kv_norm.weight | norm | [512] | 0.9996 | 98.8% |
| 4 | layers.0.attn_norm.weight | norm | [7,168] | 0.9995 | 99.0% |
| 5 | layers.0.attn.compressor.norm.weight | norm | [512] | 0.9981 | 98.8% |
| 6 | layers.0.hc_attn_base | hc_base | [24] | 0.9916 | 83.3% |
| 7 | layers.0.hc_ffn_base | hc_base | [24] | 0.9909 | 83.3% |
| 8 | layers.0.attn.attn_sink | attn_sink | [128] | 0.9904 | 84.4% |
| 9 | layers.0.attn.compressor.wkv.weight | compressor_wkv | [512, 7,168] | 0.9136 | 64.7% |
| 10 | layers.0.attn.compressor.wgate.weight | compressor_gate | [512, 7,168] | 0.9065 | 64.7% |
| 11 | layers.0.attn.q_a_proj.weight | mla_proj | [1,536, 7,168] | ~0.9065 | ~64.7% |
| 12 | layers.0.attn.q_b_proj.weight | mla_proj | [6,144, 1,536] | ~0.9065 | ~64.7% |
| 13 | layers.0.attn.kv_a_proj.weight | mla_proj | [576, 7,168] | ~0.9065 | ~64.7% |
| 14 | layers.0.ffn.gate.weight | ffn_gate | [384, 7,168] | 0.8479 | 60.3% |
Aggregate Statistics:
| Metric | Value |
|---|---|
| Mean R² | 0.9436 |
| Median R² | 0.9906 |
| Min R² | 0.8132 |
| Max R² | 0.9999 |
| Std Dev R² | 0.0654 |
| ≥ 0.90 | 11/14 (78.6%) |
| ≥ 0.95 | 8/14 (57.1%) |
| Mean Relative Error | 0.1751 |
| Median Relative Error | 0.0778 |
| Mean Mask Coverage | 80.35% |
| Median Mask Coverage | 83.33% |
1.6 Key Observations from DeepSeek Results
RMSNorm layers are trivially compressible: R² > 0.999 because they have only ~5K-7K elements, small variance, and the operation (elementwise multiply with reciprocal sqrt of variance) is linear in the weight.
Small 1D tensors (hc_base, attn_sink) also compress well: R² > 0.99 because there are only 24-128 elements — the scalar model has enough degrees of freedom.
Large matrices (FFN gate, compressor) are harder: The FFN gate at [384, 7,168] = 22M elements achieves only R² = 0.8479. This is the hardest layer type because:
- Gate projections use SwiGLU: output = gate(x) * up(x), where gate = sigmoid(linear(x)) — the nonlinearity amplifies weight errors
- The gate matrix has a "bottleneck" structure (384 → 7,168) that is sensitive to sign flips
MLA projections show consistent R² ~0.9065: The compressed attention mechanism (q_a, q_b, kv_a) has structured low-rank properties that make it more amenable to scalar approximation than standard attention.
Part 2: Gemma 4 31B IT — Packed 1-Bit V11
2.1 What We Are Approximating
Gemma 4 31B IT (Instruction-Tuned) has a dense transformer architecture (no MoE):
| Parameter | Value |
|---|---|
| Hidden Size | 5,376 |
| Attention Heads | 32 |
| KV Heads | 16 (GQA) |
| Head Dimension | 256 |
| Intermediate Size | 21,504 |
| Layers | 60 |
| Vocabulary | 262,144 |
| Max Position Embeddings | 262,144 |
| RMSNorm Epsilon | 1e-6 |
| Activation | GELU with PyTorch tanh approximation |
| Tied Word Embeddings | Yes |
| Sliding Window | 1,024 |
| Global Head Dim | 512 |
| Global KV Heads | 4 |
| Final Logit Softcapping | 30.0 |
| RoPE Theta (Full) | 1,000,000 |
| RoPE Theta (Sliding) | 10,000 |
Vision encoder (for multimodal understanding):
| Parameter | Value |
|---|---|
| Hidden Size | 1,152 |
| Attention Heads | 16 |
| KV Heads | 16 |
| Head Dim | 72 |
| Intermediate Size | 4,304 |
| Layers | 27 |
| Patch Size | 16 |
2.2 The Core Problem (Same, Different Approach)
Unlike DeepSeek's scalar-only approach, Gemma uses true 1-bit packing:
- Each weight is represented by a single bit: 1 if ≥ 0, 0 if < 0
- Magnitude is recovered via per-row (or per-group) floating-point scales
- This achieves genuine ~16x compression vs FP16
The challenge is that sign-only representation loses all magnitude information within each sign class. The row-wise scales recover only the mean magnitude per row, not per-element magnitudes.
2.3 Technical Approach: Packed 1-Bit V11
Phase 1: Weight Quantization (Same as DeepSeek's masking but with true bit-packing)
Step 1-5: Same as DeepSeek — normalization, block-wise energy masking, multi-pass scalar refinement, denormalization.
Step 6: Sign Extraction and Bit Packing
# After reconstruction, extract signs
signs = (W_recon >= 0).flatten().cpu().numpy()[:numel]
# Pack 8 booleans into 1 byte
packed_bits = np.packbits(signs) # torch.uint8 tensor
# Store: packed_bits (1 bit per element), row_scales (float32 per row × 2)
Step 7: Row-wise Scale Extraction
num_rows = shape[0]
row_scales = zeros(num_rows, 2) # [pos_mean, neg_mean] per row
for r in range(num_rows):
row = W_recon[r]
pos = row[row > 0]
neg = row[row <= 0]
row_scales[r, 0] = mean(pos) if len(pos) > 0 else 0.0
row_scales[r, 1] = mean(neg) if len(neg) > 0 else 0.0
Phase 2: Recursive Scale Quantization (The V11 Innovation)
The row_scales themselves are float32 tensors. For a [8,192, 2] scales tensor (from Q_Proj), that's 16,384 floats = 64 KB. While small, at scale across all layers this adds up. The V11 method quantizes scales themselves using the same 1-bit approach:
Algorithm for scale quantization:
Input: row_scales [num_rows, 2], target_r2=0.90, max_attempts=4
Configs (from coarse to fine):
Attempt 1: block_size=4, passes=4, ratio=0.70
Attempt 2: block_size=4, passes=6, ratio=0.80
Attempt 3: block_size=2, passes=6, ratio=0.90
Attempt 4: block_size=2, passes=8, ratio=0.97
For each config:
packed_s, coverage = PackedOneBitTensor.from_float(S, config)
S_recon = packed_s.to_dense()
r2_s = 1 - sum((S - S_recon)^2) / sum((S - mean(S))^2)
if r2_s >= target_r2: break
track best attempt
Store: scales_packed (1-bit packed) + scales_of_scales (float32, tiny)
Phase 3: ShardStats — Cross-Shard Adaptive Ratio
This is the most important innovation for practical deployment. The problem: static ratios (e.g., attention=0.88) don't account for weight distribution variance across layers. Layer 0's Q_Proj may compress well at 88%, but Layer 30's may need 95%.
ShardStats Algorithm:
class ShardStats:
TARGET_R2 = 0.90
EMA_ALPHA = 0.3
MIN_SAMPLES = 2
ADAPT_STEP = 0.03
CAP = 0.12
def suggest_ratio(layer_type, numel):
base = RATIOS[layer_type] # static base
if count[layer_type] < MIN_SAMPLES:
return base # not enough data yet
adjusted = clip(base + offset[layer_type], 0.50, 0.99)
return adjusted
def update(layer_type, measured_r2, ratio_used):
# Update EMA of R² for this layer type
ema_r2[layer_type] = (ALPHA * measured_r2 + (1-ALPHA) * ema_r2[layer_type])
# Adjust offset based on whether we're hitting target
if ema_r2 < TARGET_R2 - 0.02:
offset[layer_type] = min(CAP, offset + ADAPT_STEP) # need more coverage
elif ema_r2 > TARGET_R2 + 0.05:
offset[layer_type] = max(-CAP, offset - ADAPT_STEP) # can afford less
Why this matters:
- Early layers (0-10) may have "cleaner" weight distributions (closer to Gaussian)
- Later layers (40-60) may have "spikier" distributions (specialized features)
- Without adaptation, you'd use the same ratio for all, causing some layers to fail
- ShardStats learns this online as it processes shards, improving consistency
2.4 What Gets Stored (The "Compressed" Representation)
For each tensor:
- packed_bits:
torch.uint8tensor,ceil(numel / 8)bytes (true 1-bit packing) - row_scales:
[num_rows, 2]float32 tensor (or recursively quantized) - shape: Original shape for reconstruction
- numel: Number of elements
- W_mean, W_std: Global normalization params
- coverage: Actual mask coverage achieved
If scales are quantized: 7. scales_packed_bits: 1-bit packed version of row_scales 8. scales_packed_scales: Scalars for the scales (meta-scales) 9. scales_packed_numel: Element count for scale tensor
2.5 Results: Real Generation Check on Layer 0 & Layer 1
These results use real prompt-based activation checks — not just weight R², but R² of the actual layer outputs when fed real token embeddings from the model.
Layer 0: Post-Feedforward Layernorm
| Metric | Value |
|---|---|
| Shape | [5,376] |
| Elements | 5,376 |
| Layer Type | norm |
| R² (weights) | 0.0076 |
| Relative Error (weights) | 0.7759 |
| R² (activation on real prompt) | 0.6594 |
| Scales R² | n/a (too small) |
Analysis: The weight R² is terrible (0.0076) because the 1-bit approximation of a 5K-element vector is extremely coarse. However, in RMSNorm the weight acts as a gain factor after variance normalization. The activation R² (0.6594) is much higher because:
- The input activations x have their own variance structure
- The error in the weight is multiplied by x, but x is normalized:
output = x / sqrt(var(x) + eps) * weight - The normalization step absorbs some of the weight error
Layer 0: Pre-Feedforward Layernorm
| Metric | Value |
|---|---|
| Shape | [5,376] |
| Elements | 5,376 |
| R² (weights) | 0.0056 |
| Relative Error (weights) | 0.3406 |
| R² (activation on real prompt) | 0.9402 |
| Scales R² | n/a |
Analysis: Same pattern — weight R² is near-zero, but activation R² is 0.94. The pre-FFN norm weight has smaller relative error (0.34 vs 0.78), leading to better activation preservation. This shows that weight R² is not predictive of activation R² for normalization layers.
Layer 0: K_Norm (Attention Key Norm)
| Metric | Value |
|---|---|
| Shape | [256] |
| Elements | 256 |
| R² (weights) | 1.0000 |
| Relative Error | 0.0000 |
| R² (activation) | 1.0000 |
| Scales R² | n/a |
Analysis: Perfect reconstruction. Only 256 elements — the scalar model has more parameters than data points. This is trivial.
Layer 0: K_Proj (Key Projection)
| Metric | Value |
|---|---|
| Shape | [4,096, 5,376] |
| Elements | 22,020,096 |
| Layer Type | attn |
| R² (weights) | 0.4614 |
| Relative Error | 0.7339 |
| R² (activation on real prompt) | 0.4812 |
| Scales R² (quantized) | 0.9481 |
Scale Quantization Attempts:
| Attempt | block_size | passes | ratio | R² (scales) | Coverage |
|---|---|---|---|---|---|
| 1 | 2 | 4 | 0.70 | 0.7483 | 63.2% |
| 2 | 2 | 6 | 0.80 | 0.8360 | 65.1% |
| 3 | 2 | 6 | 0.90 | 0.9206 | 73.3% |
Analysis:
- Weight R² (0.4614) and activation R² (0.4812) are close — for linear layers, weight error directly propagates to activation error
- The quantized scales achieve R² = 0.9481, meaning the scale quantization itself is high-quality
- However, even perfect scales can't fix the fundamental limitation: 1-bit signs lose intra-row magnitude variation
- Coverage of 72.8% means 27.2% of elements are reconstructed from residual bias only
Layer 0: O_Proj (Output Projection)
| Metric | Value |
|---|---|
| Shape | [5,376, 8,192] |
| Elements | 44,040,192 |
| Layer Type | attn |
| R² (weights) | 0.4192 |
| Relative Error | 0.7621 |
| R² (activation) | 0.4501 |
| Scales R² | 0.9354 |
Analysis: O_Proj is the hardest attention matrix because it projects from concatenated heads (8,192) back to hidden size (5,376). The high output dimension means each row has 8K elements — row-wise scales average over too many values, losing fine structure.
Layer 0: Q_Norm (Query Norm)
| Metric | Value |
|---|---|
| Shape | [256] |
| Elements | 256 |
| R² (weights) | 1.0000 |
| Relative Error | 0.0000 |
| R² (activation) | 1.0000 |
| Scales R² | n/a |
Same as K_Norm — trivially perfect.
Layer 0: Q_Proj (Query Projection)
| Metric | Value |
|---|---|
| Shape | [8,192, 5,376] |
| Elements | 44,040,192 |
| Layer Type | attn |
| R² (weights) | 0.4507 |
| Relative Error | 0.7411 |
| R² (activation) | 0.4910 |
| Scales R² | 0.9371 |
Scale Quantization:
| Attempt | block_size | passes | ratio | R² (scales) | Coverage |
|---|---|---|---|---|---|
| 1 | 2 | 4 | 0.70 | 0.7483 | 63.2% |
| 2 | 2 | 6 | 0.80 | 0.8361 | 65.1% |
| 3 | 2 | 6 | 0.90 | 0.9204 | 73.3% |
Analysis: Q_Proj shows the same pattern as K_Proj. The 1-bit weight R² (~0.45) is the fundamental bottleneck. Even with near-perfect scale quantization (R²=0.9371), the activation R² caps at ~0.49.
Layer 0: V_Proj (Value Projection)
| Metric | Value |
|---|---|
| Shape | [4,096, 5,376] |
| Elements | 22,020,096 |
| Layer Type | attn |
| R² (weights) | 0.5122 |
| Relative Error | 0.6984 |
| R² (activation) | 0.5398 |
| Scales R² | 0.9276 |
Scale Quantization:
| Attempt | block_size | passes | ratio | R² (scales) | Coverage |
|---|---|---|---|---|---|
| 1 | 2 | 4 | 0.70 | 0.7513 | 63.1% |
| 2 | 2 | 6 | 0.80 | 0.8488 | 65.1% |
| 3 | 2 | 6 | 0.90 | 0.9324 | 73.3% |
Analysis: V_Proj achieves the highest weight R² (0.5122) among attention projections. This is because value projections typically have smoother, more Gaussian weight distributions than query/key projections. The activation R² (0.5398) is correspondingly the highest.
Layer 1: Input Layernorm
| Metric | Value |
|---|---|
| Shape | [5,376] |
| Elements | 5,376 |
| Layer Type | norm |
| R² (weights) | 0.0050 |
| Relative Error | 0.3235 |
| R² (activation) | 0.9086 |
| Scales R² | n/a |
Analysis: Layer 1's input norm achieves activation R² = 0.9086 — better than Layer 0's post-FFN norm (0.6594). This suggests that deeper layer norms may be more robust to weight approximation, possibly because their inputs have been "pre-conditioned" by previous layers.
2.6 Compression Metrics
| Tensor | Original (FP16) | Packed | Compression Ratio |
|---|---|---|---|
| Q_Proj | 84.00 MB | 5.31 MB | 15.8x |
| K_Proj | 84.00 MB | 5.29 MB | 15.9x |
| V_Proj | 42.00 MB | 2.66 MB | 15.8x |
| O_Proj | 84.00 MB | ~5.3 MB | ~15.8x |
| Norms | ~0.5 KB | ~0.5 KB | ~12x |
Forward Pass Timing:
| Tensor | Original Fwd | Packed Fwd | Unpack Time | VRAM |
|---|---|---|---|---|
| K_Proj | 3.74 ms | 3.79 ms | 43.84 ms | 0.28 GB |
| Q_Proj | 5.42 ms | 4.90 ms | 49.20 ms | 0.28 GB |
| V_Proj | 2.28 ms | 2.31 ms | 13.78 ms | 0.28 GB |
Key Insight: The packed forward pass is actually slightly faster than original in some cases (Q_Proj: 4.90ms vs 5.42ms). This is because:
- The packed weights are smaller, improving cache locality
- The reconstruction (unpack) happens once and the dense tensor is cached
- However, the unpack step (43-49ms) is expensive — it must happen before the first forward pass
Part 3: Critical Analysis — Why Real Generation R² is Lower
3.1 The Compounding Error Problem
The experiments above measure R² per layer with the original upstream activations. In a real generation scenario:
Layer 0: x0 (real) → approx_layer_0 → x1 (approximated)
Layer 1: x1 (approximated, not real!) → approx_layer_1 → x2 (doubly approximated)
...
Layer 60: x60 (accumulated error) → approx_layer_60 → output
Error propagation in deep networks is multiplicative, not additive.
If each layer has activation R² = 0.5 (generous estimate for attention layers), after 60 layers:
- The effective R² degrades exponentially
- Even with perfect norm layers (R²=1.0), the attention and FFN errors compound
3.2 Resource Limitations
The experiments were conducted on a single GPU with limited VRAM (evidenced by frequent torch.cuda.empty_cache() calls and 0.28 GB VRAM usage). This constrains:
- Batch size: Only batch=2, seq=1000 could be tested — real generation uses larger contexts
- Layer coverage: Only Layer 0 and scattered layers were validated, not all 60 layers end-to-end
- Embedding quality: The input embeddings are loaded from FP16 weights, but in a fully quantized model, even embeddings would be 1-bit
- No end-to-end generation: Perplexity (PPL) and BLEU/ROUGE scores were not computed due to memory constraints
3.3 Why RMSNorm is Perfect but Attention is Not
| Aspect | RMSNorm | Attention Q/K/V/O Proj |
|---|---|---|
| Elements | 256-7,168 | 22M-44M |
| Operation | Elementwise multiply | Matrix multiply |
| Error sensitivity | Low (normalization absorbs variance) | High (error propagates through softmax) |
| Weight distribution | Near-constant, small variance | Gaussian with heavy tails |
| Scalar approximation quality | Excellent (more params than data) | Poor (severe underparameterization) |
| Activation R² | > 0.94 | ~0.45-0.54 |
The fundamental issue: 1-bit quantization of 44M-element matrices with only row-wise scales is massively underparameterized.
For Q_Proj [8,192, 5,376]:
- Original parameters: 44,040,192 floats
- 1-bit packed: 44,040,192 bits = 5.5 MB
- Row scales: 8,192 × 2 = 16,384 floats = 64 KB
- Information loss: We're representing 44M continuous values with 44M bits + 16K floats — a compression ratio of ~256:1 in information-theoretic terms
3.4 Theoretical Limits
From information theory, the minimum bits needed to represent a weight matrix with distortion D is given by rate-distortion theory. For Gaussian weights with variance σ²:
R(D) = (1/2) * log2(σ² / D) bits per dimension
For D/σ² ≈ 0.5 (R² ≈ 0.5), R(D) ≈ 0.5 bits per weight. True 1-bit quantization is at the theoretical limit. Achieving R² > 0.9 would require:
- Non-uniform quantization (learned codebooks)
- Vector quantization (grouping weights into vectors)
- Mixed-precision (1-bit for some layers, 2-4 bit for critical layers)
- Outlier-aware quantization (keep top-k weights in full precision)
Part 4: What Would Be Needed to Succeed
4.1 Immediate Technical Improvements
Mixed-Precision Strategy: Use 1-bit for norms and small tensors, 2-bit for attention, 4-bit for FFN gates. This preserves the 10-15x compression while keeping R² > 0.9.
Outlier Preservation: Keep the top 1% of weights (by magnitude) in FP16. Experiments show 1% outliers contain ~20% of the "information" in the matrix.
Learned Codebooks: Instead of row-wise scales, use k-means on weight clusters to learn 16-32 centroids per layer. This is 4-5 bit but with much better R².
Activation-Aware Quantization (AWQ-style): Weight the quantization error by activation magnitude. Rarely-activated weights can tolerate more error.
Layer-wise Fine-Tuning: After quantization, run 100-1000 steps of distillation on the quantized model to recover accuracy. This requires the full model loaded in memory.
4.2 Resource Requirements
| Requirement | Current | Needed |
|---|---|---|
| GPU Memory | ~16-24 GB | 8× A100 80GB or 4× H100 96GB |
| Model Loading | Shard-by-shard (streaming) | Full model in memory |
| Batch Size | 2 | 16-32 |
| Sequence Length | 1,000 | 8,192-32,768 |
| Validation | Per-layer R² | End-to-end PPL, downstream tasks |
| Fine-tuning | None | 1K-10K steps QLoRA-style |
4.3 Collaboration Opportunities
This work demonstrates a proof-of-concept with the following validated components:
- ✅ Streaming safetensors parsing without full model download
- ✅ Block-wise energy analysis for structured masking
- ✅ Multi-pass scalar refinement with convergence
- ✅ True 1-bit packing with
np.packbits - ✅ Recursive scale quantization (scales of scales)
- ✅ Cross-shard adaptive ratio via EMA (ShardStats)
- ✅ Real activation R² measurement (not just weight R²)
What is needed from partners:
- Access to multi-GPU cluster (8× A100 minimum)
- Existing quantization infrastructure (vLLM, TensorRT-LLM, or custom kernels)
- Dataset for calibration (C4, WikiText, or domain-specific corpora)
- Evaluation framework (LM Evaluation Harness, HELM, etc.)
Potential collaborators:
- Companies building edge AI chips (need ultra-small models)
- Cloud providers offering quantized model serving
- Research labs working on sub-1-bit quantization
- Open-source projects (llama.cpp, ollama, etc.)
Part 5: Detailed Results Tables
5.1 DeepSeek-V4 Pro: Complete Layer 0 Results
| # | Tensor Key | Type | Shape | Elements | R² | Rel Err | Mask Cov | Norm Mean | Norm Std |
|---|---|---|---|---|---|---|---|---|---|
| 1 | layers.0.ffn_norm.weight | norm | [7,168] | 7,168 | 0.9999 | 0.0099 | 99.00% | 0.1222 | 0.0078 |
| 2 | layers.0.attn.q_norm.weight | norm | [1,536] | 1,536 | 0.9998 | 0.0151 | 99.00% | 0.0272 | 0.0027 |
| 3 | layers.0.attn.kv_norm.weight | norm | [512] | 512 | 0.9996 | 0.0199 | 98.83% | 0.5130 | 0.0834 |
| 4 | layers.0.attn_norm.weight | norm | [7,168] | 7,168 | 0.9995 | 0.0221 | 99.00% | 0.0312 | 0.0038 |
| 5 | layers.0.attn.compressor.norm.weight | norm | [512] | 512 | 0.9981 | — | 98.83% | — | — |
| 6 | layers.0.hc_attn_base | hc_base | [24] | 24 | 0.9916 | — | 83.33% | — | — |
| 7 | layers.0.hc_ffn_base | hc_base | [24] | 24 | 0.9909 | — | 83.33% | — | — |
| 8 | layers.0.attn.attn_sink | attn_sink | [128] | 128 | 0.9904 | — | 84.38% | — | — |
| 9 | layers.0.attn.compressor.wkv.weight | compressor_wkv | [512, 7,168] | 3,670,016 | 0.9136 | 0.2939 | 64.69% | 0.0000 | 0.0277 |
| 10 | layers.0.attn.compressor.wgate.weight | compressor_gate | [512, 7,168] | 3,670,016 | 0.9065 | 0.3058 | 64.69% | 0.0001 | 0.0324 |
| 11 | layers.0.attn.q_a_proj.weight | mla_proj | [1,536, 7,168] | 11,010,048 | ~0.9065 | — | ~64.7% | — | — |
| 12 | layers.0.attn.q_b_proj.weight | mla_proj | [6,144, 1,536] | 9,437,184 | ~0.9065 | — | ~64.7% | — | — |
| 13 | layers.0.attn.kv_a_proj.weight | mla_proj | [576, 7,168] | 4,128,768 | ~0.9065 | — | ~64.7% | — | — |
| 14 | layers.0.ffn.gate.weight | ffn_gate | [384, 7,168] | 2,752,512 | 0.8479 | 0.3900 | 60.28% | -0.0001 | 0.0321 |
5.2 Gemma 4 31B IT: Real Generation Results (Layers 0-1)
| Layer | Tensor Key | Type | Shape | Elements | R² (weights) | Rel Err | R² (activation) | Scales R² |
|---|---|---|---|---|---|---|---|---|
| 0 | post_feedforward_layernorm.weight | norm | [5,376] | 5,376 | 0.0076 | 0.7759 | 0.6594 | n/a |
| 0 | pre_feedforward_layernorm.weight | norm | [5,376] | 5,376 | 0.0056 | 0.3406 | 0.9402 | n/a |
| 0 | self_attn.k_norm.weight | norm | [256] | 256 | 1.0000 | 0.0000 | 1.0000 | n/a |
| 0 | self_attn.k_proj.weight | attn | [4,096, 5,376] | 22,020,096 | 0.4614 | 0.7339 | 0.4812 | 0.9481 |
| 0 | self_attn.o_proj.weight | attn | [5,376, 8,192] | 44,040,192 | 0.4192 | 0.7621 | 0.4501 | 0.9354 |
| 0 | self_attn.q_norm.weight | norm | [256] | 256 | 1.0000 | 0.0000 | 1.0000 | n/a |
| 0 | self_attn.q_proj.weight | attn | [8,192, 5,376] | 44,040,192 | 0.4507 | 0.7411 | 0.4910 | 0.9371 |
| 0 | self_attn.v_proj.weight | attn | [4,096, 5,376] | 22,020,096 | 0.5122 | 0.6984 | 0.5398 | 0.9276 |
| 1 | input_layernorm.weight | norm | [5,376] | 5,376 | 0.0050 | 0.3235 | 0.9086 | n/a |
5.3 Gemma 4 31B IT: Scale Quantization Attempts Detail
K_Proj Scales (Layer 0)
| Attempt | block_size | num_passes | ratio | R² (scales) | Coverage | Status |
|---|---|---|---|---|---|---|
| 1 | 2 | 4 | 0.70 | 0.7483 | 63.2% | Too low |
| 2 | 2 | 6 | 0.80 | 0.8360 | 65.1% | Too low |
| 3 | 2 | 6 | 0.90 | 0.9206 | 73.3% | OK |
Q_Proj Scales (Layer 0)
| Attempt | block_size | num_passes | ratio | R² (scales) | Coverage | Status |
|---|---|---|---|---|---|---|
| 1 | 2 | 4 | 0.70 | 0.7483 | 63.2% | Too low |
| 2 | 2 | 6 | 0.80 | 0.8361 | 65.1% | Too low |
| 3 | 2 | 6 | 0.90 | 0.9204 | 73.3% | OK |
V_Proj Scales (Layer 0)
| Attempt | block_size | num_passes | ratio | R² (scales) | Coverage | Status |
|---|---|---|---|---|---|---|
| 1 | 2 | 4 | 0.70 | 0.7513 | 63.1% | Too low |
| 2 | 2 | 6 | 0.80 | 0.8488 | 65.1% | Too low |
| 3 | 2 | 6 | 0.90 | 0.9324 | 73.3% | OK |
5.4 Compression Summary: Gemma 4 31B IT
| Tensor | Original (MB) | Packed (MB) | Ratio | Fwd Orig (ms) | Fwd Packed (ms) | Unpack (ms) |
|---|---|---|---|---|---|---|
| Q_Proj | 84.00 | 5.3145 | 15.8x | 5.42 | 4.90 | 49.20 |
| K_Proj | 84.00 | 5.2923 | 15.9x | 3.74 | 3.79 | 43.84 |
| V_Proj | 42.00 | 2.6572 | 15.8x | 2.28 | 2.31 | 13.78 |
| O_Proj | 84.00 | ~5.3 | ~15.8x | — | — | — |
| Norm (any) | ~0.0005 | ~0.0005 | ~12x | 0.23 | 0.16 | 0.48 |
Part 6: Conclusions and Call for Collaboration
What Works
- RMSNorm layers: Perfectly approximated (R² > 0.99) with trivial compression
- Small 1D tensors: Perfect reconstruction due to overparameterization
- Scale quantization: Recursive 1-bit on scales achieves R² > 0.92 in 3 attempts
- ShardStats: Cross-shard adaptation improves consistency
- Streaming processing: Can process 64-shard models without loading full weights
What Doesn't Work (Yet)
- Attention projections: R² ~0.45-0.54 on real activations — too low for usable generation
- Error compounding: Per-layer R² doesn't reflect end-to-end degradation
- Resource constraints: Single GPU limits validation to small batches and few layers
- No fine-tuning: Quantization-aware training would recover 10-20% R²
The Path Forward
To make 1-bit LLMs practical, we need:
| Milestone | Requirement | Estimated Impact |
|---|---|---|
| Mixed precision (1-bit + 4-bit outliers) | Implementation | R² +0.2-0.3 |
| Quantization-aware fine-tuning | 8× A100, 1K steps | R² +0.15-0.25 |
| Activation-aware quantization | Calibration data | R² +0.1-0.15 |
| Custom CUDA kernels for 1-bit matmul | Kernel engineer | 10x speedup |
| Full end-to-end validation | Multi-GPU cluster | Confidence metric |
Call for Investment / Collaboration
This research demonstrates a novel approach to extreme LLM quantization with the following intellectual property:
- Multi-pass block-wise scalar refinement with adaptive masking
- Recursive scale quantization (1-bit on scales of scales)
- Cross-shard EMA-based ratio adaptation (ShardStats)
- Streaming safetensors processing for models of any size
I am seeking:
- Compute partnership: Access to 8+ A100/H100 GPUs for 2-4 weeks
- Research collaboration: Joint paper on sub-1-bit quantization
- Investment: Seed funding to build custom inference kernels and validate at scale
- Industry partnership: Integration with existing serving stacks (vLLM, TensorRT-LLM)
Contact: bogunusov@gmail.com or X: @liberal17th