Uncensoring Gemma 4 12B with Heretic — Keeping Vision, Audio, and the Encoder-Free Design Intact

Community Article
Published June 4, 2026

Authors: Arjun Reddy, Kesavan Sekar, Mahesh Kumar, Venkatesh Rajendran and Pritam Christpin

Research attribution: osmAPI Research Team Terv Student Research Team

Base model: google/gemma-4-12B-it Released artifacts: osmGemma-4-12B-uncensored (bf16 + 3 MLX quants)


TLDR

We abliterated (refusal-ablated) Google's brand-new Gemma 4 12B — the encoder-free unified multimodal model — using Heretic, dropping refusals from 99/100 to 12/100 on mlabonne/harmful_behaviors at a KL divergence of only 0.053 from the original. Crucially, we kept every vision and audio weight intact through both abliteration and quantization, and shipped a full-precision bf16 checkpoint plus three MLX quants for Apple Silicon. Along the way we fixed a bf16-on-MPS numerical bug in the refusal-direction search, and worked around the fact that the MLX vision tooling does not yet model this architecture's encoder-free image pathway.

Abstract

Gemma 4 12B is the first unified (encoder-free) Gemma: there is no separate SigLIP vision tower or audio encoder. Image patches and audio frames are projected directly into the language model and processed by the shared decoder. That design is wonderful for deployment size — and inconvenient for every tool that assumes a vision tower exists.

This report documents the full pipeline — download → abliterate → quantize → publish — entirely on a single 128 GB M3 Max MacBook Pro, including the platform bugs we had to clear, how we guaranteed the multimodal weights survived, where multi-token prediction (MTP) fits, and the honest limitations of MLX inference for this architecture today.

What makes Gemma 4 12B different

We confirmed the architecture directly from the checkpoint. The model is Gemma4UnifiedForConditionalGeneration (model_type: gemma4_unified), 11.95 B parameters, 48 decoder layers, 256 K context. Its tensor inventory is revealing:

Group Tensors Role
language_model.* 666 the 48-layer decoder (the bulk)
vision_embedder.* 9 patch projection + positional embedding (the entire "vision encoder")
embed_vision, embed_audio 2 project visual / audio soft-tokens into LM space
Total 677

There is no vision_tower.encoder.layers. There is no audio transformer. The vision_config/audio_config carry no num_hidden_layers at all — just patch sizes, soft-token counts, and projection dims. As Google's card puts it, the model brings "native audio and vision understanding… without the need for separate encoders." Preserving "vision and audio" therefore means preserving those 11 small projector tensors and keeping the shared decoder healthy.

Abliteration with Heretic

Heretic performs directional ablation: it finds the residual-stream directions most associated with refusal (from contrasting "harmful" and "harmless" prompt sets) and removes their projection from the weights, while an Optuna/TPE search co-optimizes two objectives — minimize refusals and minimize KL divergence from the original model.

Our run: 100 trials (40 random startup + TPE), 400 + 400 direction prompts (harmless_alpaca / harmful_behaviors), evaluation on harmful_behaviors test[:100], seed 42. Heretic only touches the text decoder's attn.o_proj and mlp.down_proj — it never sees the vision/audio projectors.

