Add VideoChat-Flash (OpenGVLab) language model support - #2147
Merged
kunal-vaishnavi merged 25 commits intoMay 22, 2026
Conversation
Adds text decoder export support for OpenGVLab/VideoChat-Flash-Qwen2_5-7B_InternVideo2-1B. Architecture: VideoChatFlashQwenForCausalLM is a VLM whose language backbone is standard Qwen2.5-7B (flat config, standard weight keys, 2D RoPE, rope_theta=1e6, 28L / 28h / 4kv / hidden=3584). The model does NOT use MRoPE, so the builder inherits QwenModel directly rather than Qwen25VLTextModel. Changes: - src/python/py/models/builders/qwen.py: Add VideoChatFlashQwenModel subclass of QwenModel. Sets exclude_embeds=True (text decoder receives inputs_embeds from the embedding merger) and model_type="videochat_flash_qwen". - src/python/py/models/builders/__init__.py: Export VideoChatFlashQwenModel. - src/python/py/models/builder.py: Map "VideoChatFlashQwenForCausalLM" architecture string to VideoChatFlashQwenModel with exclude_embeds=True. - src/models/model_type.h: Register "videochat_flash_qwen" in IsVLM() (size 6->7). - examples/python/videochat-flash/builder.py: New example export script. Phase 1 (this PR): text decoder only. Vision encoder (InternVideo2-1B) and embedding merger export are Phase 2 (scaffolded as TODOs). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…inference support - builder.py (example): use local OGA builder via sys.path; fix create_model args when no local input dir; move prepare_model() inside Phase-2 block (trust_remote_code=False is safe for config-only loads) - builder.py (core): add VCF config bypass using hf_hub_download + Qwen2Config to avoid av/cv2/decord/imageio imports triggered by AutoConfig; set config._name_or_path so load_weights() resolves the model correctly; make exclude_embeds opt-in (guard with 'not in extra_options') so standalone (input_ids) export also works - qwen.py: add make_genai_config() override that writes a temp Qwen2Config and patches genai_config.json type back to videochat_flash_qwen; add load_weights() override using Qwen2ForCausalLM.from_pretrained() directly Validated: text-only inference with vcf-oga-fp32-standalone/ produces correct answers (Paris, 56, ONNX Runtime description) using append_tokens() API on the exported Qwen2.5-7B backbone. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
examples/python/videochat-flash/run.py:
- Text-only inference for the exported OGA model
- Uses HF AutoTokenizer (og.Tokenizer fails for TokenizersBackend models)
- Feeds tokens via generator.append_tokens(np.int32 array)
- --batch flag runs 4 built-in QA prompts for quick validation
- --prompt / --max-length for custom single-prompt runs
- Notes in docstring on genai_config.json type patch workaround for
installed OGA binaries that predate videochat_flash_qwen support
Validated: all 4 batch prompts produce correct answers on vcf-oga-fp32-standalone.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…xt-only mode Root cause of teammate's inference failure: 1. builder.py set type=videochat_flash_qwen even in --text-only mode. OGA loads this via MultiModalLanguageModel which requires vision.onnx + embedding.onnx (not present in text-only export) → 'File doesn't exist' error on og.Model(). 2. exclude_embeds defaulted to true → decoder expected inputs_embeds, but run.py feeds token IDs via append_tokens() → 'input not found' error. Fix: - builder.py export_text_model(): pass exclude_embeds=false in text-only mode (decoder uses input_ids for standalone inference). - builder.py update_genai_config(): set type=qwen2 in text-only mode so OGA loads the model as a plain decoder (LM backbone is identical to Qwen2.5-7B). type=videochat_flash_qwen is reserved for Phase 2 full VLM pipeline. - run.py: simplify docstring now that no manual patching is needed. Validated with compiled OGA build (onnxruntime-genai conda env, Python 3.11): all 4 batch prompts produce correct answers without any manual config changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents Phase 1 (text decoder, done) and Phase 2 (vision + embedding, TODO): - Architecture overview: InternVideo2-1B ViT → mm_projector → embedding merger → Qwen2.5-7B - Phase 1 summary: what was implemented, design decisions, usage instructions - Phase 2 roadmap: vision.onnx export (39-block ViT + MLP projector), embedding.onnx (embed_tokens + image-pad replacement), genai_config.json wiring, video preprocessing, and optional in-LLM HiCo compression (llm_compress_layer_list) - Key challenges: 3D spatiotemporal attention ONNX compat, ToMe token merging ops, dynamic temporal position embeddings - File map and reference links Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
|
Olive Recipe: microsoft/olive-recipes#406 |
Contributor
Author
|
@microsoft-github-policy-service agree company="AMD" |
Contributor
There was a problem hiding this comment.
Pull request overview
Adds first-class support for the OpenGVLab VideoChat-Flash Qwen-based video-language model by extending the Python model builder to export its (text) decoder without pulling video dependencies, and extending the C++ runtime to recognize/run the new multimodal model type.
Changes:
- Python: detect
VideoChatFlashQwenForCausalLMearly from rawconfig.json, route to a newVideoChatFlashQwenModel, and avoidtrust_remote_codevideo-library imports. - C++: introduce
VideoChatFlashProcessorand registervideochat_flash_qwenas a VLM model type/processor. - Config: add and parse
vision.num_visual_tokensused by the new processor for fixed visual-token padding.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/python/py/models/builders/qwen.py | Adds VideoChatFlashQwenModel subclass to export the LM backbone while bypassing remote-code video deps. |
| src/python/py/models/builders/init.py | Exports the new builder class from the builders package. |
| src/python/py/models/builder.py | Adds config “peek” detection for VideoChat-Flash and routes to the new builder with default exclude_embeds=True. |
| src/models/videochat_flash_processor.h | Declares VideoChatFlashProcessor (new multimodal processor). |
| src/models/videochat_flash_processor.cpp | Implements preprocessing/token padding + emits image_grid_thw for batching inference. |
| src/models/model.h | Updates header/license comments. |
| src/models/model.cpp | Registers videochat_flash_qwen → VideoChatFlashProcessor in the multimodal processor factory. |
| src/models/model_type.h | Adds videochat_flash_qwen to the VLM model-type list. |
| src/config.h | Adds vision.num_visual_tokens to config schema. |
| src/config.cpp | Parses vision.num_visual_tokens from genai_config.json. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
- builder.py: introduce _has_vcf_architecture() helper that handles architectures as a list, a bare string, or absent/unknown type, then use it in both the local-dir and HF-hub code paths (Copilot comment #2) - config.h: correct misleading comment on num_visual_tokens — remove the false "0 = compute from image_grid_thw" claim; the field must be > 0 for videochat_flash_qwen (Copilot comment #3) - videochat_flash_processor.cpp: add clarifying comment to empty catch block — exception is expected when only the language decoder session is loaded (Copilot comment microsoft#4) - builders/__init__.py: move VideoChatFlashQwenModel to its correct alphabetical position in __all__ (after SmolLM3Model, before WhisperModel) per kunal-vaishnavi comment microsoft#6 Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
Contributor
Author
|
Hi kunal-vaishnavi |
Address PR microsoft#2147 review: keep the config loading section generic by removing the VideoChat-Flash architecture peek/Qwen2Config workaround. Use the standard AutoConfig.from_pretrained path for all models. Also remove the forced hf_remote=False in the VCF dispatch branch so HF model dependencies (video libraries) are loaded normally, consistent with how other models handle their library requirements. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
Author
|
Hi kunal-vaishnavi |
kunal-vaishnavi
previously approved these changes
May 22, 2026
kunal-vaishnavi
approved these changes
May 22, 2026
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
Adds support for OpenGVLab/VideoChat-Flash-Qwen2_5-7B_InternVideo2-1B, a video-language model whose architecture is
VideoChatFlashQwenForCausalLM. The language backbone is standard Qwen2.5-7B (flat config, standard weight keys, 2D RoPE,rope_theta=1e6, 28 layers / 28 heads / 4 KV heads / hidden=3584). Because it does not use MRoPE, the new builder inherits fromQwenModeldirectly rather thanQwen25VLTextModel.Changes
Python builder (
src/python/py/models/)builders/qwen.py— NewVideoChatFlashQwenModelsubclass ofQwenModel.make_genai_config()to bypass the model's custom remote code (which importsav,cv2,decord,imageioeven for config-only loads) by writing a temporaryQwen2Config-basedconfig.jsonand patchinggenai_config.json["model"]["type"]back tovideochat_flash_qwen.load_weights()to load the LM backbone directly viaQwen2ForCausalLM.from_pretrained(), avoiding video deps.model_type = "videochat_flash_qwen"andhf_remote = False.builders/__init__.py— ExportsVideoChatFlashQwenModel.builder.py—VideoChatFlashQwenForCausalLMby peeking at rawconfig.json(local dir or viahf_hub_download) before callingAutoConfig, then loads asQwen2Configto avoid pulling in video libraries.VideoChatFlashQwenForCausalLM→VideoChatFlashQwenModeland defaultsexclude_embeds=True(the text decoder receivesinputs_embedsfrom the embedding merger).exclude_embedsis now opt-in (guarded withnot in extra_options) so standaloneinput_idsexport still works.C++ runtime (
src/)models/videochat_flash_processor.{h,cpp}(new) —VideoChatFlashProcessorruns ORT-Extensions image preprocessing, transposes HWC→CHW, reshapes to[1, num_frames, C, H, W], casts pixel values to the session input dtype, buildsinput_idsby replacing each<|vision_start|>…<|vision_end|>block with a fixed number of<|image_pad|>tokens, and emitsimage_grid_thwsoGetImageFeatureBatchSizecan determinenum_imagesafter thepixel_valuesname remap.models/model.cpp— Registers"videochat_flash_qwen" → VideoChatFlashProcessorinMultiModalProcessor.models/model_type.h— Adds"videochat_flash_qwen"to theIsVLM()list (size 6 → 7).config.{h,cpp}— AddsVision::num_visual_tokens(default0) — fixed visual tokens per image;0falls back to computing fromimage_grid_thw. Required (>0) by the new processor.Files changed
src/config.cppnum_visual_tokensfrom vision configsrc/config.hnum_visual_tokensfield onVisionsrc/models/model.cppVideoChatFlashProcessorsrc/models/model.hsrc/models/model_type.hvideochat_flash_qwento VLM listsrc/models/videochat_flash_processor.cppsrc/models/videochat_flash_processor.hsrc/python/py/models/builder.pysrc/python/py/models/builders/__init__.pyVideoChatFlashQwenModelsrc/python/py/models/builders/qwen.pyVideoChatFlashQwenModelValidation
python -m onnxruntime_genai.models.builder -m OpenGVLab/VideoChat-Flash-Qwen2_5-7B_InternVideo2-1B -o <dir> -p fp32 -e cpu --extra_options exclude_embeds=falsesucceeds withoutav/cv2/decord/imageioinstalled.vcf-oga-fp32-standalonemodel produces correct answers across 4 batched QA prompts (e.g. Paris, 56, ONNX Runtime description) usinggenerator.append_tokens()on the Qwen2.5-7B backbone.Test plan
IsVLM("videochat_flash_qwen")returnstrue.exclude_embeds=falseand run text-only inference end-to-end.genai_config.jsoncontains"type": "videochat_flash_qwen"(full VLM) or"type": "qwen2"(text-only standalone).vision.onnxandembedding.onnxland.