Repository navigation
feat(embeddings): support EmbeddingGemma 2 (embedding_gemma2) multimodal embedder - #2316
Merged
Merged
Conversation
…dal embedder Implement `ModelType::EmbeddingGemma2` to support Google's EmbeddingGemma 2 (`google/embeddinggemma-2` and `mlx-community/embeddinggemma-2-*`) 300M multimodal embedding model: - Add `EmbeddingGemma2Config` parsing both top-level multimodal configs (`model_type = "embedding_gemma2"`) and text-only configs (`model_type = "embedding_gemma2_text"`), resolving `per_layer_config` overrides on zero-padded (`"05"`, `"11"`, `"17"`, `"23"`) and unpadded layer keys, and handling mixed quantization (`"language_model.ple": false` and per-module bit/group dicts). - Add `sanitize_embedding_gemma2_weights` normalizing both Hugging Face (`model.language_model.layers.*`, `model.language_model.embed_tokens_per_layer.*`) and `mlx-vlm` (`language_model.layers.*`, `language_model.ple.*`, `language_model.embedding_projection.*`) checkpoint weight layouts. - Preserve `BFloat16` weights at load time in `bf16_to_f16_at_load` for `embedding_gemma2` / `embedding_gemma2_text` / `EmbeddingGemma2Model` to avoid FP16 overflow on its unscaled pre-norm activations. - Implement `EmbeddingGemma2Attention` (`q_norm` and `k_norm` with learnable scale, `v_norm` parameterless `RMSNormNoScale`, per-layer `head_dim`, `num_key_value_heads`, and `rope_theta`, SDPA `scale = 1.0`), `EmbeddingGemma2Mlp` (`gelu_pytorch_tanh`), `EmbeddingGemma2PleBlock`, and `EmbeddingGemma2Layer` (`layer_scalar`). - Implement `EmbeddingGemma2Model` with `sqrt(hidden_size)` input scaling, projection-only Per-Layer Embeddings (`per_layer_model_projection` scaled by `hidden_size^-0.5` + `per_layer_projection_norm`), optional `Gemma4VisionModel` and `AudioEncoder` + `Gemma4MultimodalEmbedder` placeholder scatter (`<|image|>` `258880`, `<|audio|>` `258881`), bidirectional full-attention (`create_bidirectional_padding_mask`) and sliding-window (`create_bidirectional_window_mask(attention_mask, sliding_window + 1)`) masks, final RMSNorm, and in-model `embedding_projection` (`512 -> 768`) with Matryoshka truncation (`768 / 512 / 256 / 128`) and L2 normalization via `EmbeddingEngine`. - Register `ModelType::EmbeddingGemma2` across `detection.rs`, `loader.rs`, `model_metadata.rs`, `registry.rs`, `memory_estimate.rs`, `tensor_parallel/inference.rs`, and documentation (`docs/embeddings.md`, `docs/supported-models.md`). Refs #2314
…ion geometry Remove corrupted placeholder string in EmbeddingGemma2Model::format_text and preserve leading tokens when expanding image placeholders with empty text. Ensure non-sliding attention layers unconditionally fall back to global head dimension and key-value head count when omitted from per_layer_config overrides. Support nested text_config.model_type during embedding checkpoint detection to match dtype preservation detection. Align the reference real-checkpoint integration test with official Venus/Mars benchmark numbers and add multimodal token expansion unit coverage. Add bilingual technical review report under TECHNICAL_REPORTS/.
Member
Author
Implementation Review SummaryIntent
Findings Addressed
Remaining ItemsNone Verification
|
…ed quant and mask allocations Resolve multiple security, stability, and performance issues in EmbeddingGemma 2: - Prevent server panics when multimodal inputs produce empty feature lists or zero-length audio sequences during masked scatter. - Support boolean false overrides in mixed quantization configurations, correctly disabling quantization for unquantized modules like PLE. - Optimize bidirectional sliding window mask allocation by avoiding O(L^2) tensor generation when sequence length is within sliding window + 1. - Eliminate redundant host-to-device transfers, array copies, and unnecessary dtype conversions in layer scalar scaling and forward passes. - Enforce positive minimum bounds on geometry configuration parameters and inspect nested text_config architectures during model detection. - Update technical reports and regression tests to verify all security and performance hardening fixes.
Member
Author
Security & Performance Review SummaryReview ScopeComprehensive security and performance audit of PR #2316 ( Findings Addressed
Verification
|
Apply rustfmt formatting to EmbeddingGemma 2 detection, forward pass, test, and weight sanitization modules. Update bilingual technical reports with cargo fmt check verification. Validation: - cargo fmt --check (passed) - cargo clippy --lib --tests -- -D warnings (passed) - cargo test --lib embedding_gemma2 (8 passed, 0 failed, 1 ignored) - cargo test --lib embeddings:: (85 passed, 0 failed) Refs #2314
Member
Author
PR Finalization CompleteSummary
All checks passing. Ready for merge. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements
ModelType::EmbeddingGemma2to support Google's EmbeddingGemma 2 (google/embeddinggemma-2andmlx-community/embeddinggemma-2-*inbf16,8bit,6bit,5bit,4bit,mxfp8,mxfp4,nvfp4), a 0.6B Gemma 4-based multimodal embedding architecture (architectures: ["EmbeddingGemma2Model"],model_type: "embedding_gemma2").Key Changes
src/models/embedding_gemma2_config.rs):model_type = "embedding_gemma2") and standalone text configs (model_type = "embedding_gemma2_text"), enforcing positive lower bounds (.max(1)) on geometry dimensions.per_layer_configoverrides on zero-padded ("05","11","17","23") and unpadded keys (head_dim = 512,num_key_value_heads = 1,rope_theta = 1_000_000.0,attention_type = "full_attention"), unconditionally defaulting non-sliding layers to global geometry when specific fields are omitted.mlx-vlmmixed quantization overrides ("language_model.ple": falseboolean overrides and per-module bit/group dicts across bothtext_configand rootconfig) viaquant_params_for_prefix.model.language_model.layers.*) andmlx-vlm(language_model.layers.*,language_model.ple.*,language_model.embedding_projection.*) checkpoint weight layouts viasanitize_embedding_gemma2_weights.src/models/sanitize.rs,src/models/detection.rs):bf16_to_f16_at_loadandis_embedding_checkpointto inspect top-level and nestedtext_configmodel_type/architecturessoembedding_gemma2/embedding_gemma2_text/EmbeddingGemma2ModelpreserveBFloat16weights at load time and avoid FP16 overflow on unscaled pre-norm activations.src/models/embedding_gemma2_layers.rs):EmbeddingGemma2Attention: per-layerhead_dim,num_key_value_heads, andrope_theta;q_normandk_normwith learnable scale (RMSNorm) and parameterlessv_norm(RMSNormNoScaleviafast_rms_norm_no_weight); bidirectional RoPE and SDPA withscale = 1.0.EmbeddingGemma2Mlp: GeGLU withgelu_pytorch_tanh(compiled_geglu_approx_activation).EmbeddingGemma2PleBlock&EmbeddingGemma2Layer: gated per-layer residual block (per_layer_input_gate-> GeLU ->* per_layer_input->per_layer_projection->post_per_layer_input_norm) and learnablelayer_scalar(mlxcel_core::multiply_scalar).src/models/embedding_gemma2.rs):sqrt(hidden_size)input embedding scaling and projection-only PLE (language_model.ple.per_layer_model_projectionscaled byhidden_size^-0.5+per_layer_projection_normacross24layers).Gemma4VisionModel+Gemma4MultimodalEmbedder(<|image|>258880) andAudioEncoder+Gemma4MultimodalEmbedder(<|audio|>258881) placeholder replacement viamasked_scatter, with guards against empty image lists or zero-length audio sequences.create_bidirectional_padding_mask) and bidirectional sliding-window mask (create_bidirectional_window_mask(attention_mask, sliding_window + 1)), bypassinglanguage_model.embedding_projection(512 -> 768, bias=False) before masked mean pooling (PoolingMode::Mean), supporting Matryoshka truncation (768 / 512 / 384 / 256 / 128) and L2 normalization throughEmbeddingEngine.ModelType::EmbeddingGemma2intosrc/models/mod.rs,src/models/detection.rs,src/embeddings/loader.rs,src/model_metadata.rs,src/models/registry.rs,src/execution/memory_estimate.rs,src/distributed/tensor_parallel/inference.rs,docs/embeddings.md,docs/supported-models.md, andTECHNICAL_REPORTS/2316-embedding-gemma2-embedder-20261015.{en,ko}.md.Changes during review
format_textwith clean identity formatting and preserved leading tokens inexpand_image_tokens.EmbeddingGemma2Config::from_jsonand added booleanfalsemixed quantization override handling inquant_params_for_prefix.forward_multimodaland bypassedTest plan
src/models/embedding_gemma2_tests.rs:per_layer_config_resolves_local_and_global_layersconfig_bounds_guard_against_malformed_nonpositive_valuesdetection_accepts_embedding_gemma2_variants_and_preserves_bf16sanitize_and_quant_params_handle_hf_and_mlx_layoutssynthetic_forward_padding_invariance_bidirectionality_and_matryoshkasliding_window_mask_blocks_tokens_beyond_windowshort_sequence_sliding_window_bypass_matches_explicit_window_maskexpand_image_tokens_text_only_and_vision_pathsreal_checkpoint_embeddinggemma2_parity_and_ranking(#[ignore], checksretrieval_scores_venus_mars: [0.6775, 0.8348])cargo test --lib embedding_gemma2,cargo test --lib embeddings::,cargo test --lib models::detection_tests,cargo clippy --lib --tests -- -D warnings, andcargo fmt --check.Closes #2314