Skip to content

Add VideoChat-Flash (OpenGVLab) language model support - #2147

Merged
kunal-vaishnavi merged 25 commits into
microsoft:mainfrom
anilmartha:add-opengv-support_updated
May 22, 2026
Merged

Add VideoChat-Flash (OpenGVLab) language model support#2147
kunal-vaishnavi merged 25 commits into
microsoft:mainfrom
anilmartha:add-opengv-support_updated

Conversation

@anilmartha

@anilmartha anilmartha commented May 8, 2026

Copy link
Copy Markdown
Contributor

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 from QwenModel directly rather than Qwen25VLTextModel.

Changes

Python builder (src/python/py/models/)

  • builders/qwen.py — New VideoChatFlashQwenModel subclass of QwenModel.
    • Overrides make_genai_config() to bypass the model's custom remote code (which imports av, cv2, decord, imageio even for config-only loads) by writing a temporary Qwen2Config-based config.json and patching genai_config.json["model"]["type"] back to videochat_flash_qwen.
    • Overrides load_weights() to load the LM backbone directly via Qwen2ForCausalLM.from_pretrained(), avoiding video deps.
    • Sets model_type = "videochat_flash_qwen" and hf_remote = False.
  • builders/__init__.py — Exports VideoChatFlashQwenModel.
  • builder.py
    • Detects VideoChatFlashQwenForCausalLM by peeking at raw config.json (local dir or via hf_hub_download) before calling AutoConfig, then loads as Qwen2Config to avoid pulling in video libraries.
    • Routes VideoChatFlashQwenForCausalLMVideoChatFlashQwenModel and defaults exclude_embeds=True (the text decoder receives inputs_embeds from the embedding merger). exclude_embeds is now opt-in (guarded with not in extra_options) so standalone input_ids export still works.

C++ runtime (src/)

  • models/videochat_flash_processor.{h,cpp} (new)VideoChatFlashProcessor runs ORT-Extensions image preprocessing, transposes HWC→CHW, reshapes to [1, num_frames, C, H, W], casts pixel values to the session input dtype, builds input_ids by replacing each <|vision_start|>…<|vision_end|> block with a fixed number of <|image_pad|> tokens, and emits image_grid_thw so GetImageFeatureBatchSize can determine num_images after the pixel_values name remap.
  • models/model.cpp — Registers "videochat_flash_qwen" → VideoChatFlashProcessor in MultiModalProcessor.
  • models/model_type.h — Adds "videochat_flash_qwen" to the IsVLM() list (size 6 → 7).
  • config.{h,cpp} — Adds Vision::num_visual_tokens (default 0) — fixed visual tokens per image; 0 falls back to computing from image_grid_thw. Required (>0) by the new processor.

Files changed

File Change
src/config.cpp Parse num_visual_tokens from vision config
src/config.h Add num_visual_tokens field on Vision
src/models/model.cpp Register VideoChatFlashProcessor
src/models/model.h Header / license update
src/models/model_type.h Add videochat_flash_qwen to VLM list
src/models/videochat_flash_processor.cpp New — image processor
src/models/videochat_flash_processor.h New — header
src/python/py/models/builder.py Detect VCF arch, bypass remote-code video deps, route to new builder
src/python/py/models/builders/__init__.py Export VideoChatFlashQwenModel
src/python/py/models/builders/qwen.py Add VideoChatFlashQwenModel

Validation

  • Text-only export of the Qwen2.5-7B backbone via 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=false succeeds without av/cv2/decord/imageio installed.
  • Standalone inference on the exported vcf-oga-fp32-standalone model produces correct answers across 4 batched QA prompts (e.g. Paris, 56, ONNX Runtime description) using generator.append_tokens() on the Qwen2.5-7B backbone.

Test plan

  • Build OGA with the new processor compiled in and confirm IsVLM("videochat_flash_qwen") returns true.
  • Export the text decoder with exclude_embeds=false and run text-only inference end-to-end.
  • Confirm genai_config.json contains "type": "videochat_flash_qwen" (full VLM) or "type": "qwen2" (text-only standalone).
  • Image-input smoke test once vision.onnx and embedding.onnx land.

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>
@VishalX

Copy link
Copy Markdown
Contributor

Olive Recipe: microsoft/olive-recipes#406

@anilmartha
anilmartha marked this pull request as ready for review May 11, 2026 09:51
@anilmartha
anilmartha requested a review from a team as a code owner May 11, 2026 09:51
Copilot AI review requested due to automatic review settings May 11, 2026 09:51
@anilmartha

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree company="AMD"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 VideoChatFlashQwenForCausalLM early from raw config.json, route to a new VideoChatFlashQwenModel, and avoid trust_remote_code video-library imports.
  • C++: introduce VideoChatFlashProcessor and register videochat_flash_qwen as a VLM model type/processor.
  • Config: add and parse vision.num_visual_tokens used 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_qwenVideoChatFlashProcessor 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.

Comment thread src/python/py/models/builders/__init__.py Outdated
Comment thread src/python/py/models/builder.py Outdated
Comment thread src/config.h Outdated
Comment thread src/models/videochat_flash_processor.cpp
Comment thread src/python/py/models/builders/__init__.py Outdated
anilmartha and others added 2 commits May 18, 2026 11:03
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>
Comment thread src/python/py/models/builders/qwen.py Fixed
Comment thread src/python/py/models/builders/qwen.py Fixed
Comment thread src/python/py/models/builder.py Fixed
@anilmartha

Copy link
Copy Markdown
Contributor Author

Hi kunal-vaishnavi
Could you please review it again?

Comment thread src/models/videochat_flash_processor.cpp Outdated
Comment thread src/models/videochat_flash_processor.cpp Outdated
Comment thread src/models/videochat_flash_processor.cpp Outdated
Comment thread src/models/videochat_flash_processor.cpp Outdated
Comment thread src/python/py/models/builder.py Outdated
Comment thread src/python/py/models/builders/qwen.py Outdated
Comment thread src/python/py/models/builders/qwen.py Outdated
Comment thread src/python/py/models/builders/qwen.py Outdated
Comment thread src/python/py/models/builders/qwen.py Outdated
Comment thread src/python/py/models/builders/qwen.py Outdated
Comment thread src/python/py/models/builder.py Outdated
Comment thread src/python/py/models/builder.py
Anil Kumar Martha and others added 4 commits May 20, 2026 11:48
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>
@anilmartha

Copy link
Copy Markdown
Contributor Author

Hi kunal-vaishnavi
I have addressed the review comments. Could you please take another look?

Comment thread src/python/py/models/builders/qwen.py Fixed
Comment thread src/python/py/models/builders/qwen.py Outdated
Comment thread src/python/py/models/builders/qwen.py Dismissed
@kunal-vaishnavi
kunal-vaishnavi enabled auto-merge (squash) May 22, 2026 17:07
@kunal-vaishnavi
kunal-vaishnavi merged commit 5439ab9 into microsoft:main May 22, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants