Views
No views yet
| Version | Size | Speed Gain | Reduction |
|---|---|---|---|
| BF16 baseline | ~58 GB | — | — |
| Mixed 8-bit | 40 GB | 33% | 31% |
| Mixed 6-bit | 35 GB | 48% | 40% |
| Mixed 4-bit | 30 GB | 60% | 48% |[sliding_attention, sliding_attention, sliding_attention, sliding_attention, sliding_attention, full_attention] × 10 = 60 layersembed_vision) that maps vision features into language model spacevision_tower.encoder.layers.N.* tensors appear alongside language_model.layers.N.* tensors in the same shard.| Layer | Why Protected |
|---|---|
| Full attention (q_proj, k_proj, v_proj, o_proj, q_norm, k_norm) | Deep reasoning and cross-token attention. 16 layers of full softmax attention are the model's primary reasoning engine. |
| Sliding attention (q_proj, k_proj, v_proj, o_proj, q_norm, k_norm) | Local context tracking across 45 layers. Quantizing these degrades the model's ability to maintain coherent state. |
| Vision tower (all 27 encoder layers, nested in every LM layer) | Image and video comprehension. The nested structure makes this especially fragile — a single misclassified layer corrupts all vision understanding. |
| Embed vision projector | Bridges vision features into language model space. Quantizing this collapses the multimodal interface. |
| Embed tokens | Input embeddings. Quantizing these adds noise at the model's primary interface. |
| Norm layers (input_layernorm, post_attention_layernorm, pre_feedforward_layernorm, post_feedforward_layernorm) | Stability anchors. Gemma 4 uses four norm layers per layer — more than most architectures. |
| Layer scalars | Gemma's layer scaling mechanism. Critical for training stability. |
| Layer | Quantization | Rationale |
|---|---|---|
| MLP (gate_proj, up_proj, down_proj) | 8-bit, 6-bit, or 4-bit | 68% of model mass. GeGLU MLPs are the most quantization-tolerant component in a transformer. All the savings live here. |
nn.quantize() with a class_predicate filter that targets only the three GeGLU projection matrices inside language_model.layers.N.mlp. Everything else passes through untouched.1import mlx.core as mx
2import mlx.nn as nn
3from mlx_vlm.utils import load
4import json, os, gc, argparse
5
6parser = argparse.ArgumentParser()
7parser.add_argument("--bits", type=int, default=8, choices=[8, 6, 4])
8parser.add_argument("--group-size", type=int, default=64)
9args = parser.parse_args()
10
11model_path = "/path/to/gemma-4-31B-it"
12output_path = f"/path/to/gemma-4-31B-it-Mixed-{args.bits}bit"
13
14# Lazy load — no eager evaluation
15model, processor = load(model_path, lazy=True)
16
17def gemma4_mlp_only_filter(path, module=None):
18 """Target ONLY language model MLP projections. Protect everything else."""
19 # Hard shield: vision tower (nested inside every layer)
20 if "vision_tower" in path:
21 return False
22 # Hard shield: vision embedding projector
23 if "embed_vision" in path:
24 return False
25 # Hard shield: embeddings
26 if "embed_tokens" in path:
27 return False
28 # Hard shield: norms and scalars
29 if "layernorm" in path or "layer_scalar" in path or path.endswith(".norm"):
30 return False
31 # Hard shield: attention
32 if "self_attn" in path:
33 return False
34 # Target: MLP inside language_model only
35 if "language_model" not in path or ".mlp." not in path:
36 return False
37 leaf = path.split('.')[-1]
38 return leaf in ("gate_proj", "up_proj", "down_proj")
39
40# Single-pass quantization — only MLP gets touched
41nn.quantize(model, group_size=args.group_size, bits=args.bits,
42 class_predicate=gemma4_mlp_only_filter)
43
44# Save config and processor
45os.makedirs(output_path, exist_ok=True)
46if hasattr(processor, "save_pretrained"):
47 processor.save_pretrained(output_path)
48
49with open(os.path.join(model_path, "config.json")) as f:
50 config = json.load(f)
51config["quantization"] = {
52 "group_size": args.group_size,
53 "bits": args.bits,
54 "type": "mixed",
55 "description": f"Gemma 4 MLP-only {args.bits}-bit. Attention, vision, embeddings, norms remain BF16."
56}
57with open(os.path.join(output_path, "config.json"), "w") as f:
58 json.dump(config, f, indent=4)
59
60# Flatten, destroy model tree, shard to SSD
61flat_weights = dict(flatten_parameters(model.parameters()))
62del model, processor
63gc.collect()
64mx.clear_cache()
65
66# Sequential eval + shard (5 GB chunks)
67current_shard, shard_size, shard_idx = {}, 0, 1
68for name, tensor in flat_weights.items():
69 if not isinstance(tensor, mx.array):
70 continue
71 mx.eval(tensor)
72 current_shard[name] = tensor
73 shard_size += tensor.nbytes
74 if shard_size >= 5 * 1024**3:
75 mx.save_safetensors(
76 f"{output_path}/model-{shard_idx:05d}.safetensors", current_shard)
77 current_shard, shard_size, shard_idx = {}, 0, shard_idx + 1
78 gc.collect(); mx.clear_cache()
79if current_shard:
80 mx.save_safetensors(
81 f"{output_path}/model-{shard_idx:05d}.safetensors", current_shard)mixed_quantize_gemma4.py in the quantization-scripts repository.sanitize_weights or other framework internals. The surgical filter ensures that only language model MLP layers are quantized, and the output format follows MLX's native safetensors conventions exactly.1from mlx_vlm.utils import load
2
3model, processor = load("your-username/gemma-4-31B-it-Mixed-8bit", lazy=True)config.json declares a single "bits" value, but MLX reads per-layer quantization metadata dynamically from the safetensors tensor headers. The actual mixed-precision structure — which layers are quantized and which remain BF16 — lives in the safetensors files, not the config. Tooling that trusts only config.json will be confused; this is expected behavior for native MLX mixed quantization.Model: gemma-4-31B-it (BF16)
Benchmark Accuracy Correct Total Time(s)
------------------------------------------------------
HUMANEVAL 95.1% 156 164 1483.2
MBPP 86.5% 173 200 2043.5
LIVECODEBENCH 74.0% 74 100 5799.9
Model: gemma-4-31B-it-Mixed-8bit
Benchmark Accuracy Correct Total Time(s)
------------------------------------------------------
HUMANEVAL 94.5% 155 164 1103.7
MBPP 86.5% 173 200 1503.3
LIVECODEBENCH 73.0% 73 100 4076.3
Model: gemma-4-31B-it-Mixed-6bit
Benchmark Accuracy Correct Total Time(s)
------------------------------------------------------
HUMANEVAL 93.9% 154 164 1275.1
MBPP 86.5% 173 200 1382.0
LIVECODEBENCH 72.0% 72 100 5259.5
Model: gemma-4-31B-it-Mixed-4bit (M1 Max, 64 GB)
Benchmark Accuracy Correct Total Time(s)
------------------------------------------------------
HUMANEVAL 93.9% 154 164 3423.6
MBPP 86.5% 173 200 3431.3
LIVECODEBENCH 70.0% 70 100 9461.1