Skip to content

Commit 970cd41

Browse files
justinchubyCopilot
andauthored
Add HunYuan VL-MoT (hunyuan_vl_mot) VLM model support (#291)
## Summary Add support for **HunYuan VL-MoT** (HY-Embodied-0.5-X) vision-language model. **Model**: tencent/HY-Embodied-0.5-X (3.8B params BF16, ~7.5GB) **Registry key**: hunyuan_vl_mot **Task**: Custom HunYuanVLMoTTask (3-model VLM split: decoder + vision_encoder + embedding) ## Architecture **Decoder** (32 layers, 2048 hidden, 16Q/4KV heads, head_dim=128): - MoT dual-pathway: separate Q/K/V/O for text vs vision tokens, merged before attention - Shared QK norms, YaRN RoPE with alpha/beta scaling, input_ids for modality mask **Vision Encoder** (27-block ViT, 1152 hidden, 16 heads): - Fused QKV + bias, LayerNorm + bias, patch_size=16, spatial merger (2x2 -> MLP) - 16384 position embeddings (128x128 grid) **Embedding**: Token lookup + CumSum-based image feature scatter (mask_init_id=12) ## Config Extraction HF config.json has no vision_config sub-object (flat config). Vision params hardcoded in _configs.py (like phi4mm). ## Test Results ### L1 - Graph builds: PASS ``` 4 passed (decoder prefill, decoder decode, vision_encoder, embedding) ``` ### L2 - YAML test case: PASS ``` testdata/cases/vision-language/hy-embodied-0_5-x.yaml 222 schema tests passed ``` ### CLI build with real weights: PASS ``` mobius build --model tencent/HY-Embodied-0.5-X /tmp/out Saved decoder to decoder/model.onnx Saved vision_encoder to vision_encoder/model.onnx Saved embedding to embedding/model.onnx ``` ### Multi-dtype: PASS ``` float32: 3 models built float16: 3 models built bfloat16: 3 models built ``` ### Weight loading: PASS All weights loaded. Only 1 unmatched: decoder.model.embed_tokens.weight (expected - tie_word_embeddings=true). ### L4/L5 Golden tests: SKIPPED **Reason**: HF repo auto_map references configuration_hunyuan_vl_mot.py / modeling_hunyuan_vl_mot.py but those files do not exist in the repo. The hunyuan_vl_mot model type is not in transformers 5.7.0. AutoModelForImageTextToText cannot load the model for HF reference inference. YAML test case has skip_reason documenting this. ## Files Changed | File | Change | |------|--------| | src/mobius/models/hunyuan_vl_mot.py | New model (~550 lines) | | src/mobius/tasks/_hunyuan_vl_mot.py | Custom task (adds input_ids for MoT routing) | | src/mobius/models/__init__.py | Export HunYuanVLMoTModel | | src/mobius/_registry.py | Register hunyuan_vl_mot | | src/mobius/_configs.py | Hardcoded vision config + QKV bias fallback | | tests/_test_configs.py | Tiny config for L1 tests | | testdata/cases/vision-language/hy-embodied-0_5-x.yaml | L4/L5 test case (skipped) | --------- Signed-off-by: Justin Chu <justinchu@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 03f524f commit 970cd41

8 files changed

Lines changed: 808 additions & 0 deletions

File tree

src/mobius/_configs.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,21 @@ def _extract_vision_config(config, parent_config, model_type: str) -> dict:
602602
image_token_id=getattr(config, "special_image_token_id", 200010),
603603
)
604604

605+
# HunYuan VL-MoT has a flat config.json with no vision_config sub-object.
606+
# The vision encoder params are hardcoded (InternViT-style ViT).
607+
if model_type == "hunyuan_vl_mot" and not vision_fields.get("hidden_size"):
608+
vision_fields.update(
609+
hidden_size=1152,
610+
intermediate_size=4304,
611+
num_hidden_layers=27,
612+
num_attention_heads=16,
613+
image_size=2048,
614+
patch_size=16,
615+
norm_eps=1e-6,
616+
spatial_merge_size=2,
617+
image_token_id=getattr(vision_source, "mask_init_id", 12),
618+
)
619+
605620
# InternVL2 doesn't expose image_token_id in its config — default to
606621
# the Qwen2 <IMG_CONTEXT> token id used by InternVL2-* models.
607622
parent_model_type = getattr(vision_source, "model_type", None)

src/mobius/_registry.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
GraniteMoECausalLMModel,
5454
HunYuanMoEV1CausalLMModel,
5555
HunYuanV1DenseCausalLMModel,
56+
HunYuanVLMoTModel,
5657
InternLM2CausalLMModel,
5758
LayerNormCausalLMModel,
5859
Llama4CausalLMModel,
@@ -473,6 +474,7 @@ def _detect_fallback_registration(hf_config) -> ModelRegistration | None:
473474
"glm4v_moe_text": ModelRegistration(Glm4MoECausalLMModel),
474475
"glm4v_text": ModelRegistration(Glm4CausalLMModel),
475476
"got_ocr2": ModelRegistration(LLaVAModel, task="vision-language"),
477+
"hunyuan_vl_mot": ModelRegistration(HunYuanVLMoTModel, task="hunyuan-vl-mot"),
476478
"idefics2": ModelRegistration(LLaVAModel, task="vision-language"),
477479
"idefics3": ModelRegistration(LLaVAModel, task="vision-language"),
478480
"instructblip": ModelRegistration(LLaVAModel, task="vision-language"),
@@ -835,6 +837,7 @@ def _create_default_registry() -> ModelRegistry:
835837
"glm4v_moe_text": "THUDM/glm-4v-9b",
836838
"glm4v_text": "THUDM/glm-4v-9b",
837839
"got_ocr2": "stepfun-ai/GOT-OCR2_0",
840+
"hunyuan_vl_mot": "tencent/HY-Embodied-0.5-X",
838841
"instructblipvideo": "Salesforce/instructblip-flan-t5-xl",
839842
"internvl": "OpenGVLab/InternVL2-1B",
840843
"internvl_chat": "OpenGVLab/InternVL-Chat-V1-5",

src/mobius/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"GraniteMoeHybridCausalLMModel",
5656
"HunYuanMoEV1CausalLMModel",
5757
"HunYuanV1DenseCausalLMModel",
58+
"HunYuanVLMoTModel",
5859
"HunyuanDiT2DModel",
5960
"IPAdapterModel",
6061
"InternLM2CausalLMModel",
@@ -172,6 +173,7 @@
172173
from mobius.models.granitemoehybrid import GraniteMoeHybridCausalLMModel
173174
from mobius.models.hunyuan_dit import HunyuanDiT2DModel
174175
from mobius.models.hunyuan_v1 import HunYuanV1DenseCausalLMModel
176+
from mobius.models.hunyuan_vl_mot import HunYuanVLMoTModel
175177
from mobius.models.internlm import InternLM2CausalLMModel
176178
from mobius.models.internvl import InternVL2Model
177179
from mobius.models.jamba import JambaCausalLMModel

0 commit comments

Comments
 (0)