The Pareto front we selected (trial #55):

Metric Original Abliterated
Refusals (/100 harmful) 99 12
KL divergence 0.053

An 87.9 % reduction in refusals at a KL well under the 0.5 "capability damage" threshold.

The bf16-on-MPS bug that almost sank it

The optimizer kept reporting KL divergence: nan, which silently emptied the Pareto front. The cause is a nice trap. Gemma masks unused-vocabulary logits to -inf. Heretic computes refusal-vs-baseline KL as kl_div(logprobs, base_logprobs, log_target=True) = Σ exp(base)·(base − trial). At the masked positions, exp(-inf) = 0 and (base − trial) = (-inf) − (-inf) = nan, so the term becomes 0 · nan = nan. Casting to fp32 alone does not help — -inf survives the cast. The fix is to sanitize the logits before log_softmax:

logits = torch.nan_to_num(outputs.scores[0].float(), nan=0.0, posinf=1e4, neginf=-1e4)
logprobs = F.log_softmax(logits, dim=-1)

With finite logits the KL became well-defined (0.002–0.5 across trials) and the search converged.

The Apple Silicon gauntlet

Running a day-old architecture + a fresh tool on Metal surfaced a chain of fixable blockers:

Blocker Fix
kernels 0.15 vs transformers' <0.13 pin (import crash) pin kernels==0.12.3
transformers 5.8 didn't know gemma4_unified upgrade to transformers 5.10.1
Heretic config not found / env-var collision pass datasets as full JSON; use a non-HERETIC_ env prefix
aten::linalg_qr unimplemented on MPS PYTORCH_ENABLE_MPS_FALLBACK=1 (the small SVD runs on CPU)
bf16 KL nan sanitize masked -inf logits (above)
Gemma4UnifiedProcessor import error pip install torchvision (the image processor imports it)

Keeping image and sound

We verified preservation at the tensor level at every stage. The abliterated bf16 checkpoint matched the original's byte count to within 984 bytes — all 677 tensors retained, vision_config/audio_config intact.

Quantization was the harder part. mlx-vlm 0.5.0 ships a gemma4 module, but for this checkpoint it (a) resolves only under a gemma4_unified → gemma4 model-type remap, and (b) does not model the vision_embedder at all — loading rejects its 9 tensors as "unexpected." Rather than drop them (which would silently delete the vision pathway), we used a hybrid:

  1. Let mlx-vlm quantize the text + projection weights (it already keeps multimodal modules at higher precision), loading non-strict so the 9 unmodeled tensors are skipped.
  2. Re-insert the 9 vision_embedder tensors at bf16 into the quantized output, and restore model_type: gemma4_unified + the multimodal configs.

The result is weight-complete: every original tensor is present, the language model is quantized, and the vision patch-embedder is preserved losslessly. The moment mlx-vlm adds the encoder-free vision forward, these quants light up with no re-quantization.

Where MTP fits

Gemma 4 ships its multi-token-prediction / speculative head separately as google/gemma-4-12B-it-assistant (a ~0.4 B draft model) — it is not baked into the 12B weights. So there were no MTP tensors to preserve in-model; an abliterated + quantized draft companion can be published later and loaded alongside for speculative decoding without touching these repos. (Like our Flash Load work, we scope MTP/speculative layers out of this proof.)

Quantization: four artifacts

All four preserve the full multimodal weight set.

Repo Scheme Eff. BPW Size
osmGemma-4-12B-uncensored-bf16 bf16 (full multimodal) 16 ~24 GB
osmGemma-4-12B-uncensored-8bit-mlx 8-bit affine 8.8 ~14 GB
osmGemma-4-12B-uncensored-mxfp4-mlx MXFP4 7.6 ~12 GB
osmGemma-4-12B-uncensored-mixed-4.2bpw-mlx mixed 3/4-bit 4.2 ~6.6 GB

A note on bits-per-weight: the 262 K-token vocabulary embedding (~1 B params, kept high-precision) sets a hard floor on the average bpw — true ~3.7 bpw is not reachable on this model without quantizing the embeddings, which we judged too risky for quality.

Results

The headline, measured identically across the family:

Model Refusals (/100) Rate
google/gemma-4-12B-it 99 99 %
osmGemma-4-12B-uncensored 12 12 %

MLX text generation is verified working (with the chat template + a small load shim); for example the 8-bit quant answers cleanly on an M3 Max. Full multimodal (image + audio + video) runs today via 🤗 transformers on the bf16 checkpoint.

Limitations

  • Vision/audio inference in MLX is pending. The weights are preserved, but mlx-vlm 0.5.0 doesn't yet implement the encoder-free vision patch-embedder forward. Text works now; full multimodal works now only via transformers (bf16).
  • bpw above nominal for the MXFP4 (7.6) and mixed (4.2) builds, per the vocab-embedding floor.
  • Bounded benchmark. Refusal rate measured on 100 prompts; broader red-team coverage and capability benchmarking are future work.
  • MTP/speculative layers are out of scope here.

Live artifacts

Acknowledgements

Thank you to:

Community

Sign up or log in to comment