jandonov commited on
Commit
5c1c55d
·
verified ·
1 Parent(s): 1f70491

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. embedding_gemma2_documentation.md +775 -0
embedding_gemma2_documentation.md ADDED
@@ -0,0 +1,775 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!--Copyright 2026 the HuggingFace Team. All rights reserved.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+
15
+
16
+ ⚠️ Note that this file is in Markdown but contains specific syntax for our doc-builder (similar to MDX) that may not be rendered properly in your Markdown viewer.
17
+
18
+ -->
19
+ *This model was contributed to Hugging Face Transformers on 2026-09-22.*
20
+
21
+
22
+ # EmbeddingGemma2
23
+
24
+ ## Overview
25
+
26
+ EmbeddingGemma 2 is a multimodal embedding model from Google built on the [Gemma 4](./gemma4) architecture. It encodes **text, images, audio, and video**—either individually or combined within the same input—into a shared 768-dimensional dense vector space for cross-modal retrieval, semantic similarity, clustering, and classification.
27
+
28
+ Key features:
29
+
30
+ - **Unified multimodal vector space.** Vision ([`Gemma4VisionModel`]) and audio ([`Gemma4AudioModel`]) towers project into a bidirectional text encoder ([`EmbeddingGemma2TextModel`]) that interleaves full and sliding-window attention with Per-Layer Embeddings (PLE). Any single modality (`text`, `image`, `audio`, `video`) or combination of modalities (`image + text`, `text + audio`, `image + audio`, multiple images, interleaved text and media) maps to a single comparable embedding.
31
+ - **Matryoshka Representation Learning (MRL).** [`EmbeddingGemma2Model`] outputs token representations projected to `embedding_dim` (`768`) via a linear head. Embeddings can be truncated to a smaller prefix (`512`, `256`, or `128`) and re-normalized with minimal quality loss.
32
+ - **Configurable visual & video budgets.** [`EmbeddingGemma2Processor`] lets you tune the soft-token budget per image or frame (`max_soft_tokens` in `{70, 140, 280, 560, 1120}`) and video sampling rate (`fps=1`, `max_frames=32`, `overflow_strategy="uniform"`, `add_timestamps=False` by default).
33
+ - **Selective modality tower loading.** Unused vision or audio towers can be disabled at load time (`vision_config=None`, `audio_config=None`) to reduce memory footprint for text-only or single-modality deployments.
34
+
35
+ You can find all the original EmbeddingGemma checkpoints under the [EmbeddingGemma](https://huggingface.co/collections/google/embeddinggemma) collection. The examples below use the `google/embeddinggemma-2` identifier.
36
+
37
+ ## Usage examples
38
+
39
+ A sentence or multimodal embedding is obtained in two steps: mask-aware mean pooling over the non-padded tokens of `last_hidden_state`, followed by L2 normalization in `float32`. [Sentence Transformers](https://sbert.net) (`>=6.1.0`) performs preprocessing, prompt formatting, mean pooling, and normalization automatically and is the recommended entry point. With [`AutoModel`], use `processor.apply_chat_template` (or `AutoTokenizer` for plain text) and pool `last_hidden_state` directly.
40
+
41
+ ### Text retrieval (`encode_query` / `encode_document`)
42
+
43
+ <hfoptions id="usage">
44
+ <hfoption id="Sentence Transformers">
45
+
46
+ ```bash
47
+ pip install -U sentence-transformers
48
+ ```
49
+
50
+ ```python
51
+ from sentence_transformers import SentenceTransformer
52
+
53
+
54
+ model = SentenceTransformer("google/embeddinggemma-2")
55
+
56
+ queries = ["Which planet is known as the Red Planet?"]
57
+ documents = [
58
+ "Venus is often called Earth's twin because of its similar size and proximity.",
59
+ "Mars, known for its reddish appearance, is often referred to as the Red Planet.",
60
+ ]
61
+
62
+ # encode_query and encode_document apply the "query" and "document" task prompts
63
+ query_embeddings = model.encode_query(queries)
64
+ document_embeddings = model.encode_document(documents)
65
+ print(query_embeddings.shape, document_embeddings.shape)
66
+ # (1, 768) (2, 768)
67
+
68
+ # (1, 2) matrix of cosine similarities
69
+ print(model.similarity(query_embeddings, document_embeddings))
70
+ ```
71
+
72
+ </hfoption>
73
+ <hfoption id="AutoModel">
74
+
75
+ ```python
76
+ import torch
77
+ import torch.nn.functional as F
78
+ from transformers import AutoModel, AutoTokenizer
79
+
80
+
81
+ model = AutoModel.from_pretrained("google/embeddinggemma-2", device_map="auto")
82
+ tokenizer = AutoTokenizer.from_pretrained("google/embeddinggemma-2")
83
+
84
+ # Prepend the task prompt directly to plain text inputs (see Task prompts below)
85
+ sentences = [
86
+ "task: search result | query: Which planet is known as the Red Planet?",
87
+ "title: none | text: Venus is often called Earth's twin because of its similar size and proximity.",
88
+ "title: none | text: Mars, known for its reddish appearance, is often referred to as the Red Planet.",
89
+ ]
90
+ inputs = tokenizer(sentences, padding=True, return_tensors="pt").to(model.device)
91
+
92
+ with torch.no_grad():
93
+ # (batch_size, sequence_length, config.text_config.embedding_dim)
94
+ token_embeddings = model(**inputs).last_hidden_state
95
+
96
+ # Mask-aware mean pooling over non-padded tokens, then L2 normalization in float32
97
+ mask = inputs["attention_mask"].unsqueeze(-1).to(token_embeddings.dtype)
98
+ sentence_embeddings = (token_embeddings * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1e-9)
99
+ sentence_embeddings = F.normalize(sentence_embeddings.float(), p=2, dim=-1)
100
+
101
+ query_embedding, document_embeddings = sentence_embeddings[:1], sentence_embeddings[1:]
102
+ print(query_embedding @ document_embeddings.T)
103
+ ```
104
+
105
+ </hfoption>
106
+ </hfoptions>
107
+
108
+ ### Task prompts
109
+
110
+ The model supports optional task prompts prepended to the input (and included in mean pooling), though prompts are not mandatory and the model also works without them. Because the optimal setup depends on the downstream domain and modality mix, we recommend evaluating both with and without task prompts on your specific task. Sentence Transformers ships the catalog below in `config_sentence_transformers.json`, so pass `prompt_name` (or use `encode_query` / `encode_document`, which map to `query` and `document`); with [`AutoModel`], pass the prompt as a `system` message in `apply_chat_template` (or prepend it to plain text).
111
+
112
+ ```python
113
+ from sentence_transformers import SentenceTransformer
114
+
115
+
116
+ model = SentenceTransformer("google/embeddinggemma-2")
117
+
118
+ embeddings = model.encode("How to train a neural network", prompt_name="Classification")
119
+ ```
120
+
121
+ | `prompt_name` | prompt |
122
+ |---|---|
123
+ | `query`, `Retrieval-query`, `Retrieval`, `Reranking`, `BitextMining`, `SearchQuery` | `task: search result \| query: ` |
124
+ | `document`, `Document`, `Retrieval-document` | `title: none \| text: ` |
125
+ | `Classification`, `MultilabelClassification` | `task: classification \| query: ` |
126
+ | `Clustering` | `task: clustering \| query: ` |
127
+ | `CodeRetrieval`, `InstructionRetrieval` | `task: code retrieval \| query: ` |
128
+ | `FactChecking` | `task: fact checking \| query: ` |
129
+ | `QuestionAnswering` | `task: question answering \| query: ` |
130
+ | `STS`, `SentenceSimilarity`, `PairClassification`, `Summarization` | `task: sentence similarity \| query: ` |
131
+
132
+ ### Matryoshka embeddings
133
+
134
+ The embedding head is trained with Matryoshka Representation Learning, so a 768-dimensional embedding can be sliced to a shorter prefix (`512`, `256`, or `128`) and re-normalized. This shrinks the index and speeds up retrieval while largely preserving ranking quality. Truncate queries and documents to the *same* dimension, and always normalize after slicing — in Sentence Transformers, `truncate_dim` slices the already-normalized output, so the prefix is no longer unit-length.
135
+
136
+ <hfoptions id="matryoshka">
137
+ <hfoption id="Sentence Transformers">
138
+
139
+ ```python
140
+ import torch.nn.functional as F
141
+ from sentence_transformers import SentenceTransformer
142
+
143
+
144
+ # truncate_dim can also be set once at load time: SentenceTransformer(..., truncate_dim=256)
145
+ model = SentenceTransformer("google/embeddinggemma-2")
146
+
147
+ queries = ["Which planet is known as the Red Planet?"]
148
+ documents = [
149
+ "Venus is often called Earth's twin because of its similar size and proximity.",
150
+ "Mars, known for its reddish appearance, is often referred to as the Red Planet.",
151
+ ]
152
+
153
+ query_embeddings = model.encode_query(queries, truncate_dim=256, convert_to_tensor=True)
154
+ document_embeddings = model.encode_document(documents, truncate_dim=256, convert_to_tensor=True)
155
+
156
+ query_embeddings = F.normalize(query_embeddings.float(), p=2, dim=-1)
157
+ document_embeddings = F.normalize(document_embeddings.float(), p=2, dim=-1)
158
+
159
+ # (1, 256) and (2, 256): a 3x smaller index than the full 768 dimensions
160
+ print(query_embeddings.shape, document_embeddings.shape)
161
+
162
+ # the Mars document still ranks first
163
+ print(model.similarity(query_embeddings, document_embeddings))
164
+ ```
165
+
166
+ </hfoption>
167
+ <hfoption id="AutoModel">
168
+
169
+ ```python
170
+ import torch
171
+ import torch.nn.functional as F
172
+ from transformers import AutoModel, AutoTokenizer
173
+
174
+
175
+ model = AutoModel.from_pretrained("google/embeddinggemma-2", device_map="auto")
176
+ tokenizer = AutoTokenizer.from_pretrained("google/embeddinggemma-2")
177
+
178
+ sentences = [
179
+ "task: search result | query: Which planet is known as the Red Planet?",
180
+ "title: none | text: Venus is often called Earth's twin because of its similar size and proximity.",
181
+ "title: none | text: Mars, known for its reddish appearance, is often referred to as the Red Planet.",
182
+ ]
183
+ inputs = tokenizer(sentences, padding=True, return_tensors="pt").to(model.device)
184
+
185
+ with torch.no_grad():
186
+ token_embeddings = model(**inputs).last_hidden_state
187
+
188
+ mask = inputs["attention_mask"].unsqueeze(-1).to(token_embeddings.dtype)
189
+ sentence_embeddings = (token_embeddings * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1e-9)
190
+
191
+ # Slice to the first 256 dimensions, then normalize
192
+ sentence_embeddings = F.normalize(sentence_embeddings[:, :256].float(), p=2, dim=-1)
193
+ print(sentence_embeddings.shape)
194
+ # torch.Size([3, 256])
195
+
196
+ query_embedding, document_embeddings = sentence_embeddings[:1], sentence_embeddings[1:]
197
+
198
+ # the Mars document still ranks first
199
+ print(query_embedding @ document_embeddings.T)
200
+ ```
201
+
202
+ </hfoption>
203
+ </hfoptions>
204
+
205
+ ## Multimodal embeddings
206
+
207
+ Text, images, audio, and video are mapped into the same 768-dimensional vector space, enabling **cross-modal retrieval** (e.g. searching images, audio, or videos with a text query) as well as **composed multimodal retrieval** (combining multiple modalities into a single query or document embedding).
208
+
209
+ In Sentence Transformers, multimodal inputs are passed as dictionaries keyed by `"text"`, `"image"`, `"audio"`, and `"video"` (where each value can be a single item or a list of items). With [`AutoModel`], pass chat-style message lists to `processor.apply_chat_template(..., tokenize=True, return_dict=True, return_tensors="pt")`.
210
+
211
+ ### 1. Single modalities & cross-modal retrieval
212
+
213
+ Each modality (`text`, `image`, `audio`, `video`) can be embedded on its own and compared directly against any other modality via cosine similarity:
214
+
215
+ <hfoptions id="multimodal-single">
216
+ <hfoption id="Sentence Transformers">
217
+
218
+ ```python
219
+ from sentence_transformers import SentenceTransformer
220
+
221
+
222
+ model = SentenceTransformer("google/embeddinggemma-2")
223
+ IMAGE = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
224
+
225
+ # Embed each modality on its own into the shared (768,) space
226
+ candidates = model.encode(
227
+ [
228
+ {"text": "A photo of a cat"},
229
+ {"image": IMAGE},
230
+ {"audio": "path/to/audio.wav"},
231
+ {"video": "path/to/video.mp4"},
232
+ ]
233
+ )
234
+ print(candidates.shape)
235
+ # (4, 768)
236
+
237
+ # Cross-modal retrieval: rank text, image, audio, and video candidates against a text query
238
+ query = model.encode_query(["A fluffy cat outdoors"])
239
+ print(model.similarity(query, candidates))
240
+ # tensor([[...]]) of shape (1, 4)
241
+ ```
242
+
243
+ </hfoption>
244
+ <hfoption id="AutoModel">
245
+
246
+ ```python
247
+ import torch
248
+ import torch.nn.functional as F
249
+ from transformers import AutoModel, AutoProcessor
250
+
251
+
252
+ model = AutoModel.from_pretrained("google/embeddinggemma-2", device_map="auto")
253
+ processor = AutoProcessor.from_pretrained("google/embeddinggemma-2")
254
+
255
+ IMAGE = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
256
+
257
+ conversations = [
258
+ [{"role": "user", "content": [{"type": "text", "text": "A photo of a cat"}]}],
259
+ [{"role": "user", "content": [{"type": "image", "url": IMAGE}]}],
260
+ [{"role": "user", "content": [{"type": "audio", "url": "path/to/audio.wav"}]}],
261
+ [{"role": "user", "content": [{"type": "video", "url": "path/to/video.mp4"}]}],
262
+ ]
263
+
264
+ inputs = processor.apply_chat_template(
265
+ conversations,
266
+ tokenize=True,
267
+ return_dict=True,
268
+ return_tensors="pt",
269
+ ).to(model.device)
270
+
271
+ with torch.no_grad():
272
+ token_embeddings = model(**inputs).last_hidden_state
273
+
274
+ mask = inputs["attention_mask"].unsqueeze(-1).to(token_embeddings.dtype)
275
+ embeddings = (token_embeddings * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1e-9)
276
+ embeddings = F.normalize(embeddings.float(), p=2, dim=-1)
277
+ print(embeddings.shape)
278
+ # torch.Size([4, 768])
279
+ ```
280
+
281
+ </hfoption>
282
+ </hfoptions>
283
+
284
+ ### 2. Composed multimodal embeddings (several modalities in one input)
285
+
286
+ Multiple modalities—or multiple items of the same modality—can be combined into a **single joint embedding**, including purely non-text combinations such as `image + audio`:
287
+
288
+ <hfoptions id="multimodal-composed">
289
+ <hfoption id="Sentence Transformers">
290
+
291
+ ```python
292
+ from sentence_transformers import SentenceTransformer
293
+
294
+
295
+ model = SentenceTransformer("google/embeddinggemma-2")
296
+ IMAGE_1 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
297
+ IMAGE_2 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/coco_sample.png"
298
+
299
+ composed_embeddings = model.encode(
300
+ [
301
+ # text + image
302
+ {"text": "A photo of a cat", "image": IMAGE_1},
303
+ # text + audio
304
+ {"text": "A song", "audio": "path/to/audio.wav"},
305
+ # image + audio (no text required)
306
+ {"image": IMAGE_1, "audio": "path/to/audio.wav"},
307
+ # multiple images + audio + text in one embedding
308
+ {"image": [IMAGE_1, IMAGE_2], "audio": "path/to/audio.wav", "text": "Compare both cats"},
309
+ ]
310
+ )
311
+ print(composed_embeddings.shape)
312
+ # (4, 768)
313
+ ```
314
+
315
+ </hfoption>
316
+ <hfoption id="AutoModel">
317
+
318
+ ```python
319
+ import torch
320
+ import torch.nn.functional as F
321
+ from transformers import AutoModel, AutoProcessor
322
+
323
+
324
+ model = AutoModel.from_pretrained("google/embeddinggemma-2", device_map="auto")
325
+ processor = AutoProcessor.from_pretrained("google/embeddinggemma-2")
326
+
327
+ IMAGE = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
328
+
329
+ conversations = [
330
+ # text + image
331
+ [
332
+ {
333
+ "role": "user",
334
+ "content": [
335
+ {"type": "text", "text": "A photo of a cat"},
336
+ {"type": "image", "url": IMAGE},
337
+ ],
338
+ }
339
+ ],
340
+ # text + audio
341
+ [
342
+ {
343
+ "role": "user",
344
+ "content": [
345
+ {"type": "text", "text": "A song"},
346
+ {"type": "audio", "url": "path/to/audio.wav"},
347
+ ],
348
+ }
349
+ ],
350
+ # image + audio (no text required)
351
+ [
352
+ {
353
+ "role": "user",
354
+ "content": [
355
+ {"type": "image", "url": IMAGE},
356
+ {"type": "audio", "url": "path/to/audio.wav"},
357
+ ],
358
+ }
359
+ ],
360
+ ]
361
+
362
+ inputs = processor.apply_chat_template(
363
+ conversations,
364
+ tokenize=True,
365
+ return_dict=True,
366
+ return_tensors="pt",
367
+ ).to(model.device)
368
+
369
+ with torch.no_grad():
370
+ token_embeddings = model(**inputs).last_hidden_state
371
+
372
+ mask = inputs["attention_mask"].unsqueeze(-1).to(token_embeddings.dtype)
373
+ embeddings = (token_embeddings * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1e-9)
374
+ embeddings = F.normalize(embeddings.float(), p=2, dim=-1)
375
+ print(embeddings.shape)
376
+ # torch.Size([3, 768])
377
+ ```
378
+
379
+ </hfoption>
380
+ </hfoptions>
381
+
382
+ ### 3. Automatic ordering vs. manual placeholders
383
+
384
+ When no placeholder tokens (`<|image|>`, `<|video|>`, `<|audio|>`) appear in the text, modalities are emitted in the exact order their entries appear in the dictionary or chat message `content` (immediately after any `system` task prompt).
385
+
386
+ To interleave text and media at specific positions within a sentence, write `<|image|>`, `<|video|>`, or `<|audio|>` directly in the text—automatic placeholder insertion is then disabled for that input, and each placeholder is expanded in-order with the supplied media items:
387
+
388
+ <hfoptions id="multimodal-placeholders">
389
+ <hfoption id="Sentence Transformers">
390
+
391
+ ```python
392
+ from sentence_transformers import SentenceTransformer
393
+
394
+
395
+ model = SentenceTransformer("google/embeddinggemma-2")
396
+ IMAGE_1 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
397
+ IMAGE_2 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/coco_sample.png"
398
+
399
+ # 1. Automatic ordering: follows the dictionary's key order
400
+ # -> <bos> [prompt] <image_tokens> <text_tokens> <eos>
401
+ image_first = model.encode({"image": IMAGE_1, "text": "A photo of a cat"}, prompt_name="document")
402
+
403
+ # -> <bos> [prompt] <text_tokens> <image_tokens> <eos>
404
+ text_first = model.encode({"text": "A photo of a cat", "image": IMAGE_1}, prompt_name="document")
405
+
406
+ # 2. Manual placeholders: interleave media at exact positions in the text
407
+ # No extra placeholders are inserted; counts must match the passed media inputs.
408
+ interleaved = model.encode(
409
+ {
410
+ "text": "A jacket similar to <|image|> or <|image|> featured in <|audio|>",
411
+ "image": [IMAGE_1, IMAGE_2],
412
+ "audio": "path/to/audio.wav",
413
+ },
414
+ prompt_name="query",
415
+ )
416
+ ```
417
+
418
+ </hfoption>
419
+ <hfoption id="AutoModel">
420
+
421
+ ```python
422
+ import torch
423
+ import torch.nn.functional as F
424
+ from transformers import AutoModel, AutoProcessor
425
+
426
+
427
+ model = AutoModel.from_pretrained("google/embeddinggemma-2", device_map="auto")
428
+ processor = AutoProcessor.from_pretrained("google/embeddinggemma-2")
429
+
430
+ IMAGE_1 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
431
+ IMAGE_2 = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/coco_sample.png"
432
+
433
+ # 1. Automatic ordering: follows the content list order after any system prompt
434
+ image_first_messages = [
435
+ {"role": "system", "content": "title: none | text: "},
436
+ {
437
+ "role": "user",
438
+ "content": [
439
+ {"type": "image", "url": IMAGE_1},
440
+ {"type": "text", "text": "A photo of a cat"},
441
+ ],
442
+ },
443
+ ]
444
+
445
+ # 2. Manual placeholders: interleave media at exact positions in the text
446
+ interleaved_messages = [
447
+ {"role": "system", "content": "task: search result | query: "},
448
+ {
449
+ "role": "user",
450
+ "content": [
451
+ {"type": "image", "url": IMAGE_1},
452
+ {"type": "image", "url": IMAGE_2},
453
+ {"type": "audio", "url": "path/to/audio.wav"},
454
+ {"type": "text", "text": "A jacket similar to <|image|> or <|image|> featured in <|audio|>"},
455
+ ],
456
+ },
457
+ ]
458
+
459
+ inputs = processor.apply_chat_template(
460
+ [image_first_messages, interleaved_messages],
461
+ tokenize=True,
462
+ return_dict=True,
463
+ return_tensors="pt",
464
+ ).to(model.device)
465
+
466
+ with torch.no_grad():
467
+ token_embeddings = model(**inputs).last_hidden_state
468
+
469
+ mask = inputs["attention_mask"].unsqueeze(-1).to(token_embeddings.dtype)
470
+ embeddings = (token_embeddings * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1e-9)
471
+ embeddings = F.normalize(embeddings.float(), p=2, dim=-1)
472
+ ```
473
+
474
+ </hfoption>
475
+ </hfoptions>
476
+
477
+ ### 4. Heterogeneous (mixed-modality) batching
478
+
479
+ A single batch can mix plain text, single-modality media, and multi-modality inputs in one forward pass, producing the same embedding per row as encoding each item individually:
480
+
481
+ <hfoptions id="multimodal-batch">
482
+ <hfoption id="Sentence Transformers">
483
+
484
+ ```python
485
+ from sentence_transformers import SentenceTransformer
486
+
487
+
488
+ model = SentenceTransformer("google/embeddinggemma-2")
489
+ IMAGE = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
490
+
491
+ embeddings = model.encode(
492
+ [
493
+ "A photo of a cat",
494
+ {"image": IMAGE},
495
+ {"text": "A photo of a cat", "image": IMAGE},
496
+ {"audio": "path/to/audio.wav"},
497
+ ],
498
+ prompt_name="document",
499
+ )
500
+ print(embeddings.shape)
501
+ # (4, 768)
502
+ ```
503
+
504
+ </hfoption>
505
+ <hfoption id="AutoModel">
506
+
507
+ ```python
508
+ import torch
509
+ import torch.nn.functional as F
510
+ from transformers import AutoModel, AutoProcessor
511
+
512
+
513
+ model = AutoModel.from_pretrained("google/embeddinggemma-2", device_map="auto")
514
+ processor = AutoProcessor.from_pretrained("google/embeddinggemma-2")
515
+
516
+ IMAGE = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
517
+
518
+ conversations = [
519
+ [
520
+ {"role": "system", "content": "title: none | text: "},
521
+ {"role": "user", "content": [{"type": "text", "text": "A photo of a cat"}]},
522
+ ],
523
+ [
524
+ {"role": "system", "content": "title: none | text: "},
525
+ {"role": "user", "content": [{"type": "image", "url": IMAGE}]},
526
+ ],
527
+ [
528
+ {"role": "system", "content": "title: none | text: "},
529
+ {
530
+ "role": "user",
531
+ "content": [
532
+ {"type": "text", "text": "A photo of a cat"},
533
+ {"type": "image", "url": IMAGE},
534
+ ],
535
+ },
536
+ ],
537
+ [
538
+ {"role": "system", "content": "title: none | text: "},
539
+ {"role": "user", "content": [{"type": "audio", "url": "path/to/audio.wav"}]},
540
+ ],
541
+ ]
542
+
543
+ inputs = processor.apply_chat_template(
544
+ conversations,
545
+ tokenize=True,
546
+ return_dict=True,
547
+ return_tensors="pt",
548
+ ).to(model.device)
549
+
550
+ with torch.no_grad():
551
+ token_embeddings = model(**inputs).last_hidden_state
552
+
553
+ mask = inputs["attention_mask"].unsqueeze(-1).to(token_embeddings.dtype)
554
+ embeddings = (token_embeddings * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1e-9)
555
+ embeddings = F.normalize(embeddings.float(), p=2, dim=-1)
556
+ print(embeddings.shape)
557
+ # torch.Size([4, 768])
558
+ ```
559
+
560
+ </hfoption>
561
+ </hfoptions>
562
+
563
+ ### 5. Disabling unused modality towers (memory optimization)
564
+
565
+ If your workload only embeds a subset of modalities (for example, **text-only** or **text + images** without audio), you can skip instantiating and loading the unused vision or audio towers by setting `vision_config=None` and/or `audio_config=None` on the config. The unused tower weights in the checkpoint are ignored cleanly without warnings, dropping the model from 744M to 439M parameters without the audio tower, or to 271M with neither tower.
566
+
567
+ <hfoptions id="selective-towers">
568
+ <hfoption id="Sentence Transformers">
569
+
570
+ Pass these through `config_kwargs` (which reaches `AutoConfig.from_pretrained`), not `model_kwargs`:
571
+
572
+ ```python
573
+ from sentence_transformers import SentenceTransformer
574
+
575
+
576
+ # Text-only deployment (skips both vision and audio towers)
577
+ text_model = SentenceTransformer(
578
+ "google/embeddinggemma-2",
579
+ config_kwargs={"vision_config": None, "audio_config": None},
580
+ )
581
+
582
+ # Vision + text deployment (skips audio tower)
583
+ vision_text_model = SentenceTransformer(
584
+ "google/embeddinggemma-2",
585
+ config_kwargs={"audio_config": None},
586
+ )
587
+ ```
588
+
589
+ </hfoption>
590
+ <hfoption id="AutoModel">
591
+
592
+ ```python
593
+ from transformers import AutoModel
594
+
595
+
596
+ # Text-only deployment (skips both vision and audio towers)
597
+ text_model = AutoModel.from_pretrained(
598
+ "google/embeddinggemma-2",
599
+ vision_config=None,
600
+ audio_config=None,
601
+ device_map="auto",
602
+ )
603
+
604
+ # Vision + text deployment (skips audio tower)
605
+ vision_text_model = AutoModel.from_pretrained(
606
+ "google/embeddinggemma-2",
607
+ audio_config=None,
608
+ device_map="auto",
609
+ )
610
+ ```
611
+
612
+ </hfoption>
613
+ </hfoptions>
614
+
615
+ ## Processor
616
+
617
+ [`EmbeddingGemma2Processor`] bundles the tokenizer, the image processor, the audio feature extractor, and the video processor.
618
+
619
+ > [!TIP]
620
+ > For batched multimodal inputs, we recommend passing per-sample dictionaries through **Sentence Transformers** (`model.encode([{"image": ..., "text": ...}, ...])`). For maximum control over exact modality ordering and interleaving, include `<|image|>`, `<|video|>`, and `<|audio|>` placeholders manually in `text`.
621
+
622
+ ### Controlling visual token budget (`max_soft_tokens`)
623
+
624
+ The soft-token budget (`max_soft_tokens`, supported values `{70, 140, 280, 560, 1120}`) controls the resolution and number of visual tokens produced per image or video frame (defaulting to `280` per image and `140` per video frame). Lower values reduce sequence length and latency:
625
+
626
+ <hfoptions id="processor-soft-tokens">
627
+ <hfoption id="Sentence Transformers">
628
+
629
+ ```python
630
+ from sentence_transformers import SentenceTransformer
631
+
632
+
633
+ model = SentenceTransformer("google/embeddinggemma-2")
634
+ IMAGE = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
635
+
636
+ image_embedding = model.encode(
637
+ {"image": IMAGE},
638
+ processing_kwargs={"image": {"max_soft_tokens": 70}},
639
+ )
640
+ ```
641
+
642
+ </hfoption>
643
+ <hfoption id="AutoProcessor">
644
+
645
+ ```python
646
+ from transformers import AutoProcessor
647
+
648
+
649
+ processor = AutoProcessor.from_pretrained("google/embeddinggemma-2")
650
+ IMAGE = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
651
+
652
+ inputs = processor(images=[IMAGE], max_soft_tokens=70, return_tensors="pt")
653
+ print(inputs["input_ids"].shape, inputs["pixel_values"].shape)
654
+ # torch.Size([1, 67]) torch.Size([1, 630, 768])
655
+ ```
656
+
657
+ </hfoption>
658
+ </hfoptions>
659
+
660
+ ### Video frame sampling controls
661
+
662
+ By default, [`EmbeddingGemma2VideoProcessor`] samples frames at 1 FPS (`fps=1`), caps each clip at 32 frames (`max_frames=32`, `overflow_strategy="uniform"`), and omits frame timestamps from the prompt (`add_timestamps=False`). Each parameter can be overridden per call:
663
+
664
+ - `fps` (`int | float | None`): target sampling rate in frames per second. Requires `VideoMetadata` with valid `fps` and `duration` (automatically populated when decoding from a video file/URL). For pre-decoded frame arrays without metadata, FPS sampling is skipped with a warning and `max_frames` is applied directly.
665
+ - `max_frames` (`int | None`): maximum number of frames retained per video.
666
+ - `overflow_strategy` (`"uniform" | "truncate" | None`): how excess frames above `max_frames` are reduced (`"uniform"` resamples evenly across the clip; `"truncate"` keeps the leading `max_frames` frames).
667
+ - `add_timestamps` (`bool`): whether to prefix each frame's soft-token block with its `mm:ss` timestamp. Unlike `fps`, this has no fallback: `add_timestamps=True` on a video whose metadata has no `fps` raises, because a guessed rate would write wrong `mm:ss` labels into the prompt.
668
+
669
+ <hfoptions id="multimodal-video">
670
+ <hfoption id="Sentence Transformers">
671
+
672
+ ```python
673
+ from sentence_transformers import SentenceTransformer
674
+
675
+
676
+ model = SentenceTransformer("google/embeddinggemma-2")
677
+
678
+ video_embedding = model.encode(
679
+ {"video": "path/to/video.mp4"},
680
+ processing_kwargs={"video": {"add_timestamps": True, "fps": 2, "max_frames": 16, "overflow_strategy": "truncate"}},
681
+ )
682
+ ```
683
+
684
+ </hfoption>
685
+ <hfoption id="AutoProcessor">
686
+
687
+ ```python
688
+ from transformers import AutoProcessor
689
+
690
+
691
+ processor = AutoProcessor.from_pretrained("google/embeddinggemma-2")
692
+
693
+ inputs = processor(
694
+ videos=["path/to/video.mp4"],
695
+ add_timestamps=True,
696
+ fps=2,
697
+ max_frames=16,
698
+ overflow_strategy="truncate",
699
+ return_tensors="pt",
700
+ )
701
+ ```
702
+
703
+ </hfoption>
704
+ </hfoptions>
705
+
706
+ ### Direct `processor(...)` calls without chat template
707
+
708
+ While `processor.apply_chat_template` is the primary entry point for multimodal conversations, `processor(...)` can also be called directly. When `text` is omitted (`text=None`), `<|image|>`, `<|video|>`, and `<|audio|>` placeholders are synthesized automatically for each sample in the batch:
709
+
710
+ ```python
711
+ from transformers import AutoProcessor
712
+
713
+
714
+ processor = AutoProcessor.from_pretrained("google/embeddinggemma-2")
715
+
716
+ IMAGE = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg"
717
+ AUDIO = "path/to/audio.wav" # a path, a URL, or a 1-D float array sampled at 16 kHz
718
+
719
+ # Text only
720
+ inputs = processor(text=["task: search result | query: Which planet is the Red Planet?"], return_tensors="pt")
721
+
722
+ # Media only (text=None): placeholders are synthesized per sample
723
+ inputs = processor(images=[IMAGE], return_tensors="pt")
724
+ inputs = processor(videos=["path/to/video.mp4"], return_tensors="pt")
725
+ inputs = processor(audio=[AUDIO], return_tensors="pt")
726
+
727
+ # Nested per-sample lists or combined modalities with text=None
728
+ inputs = processor(
729
+ images=[[IMAGE, IMAGE], [IMAGE]],
730
+ audio=[[AUDIO], [AUDIO, AUDIO]],
731
+ return_tensors="pt",
732
+ )
733
+
734
+ # Manual placeholders in text for direct processor calls
735
+ inputs = processor(text=["<|image|> a photo of a cat"], images=[[IMAGE]], return_tensors="pt")
736
+ print(list(inputs.keys()))
737
+ # ['input_ids', 'attention_mask', 'pixel_values', 'image_position_ids']
738
+ ```
739
+
740
+ ## EmbeddingGemma2TextConfig
741
+
742
+ [[autodoc]] EmbeddingGemma2TextConfig
743
+
744
+ ## EmbeddingGemma2Config
745
+
746
+ [[autodoc]] EmbeddingGemma2Config
747
+
748
+ ## EmbeddingGemma2VideoProcessor
749
+
750
+ [[autodoc]] EmbeddingGemma2VideoProcessor
751
+ - preprocess
752
+
753
+ ## EmbeddingGemma2Processor
754
+
755
+ [[autodoc]] EmbeddingGemma2Processor
756
+ - __call__
757
+
758
+ ## EmbeddingGemma2PreTrainedModel
759
+
760
+ [[autodoc]] EmbeddingGemma2PreTrainedModel
761
+ - forward
762
+
763
+ ## EmbeddingGemma2TextModel
764
+
765
+ [[autodoc]] EmbeddingGemma2TextModel
766
+ - forward
767
+
768
+ ## EmbeddingGemma2Model
769
+
770
+ [[autodoc]] EmbeddingGemma2Model
771
+ - forward
772
+ - get_image_features
773
+ - get_video_features
774
+ - get_audio_features
775
+