Enable Gemma4 video input#4114
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends the Gemma4 VLM implementation to accept video inputs by introducing a video placeholder token, adding Gemma4 video frame encoding, and merging video embeddings into the text embeddings flow. It also updates the Python VLM pipeline tests to exercise Gemma4 as a video-capable model.
Changes:
- Add Gemma4 video placeholder token to VLM configuration and Python test prompt generation.
- Implement Gemma4 video encoding (
encode_frames/encode_videos) and video-aware prompt normalization + embedding merge. - Register Gemma4 tiny-random model IDs as video models in the Python test suite.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
tests/python_tests/test_vlm_pipeline.py |
Adds Gemma4 model IDs to the video test matrix and defines `< |
src/cpp/src/visual_language/vlm_config.hpp |
Introduces video_token configuration (default `< |
src/cpp/src/visual_language/gemma4/classes.hpp |
Extends Gemma4 vision encoder + inputs embedder interfaces to support video inputs. |
src/cpp/src/visual_language/gemma4/classes.cpp |
Implements video metadata handling, frame encoding/concatenation, video tag expansion in prompts, and video embedding merge. |
…hc offset, add asserts
| if (!video_config.do_sample_frames) { | ||
| video_metadata.frames_indices.resize(total_num_frames); | ||
| std::iota(video_metadata.frames_indices.begin(), video_metadata.frames_indices.end(), 0); | ||
| return; | ||
| } | ||
|
|
||
| size_t num_frames = video_config.num_frames; | ||
|
|
||
| if (num_frames == 0) { | ||
| num_frames = std::min(total_num_frames, video_config.max_frames > 0 ? video_config.max_frames : total_num_frames); | ||
| } | ||
|
|
||
| num_frames = std::min(num_frames, total_num_frames); | ||
| OPENVINO_ASSERT(num_frames > 0, "Number of frames to sample must be positive."); | ||
|
|
There was a problem hiding this comment.
Gemma4 video processor config does not have fps and min_frames params and they are not used in HF transformers implementation
| void InputsEmbedderGemma4::encode_vision_token_ids() { | ||
| std::call_once(m_vision_token_ids_once_flag, [this]() { | ||
| const auto encoded_vision_tokens = | ||
| m_tokenizer.encode(m_vlm_config.image_token + m_vlm_config.video_token, ov::genai::add_special_tokens(false)).input_ids; | ||
| OPENVINO_ASSERT(encoded_vision_tokens.get_size() == 2, "Encoded vision tokens must contain two tokens"); | ||
| m_image_token_id = encoded_vision_tokens.data<int64_t>()[0]; | ||
| m_video_token_id = encoded_vision_tokens.data<int64_t>()[1]; | ||
| }); | ||
| } |
There was a problem hiding this comment.
Such pattern is already used in GenAI to have a single tokenizer.encode call
| std::vector<ov::Tensor> frame_features; | ||
| frame_features.reserve(frames.size()); | ||
|
|
||
| for (const auto& frame : frames) { | ||
| EncodedImage encoded = encode_with_config(frame, m_video_processor_config); | ||
| frame_features.push_back(std::move(encoded.resized_source)); | ||
| } | ||
|
|
||
| // Concatenate all frame features: [1, total_tokens, hidden_size] | ||
| size_t num_soft_tokens_per_frame = frame_features[0].get_shape()[1]; | ||
| const size_t hidden_size = frame_features[0].get_shape()[2]; | ||
| const size_t total_tokens = frames.size() * num_soft_tokens_per_frame; |
There was a problem hiding this comment.
Input video frames (and its embeddings) are expected to have the same shape and element type
| for (size_t f = 0; f < encoded_video.frame_num; ++f) { | ||
| ov::Tensor frame_embed(elem_type, {1, tokens_per_frame, hidden_size}); | ||
| std::memcpy(frame_embed.data(), src + f * bytes_per_frame, bytes_per_frame); | ||
| video_embeds.push_back(std::move(frame_embed)); | ||
| } |
… tiny-random-gemma4" This reverts commit 364138b.
| std::vector<size_t> original_video_indices(video_frames_num); | ||
| std::iota(original_video_indices.begin(), original_video_indices.end(), 0); | ||
|
|
||
| if (video_metadata.frames_indices.empty() || video_metadata.frames_indices == original_video_indices) { | ||
| return video; | ||
| } |
| #include <cmath> | ||
| #include <cstring> | ||
| #include <sstream> | ||
| #include <iomanip> | ||
| #include <numeric> | ||
|
|
Description
This PR adds video input support for Gemma4 model family.
CVS-185850
Checklist: