Feature Extraction
Transformers
Safetensors
sentence-transformers
multilingual
embedding_gemma2
embedding
multimodal-embedding
multimodal
vision
audio
video
image-feature-extraction
audio-feature-extraction
video-feature-extraction
sentence-similarity
Instructions to use google/embeddinggemma-2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use google/embeddinggemma-2 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="google/embeddinggemma-2")# pip install -U transformers accelerate # Load model directly from transformers import AutoProcessor, AutoModel processor = AutoProcessor.from_pretrained("google/embeddinggemma-2") model = AutoModel.from_pretrained("google/embeddinggemma-2", device_map="auto") - sentence-transformers
How to use google/embeddinggemma-2 with sentence-transformers:
from sentence_transformers import SentenceTransformer model = SentenceTransformer("google/embeddinggemma-2") sentences = [ "The weather is lovely today.", "It's so sunny outside!", "He drove to the stadium." ] embeddings = model.encode(sentences) similarities = model.similarity(embeddings, embeddings) print(similarities.shape) # [3, 3] - Notebooks
- Google Colab
- Kaggle
Upload folder using huggingface_hub
Browse files
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 |
+
|