rnagabh commited on
Commit
8d87601
·
verified ·
1 Parent(s): fc8f1f0

Initial upload: Gemma 4 audio encoder (304.8M USM-style Conformer)

Browse files
README.md ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ - multilingual
5
+ license: apache-2.0
6
+ library_name: transformers
7
+ tags:
8
+ - feature-extraction
9
+ - audio
10
+ - speech
11
+ - conformer
12
+ - gemma4
13
+ - usm
14
+ - google
15
+ pipeline_tag: feature-extraction
16
+ base_model: google/gemma-4-E2B-it
17
+ ---
18
+
19
+ # Gemma 4 Audio Encoder (USM-style Conformer)
20
+
21
+ Standalone extraction of the audio encoder from Google's [Gemma 4](https://huggingface.co/google/gemma-4-E2B-it) multimodal model family. This is a 304.8M parameter USM-style Conformer that converts audio waveforms (via 128-bin mel spectrogram) into embeddings.
22
+
23
+ **License:** Apache 2.0 (inherited from Gemma 4 — no restrictions)
24
+
25
+ ## Architecture
26
+
27
+ | Property | Value |
28
+ |---|---|
29
+ | Total parameters | 304.8M |
30
+ | Architecture | USM-style Conformer (Macaron-net) |
31
+ | Hidden dimension | 1024 |
32
+ | Output dimension | 1536 (via `output_proj` Linear + bias) |
33
+ | Conformer layers | 12 |
34
+ | Attention heads | 8 (128 dim per head) |
35
+ | FFW intermediate | 4096 (4× expansion) |
36
+ | Depthwise conv kernel | 5 |
37
+ | Subsampling conv channels | [128, 32] |
38
+ | Input | 128-bin mel spectrogram @ 16kHz |
39
+ | Conformer activation | SiLU |
40
+ | Subsampling activation | ReLU |
41
+ | Conformer normalization | RMSNorm (eps=1e-6) |
42
+ | Subsampling normalization | LayerNorm |
43
+ | Residual weight | 0.5 (Macaron half-step) |
44
+ | Attention type | Chunked causal (chunk_size=12, left_context=13, right_context=0) |
45
+ | Clipped linears | Yes (quantization-ready input_min/max, output_min/max per layer) |
46
+ | Temporal downsampling | 4× (two stride-2 Conv2d layers) |
47
+
48
+ ### Conformer Block Structure
49
+
50
+ Each of the 12 conformer blocks follows the Macaron-net pattern:
51
+
52
+ ```
53
+ Input
54
+ → FFW1: pre_layer_norm → Linear(1024→4096) → SiLU → Linear(4096→1024) → post_layer_norm
55
+ → + 0.5 × residual
56
+ → Self-Attention: norm_pre_attn → Q/K/V proj (1024→1024) → relative position → post proj → norm_post_attn
57
+ → + residual
58
+ → LightConv1d: pre_layer_norm → Linear(1024→2048, gated) → DepthwiseConv1d(k=5) → conv_norm → Linear(1024→1024)
59
+ → + residual
60
+ → FFW2: pre_layer_norm → Linear(1024→4096) → SiLU → Linear(4096→1024) → post_layer_norm
61
+ → + 0.5 × residual
62
+ → norm_out
63
+ ```
64
+
65
+ ### Input/Output Shapes
66
+
67
+ - **Input:** `(batch, time_frames, 128)` — 128-bin mel features, time-first
68
+ - **Output:** `(batch, time_frames/4, 1536)` — 4× temporal downsampling, projected to 1536
69
+ - For 4 seconds of 16kHz audio: input ~(1, 399, 128) → output ~(1, 100, 1536)
70
+
71
+ ## Usage
72
+
73
+ ```python
74
+ import torch
75
+ import numpy as np
76
+ from safetensors.torch import load_file
77
+ from transformers import Gemma4AudioModel, Gemma4AudioConfig, AutoProcessor
78
+
79
+ # Load config and weights
80
+ audio_cfg = Gemma4AudioConfig.from_pretrained("rnagabh/gemma4-audio-encoder")
81
+ audio_tower = Gemma4AudioModel(audio_cfg)
82
+
83
+ state_dict = load_file("path/to/model.safetensors") # or use from_pretrained
84
+ audio_tower.load_state_dict(state_dict)
85
+ audio_tower = audio_tower.to(dtype=torch.bfloat16, device="cuda")
86
+ audio_tower.eval()
87
+
88
+ # Use feature extractor from the parent model
89
+ processor = AutoProcessor.from_pretrained("google/gemma-4-E2B-it")
90
+ feature_extractor = processor.feature_extractor
91
+
92
+ import numpy as np
93
+ waveform = np.random.randn(64000).astype(np.float32) # 4s @ 16kHz
94
+ inputs = feature_extractor([waveform], sampling_rate=16000, return_tensors="pt")
95
+
96
+ with torch.no_grad():
97
+ output = audio_tower(inputs["input_features"].to(dtype=torch.bfloat16, device="cuda"))
98
+ embeddings = output.last_hidden_state # (1, 100, 1536)
99
+ ```
100
+
101
+ ## Critical: The AutoModel Loading Gotcha
102
+
103
+ ⚠️ **`AutoModel.from_pretrained("google/gemma-4-E2B-it")` silently fails to load audio tower weights.**
104
+
105
+ All audio tower parameters initialize as random (std ≈ 0.02). The model runs without errors, produces outputs of the correct shape, but the outputs are meaningless.
106
+
107
+ **Root cause:** The checkpoint stores keys with a `model.` prefix (e.g., `model.audio_tower.layers.0...`). `AutoModel` builds the module tree expecting keys without the prefix. The mismatch causes every key to be both UNEXPECTED and MISSING. Transformers loads with `strict=False` by default, so this silently initializes everything fresh.
108
+
109
+ **Fix:** Use `AutoModelForMultimodalLM` instead:
110
+
111
+ ```python
112
+ # ❌ WRONG — audio tower weights are randomly initialized
113
+ model = AutoModel.from_pretrained("google/gemma-4-E2B-it")
114
+ audio_tower = model.audio_tower # RANDOM WEIGHTS
115
+
116
+ # ✅ CORRECT — audio tower weights load properly
117
+ model = AutoModelForMultimodalLM.from_pretrained("google/gemma-4-E2B-it")
118
+ audio_tower = model.model.audio_tower # TRAINED WEIGHTS
119
+ ```
120
+
121
+ **How to verify:**
122
+
123
+ ```python
124
+ w = audio_tower.output_proj.weight.float()
125
+ print(f"std={w.std().item():.6f}")
126
+ # ✅ Trained: std ≈ 0.031250
127
+ # ❌ Random: std ≈ 0.019884
128
+ ```
129
+
130
+ ## E2B and E4B Share Identical Audio Weights
131
+
132
+ The audio encoder weights are **byte-for-byte identical** between Gemma 4 E2B and E4B. This was verified empirically — all 751 parameter tensors match exactly.
133
+
134
+ Gemma 4's E2B is a MatFormer sub-model nested inside E4B. The MatFormer architecture only affects the text decoder's feed-forward dimensions. The audio tower sits outside the MatFormer nesting and is a shared module.
135
+
136
+ **Implication:** There is no reason to prefer E4B over E2B for audio encoder extraction. E2B is a smaller download (~10GB vs ~16GB).
137
+
138
+ ## Files in This Repo
139
+
140
+ | File | Description | Size |
141
+ |---|---|---|
142
+ | `config.json` | Audio tower config (Gemma4AudioConfig) | <1 KB |
143
+ | `model.safetensors` | Audio tower weights (304.8M params, BF16) | 609.7 MB |
144
+ | `preprocessor_config.json` | Mel spectrogram feature extractor config | <1 KB |
145
+ | `embed_audio.safetensors` | Audio→text embedding projection (1536→1536) | 4.7 MB |
146
+
147
+ ## Limitations
148
+
149
+ - **End-to-end trained for LLM decoding:** The encoder was trained to produce features for Gemma 4's text decoder, not as a general-purpose audio encoder. For standalone feature extraction, the 1024-dim pre-projection output (before `output_proj`) may be more useful than the 1536-dim post-projection output.
150
+ - **Causal chunked attention:** The encoder uses right_context=0, meaning it cannot look ahead. This limits its use in offline/non-streaming settings compared to bidirectional encoders.
151
+ - **Multi-layer fusion doesn't help:** Unlike wav2vec2/W2v-BERT where combining multiple hidden layers improves downstream performance, this encoder's Macaron half-step residuals and causal attention mean only the final layer output is useful.
152
+ - **Subsampling frontend uses ReLU + LayerNorm** (not SiLU + GroupNorm as in some USM descriptions).
153
+
154
+ ## Extraction Details
155
+
156
+ - Extracted from `google/gemma-4-E2B-it` using `AutoModelForMultimodalLM`
157
+ - Weights saved in BF16 as safetensors
158
+ - Forward pass verified: extracted model produces outputs with **0.0 max absolute difference** from the original
159
+ - All architecture specs independently verified against the live model
160
+
161
+ ## References
162
+
163
+ - [Gemma 4 on HuggingFace](https://huggingface.co/google/gemma-4-E2B-it)
164
+ - [Gemma 4 Blog Post](https://huggingface.co/blog/gemma4)
165
+ - [Google USM Paper](https://arxiv.org/abs/2303.01037) — "Google USM: Scaling Automatic Speech Recognition Beyond 100 Languages"
config.json ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "transformers_version": "5.5.0",
3
+ "architectures": [
4
+ "Gemma4AudioModel"
5
+ ],
6
+ "output_hidden_states": false,
7
+ "return_dict": true,
8
+ "dtype": "bfloat16",
9
+ "chunk_size_feed_forward": 0,
10
+ "is_encoder_decoder": false,
11
+ "id2label": {
12
+ "0": "LABEL_0",
13
+ "1": "LABEL_1"
14
+ },
15
+ "label2id": {
16
+ "LABEL_0": 0,
17
+ "LABEL_1": 1
18
+ },
19
+ "problem_type": null,
20
+ "hidden_size": 1024,
21
+ "num_hidden_layers": 12,
22
+ "num_attention_heads": 8,
23
+ "hidden_act": "silu",
24
+ "subsampling_conv_channels": [
25
+ 128,
26
+ 32
27
+ ],
28
+ "conv_kernel_size": 5,
29
+ "residual_weight": 0.5,
30
+ "attention_chunk_size": 12,
31
+ "attention_context_left": 13,
32
+ "attention_context_right": 0,
33
+ "attention_logit_cap": 50.0,
34
+ "attention_invalid_logits_value": -1000000000.0,
35
+ "use_clipped_linears": true,
36
+ "rms_norm_eps": 1e-06,
37
+ "gradient_clipping": 10000000000.0,
38
+ "output_proj_dims": 1536,
39
+ "initializer_range": 0.02,
40
+ "_name_or_path": "",
41
+ "model_type": "gemma4_audio",
42
+ "output_attentions": false,
43
+ "torch_dtype": "bfloat16",
44
+ "_verified_total_params": 304824608,
45
+ "_verified_hidden_dim": 1024,
46
+ "_verified_output_dim": 1536,
47
+ "_verified_num_layers": 12,
48
+ "_verified_num_heads": 8,
49
+ "_verified_head_dim": 128,
50
+ "_verified_ffn_intermediate": 4096,
51
+ "_verified_conv_kernel": 5,
52
+ "_verified_subsampling_channels": [
53
+ 128,
54
+ 32
55
+ ],
56
+ "_verified_subsampling_norm": "LayerNorm",
57
+ "_verified_subsampling_activation": "ReLU",
58
+ "_verified_conformer_activation": "SiLU",
59
+ "_verified_conformer_norm": "RMSNorm",
60
+ "_verified_conformer_norm_eps": 1e-06,
61
+ "_verified_temporal_downsample": 4,
62
+ "_source_model": "google/gemma-4-E2B-it",
63
+ "_extraction_note": "Audio tower weights are identical between E2B and E4B variants"
64
+ }
embed_audio.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:966aa3b0b2a3513c4d4cfcdb0396fb802d291dfe68edc07f7efaa5487ee8f099
3
+ size 4718696
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ecbc8887cb18418036b56b67c6b6ae43f3a75a8d363fb0d63a89307684709988
3
+ size 609732608
preprocessor_config.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "feature_size": 128,
3
+ "sampling_rate": 16000,
4
+ "padding_value": 0.0,
5
+ "padding_side": "right",
6
+ "return_attention_mask": true,
7
+ "feature_extractor_type": "Gemma4AudioFeatureExtractor",
8
+ "fft_length": 512,
9
+ "frame_length": 320,
10
+ "hop_length": 160,
11
+ "min_frequency": 0.0,
12
+ "max_frequency": 8000.0,
13
+ "preemphasis": 0.0,
14
+ "preemphasis_htk_flavor": true,
15
+ "fft_overdrive": false,
16
+ "dither": 0.0,
17
+ "input_scale_factor": 1.0,
18
+ "mel_floor": 0.001,
19
+ "per_bin_mean": null,
20
+ "per_bin_stddev": null
21
+ }