Skip to content

convert: fold gemma4 audio projection scaling into the weight reparam - #723

Merged
jakmro merged 2 commits into
mainfrom
gemma4-audio-scale-consolidation
Jun 14, 2026
Merged

jakmro merged 2 commits into
mainfrom
gemma4-audio-scale-consolidation

Conversation

@ncylich

@ncylich ncylich commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

The gemma4 audio soft-token 1/16 scaling was applied at runtime in the transpile graph (_gemma4_compute_native_like_audio_features), while the equivalent vision projection scaling is applied at conversion time via the weight reparameterization. This split meant the same conceptual operation lived in two different stages depending on modality.

This change consolidates both into the conversion-time weight reparam:

  • embed_audio_proj.weights is added to the gemma4 ÷16 set in tensor_io.py.
  • The runtime projected = projected * (1.0 / 16.0) is removed from the audio path in model_adapters.py.

Why this is equivalent

The gemma4 audio embedder projection (embedding_projection) is a bias-free nn.Linear preceded by a scale-less pre-norm, with the post-projection norm removed in gemma4. Because the projection is the last operation and has no bias, scaling its weight by 1/16 is mathematically identical to scaling its output by 1/16. Audio now follows the exact pattern vision already uses.

Verification

Reconverted and retranspiled gemma-4-e2b, then ran E2E:

  • Audio: test.wav transcribes cleanly ("Hello hello hello quickly testing out getting a way file through voice memos").
  • Vision: identifies the monkey image correctly ("Monkey", 93.4% confidence).

ncylich added 2 commits June 14, 2026 12:27
The gemma4 audio soft-token 1/16 scaling lived in the transpile graph
(_gemma4_compute_native_like_audio_features) while the equivalent vision
scaling lived in the conversion-time weight reparam. The audio embedder
projection is a bias-free Linear with no post-projection norm, so scaling
its weight is identical to scaling its output. Add embed_audio_proj to the
gemma4 div set and drop the runtime multiply so all multimodal projection
scaling is applied in one place, matching vision. Verified by E2E: e2b
transcribes test.wav cleanly and identifies the monkey image.

Signed-off-by: Noah Cylich <noahcylich@gmail.com>
gemma4's Gemma4MultimodalEmbedder deletes the hard embedding table, so no
embed_vision_embedding.weights tensor is ever produced. Remove the name from
the gemma4 div set in tensor_io.py and from GEMMA4_DIV_BASENAMES; both were
no-ops. The real vision weight (embed_vision_proj) stays scaled.

Signed-off-by: Noah Cylich <noahcylich@gmail.com>
@jakmro
jakmro merged commit a8f634a into main Jun 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants