Skip to content

[Bugfix][Model] Fix EXAONE-4.5 image inputs: ViT received un-normalised pixels - #61104

Merged
Isotr0py merged 4 commits into
vllm-project:mainfrom
Godmook:fix/exaone4_5-mm-input-norm
Oct 13, 2026
Merged

Isotr0py merged 4 commits into
vllm-project:mainfrom
Godmook:fix/exaone4_5-mm-input-norm

Conversation

@Godmook

@Godmook Godmook commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Overview

EXAONE-4.5 (Exaone4_5_ForConditionalGeneration) produces garbage for any request that contains an image on every release since #50411 (v0.29.0, v0.30.0, v0.31.0, main). Text-only requests are unaffected.

Root cause: the class inherits supports_mm_device_do_normalize = True from Qwen2_5_VLForConditionalGeneration, so mm_device_do_normalize defaults to on and the HF processor is told do_rescale=False, do_normalize=False. But EXAONE4_5_VisionTransformer is constructed without input_norm, so the inherited Qwen2_5_VisionTransformer uses IdentityInputNorm and the ViT receives raw 0–255 pixels.

Two smaller issues in the same constructor are fixed alongside, since they are the same missing wiring relative to the parent class:

  • self.model_config and self.video_pruning_rate are never set, but the inherited embed_multimodal / encoder-CUDA-graph paths read them (AttributeError with --compilation-config '{"cudagraph_mm_encoder": true}').
  • The MTP drafter (Exaone4_5MultiTokenPredictor) builds its Exaone4DecoderLayer without cache_config, so the drafter's attention ignores --kv-cache-dtype.

Claims

  • With the fix, image requests give coherent answers and are identical to the pre-[Model] Fused mm preprocess normalisation on the Device #50411 behaviour (processor-side normalisation); text-only outputs and MTP acceptance are unchanged.
  • No API change: the device-side normalisation feature stays on by default for this model, now with the correct normalisation module (build_mm_input_norm(model_config)), exactly as Qwen2_5_VLForConditionalGeneration does.
  • Users on affected releases can work around it with --no-mm-device-do-normalize.

Validation

LGAI-EXAONE/EXAONE-4.5-33B-FP8, TP=2, 2× A100-SXM4-40GB, greedy, thinking off, image = the model card's assets/exaone45_input1.jpg (a bowl of kimchi):

"Describe this image in one sentence." gsm8k-50 (text only)
main (default flags) The\n</think>\n</think>one\n</think>…/or/or/or/or/or… 0.90
this PR (default flags) A person in a light blue shirt is serving freshly made kimchi from a large black bowl into a smaller black dish, … 0.90

Second prompt ("What objects are in this image? List them.") shows the same pattern: /or/or/or… before, a correct itemised list (kimchi, dark ceramic bowl, …) after.

  • pre-commit passes (ruff, mypy, typos).
  • CI: the model is 33B and not in the multimodal generation test lists; the processing test (tests/models/multimodal/processing/test_common.py) already covers it and still passes.

Details

  • exaone4_5.py: EXAONE4_5_VisionTransformer.__init__ gains input_norm and forwards it to Qwen2_5_VisionTransformer; Exaone4_5_ForConditionalGeneration.__init__ passes input_norm=build_mm_input_norm(self.model_config) and sets self.model_config / self.video_pruning_rate like the parent.
  • exaone4_5_mtp.py: pass cache_config=vllm_config.cache_config to the MTP decoder layer.

Not in this PR (follow-ups): Exaone4Model lacks EagleModelMixin although the VLM advertises SupportsEagle3 (asserts at load); EXAONE4_5_VisionTransformer builds and discards the full Qwen2.5 MHA block stack in super().__init__ before replacing it with GQA blocks.

Duplicate-work check: no open PR or issue mentions EXAONE-4.5 image output, mm_device_do_normalize for EXAONE, or exaone4_5 (searched exaone4_5, EXAONE-4.5, mm_device_do_normalize input_norm; the closed #45071 / #42281 are different bugs).


Pull Request Checklist
  • I used vLLM's /pr-checklist skill. (Mandatory for agents, optional for humans).

  • AI assistance was used during the creation of this PR.

  • Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.

  • Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.

  • Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.

  • Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.

AI assistance was used while preparing this PR; I reviewed every changed line and ran all of the validation above myself.

Signed-off-by: godmook <cmoh4135@naver.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@mergify mergify Bot added the bug Something isn't working label Oct 11, 2026

@cjackal cjackal 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.

Thank you for the fix!

@cjackal cjackal added the ready ONLY add when PR is ready to merge/full CI is needed label Oct 12, 2026
@github-actions

Copy link
Copy Markdown

✅ @Godmook, CI is now available for this PR.

  • /ci run starts upstream CI; /amd-ci run starts AMD CI only.
  • Your branch must contain every commit currently on its upstream target branch. Merge or rebase onto the latest target branch, then rerun the command. Append --allow-stale to a run command to test an outdated branch at your own risk.
  • /ci retry retries failed jobs in the CI build for the current PR head. If the current head has no CI build, it starts a new CI build for the current head containing only jobs that failed in the latest earlier CI build for this PR.
  • /amd-ci retry retries failed jobs in AMD CI for the current PR head. Use /amd-ci run when the current head has no AMD CI build.
  • /ci cancel cancels scheduled or running CI builds for this PR branch; /amd-ci cancel does the same for AMD CI only.

@cjackal

cjackal commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #94285 for commit d54739336495.

@vllm-agent

Copy link
Copy Markdown
Collaborator

CI selector (shadow): 6 test steps (29 jobs) instead of 60 (92 jobs)

Shadow mode: this changes nothing about what CI runs. It shows what the evidence-based selector would pick for this PR, next to today's rules. How it works.

Feedback welcome: reply here if it would skip a step this change needs, or runs something unrelated.

steps (jobs) Today's rules Selector Would skip Would add
NVIDIA, CPU and others 60 (92) 6 (29) 57 (71) 3 (8)
AMD mirrors 58 (85) 2 (18) 56 (67) 0 (0)
Selector would run (6)
  • arm-cpu-test ×3
  • basic-models-tests-extra-initialization ×14
  • cpu-language-generation-and-pooling-model-tests ×3
  • cpu-multi-modal-model-tests-n ×4
  • cpu-spec-decode-tests
  • multi-modal-processor ×4
Would skip (today's rules run them) (57)
  • amd-lm-eval-small-models-harness
  • amd-qwen3-next-mtp-async-eplb-accuracy
  • ascend-npu-test
  • async-engine-inputs-utils-worker
  • basic-correctness ×2
  • basic-correctness-cpu-offload
  • basic-correctness-cumem
  • basic-correctness-prefetch-offload
  • basic-correctness-sleep-mode
  • basic-models-test-other-cpu
  • basic-models-tests-initialization
  • basic-models-tests-other
  • benchmarks-cli-test
  • distributed-model-tests-2-gpus ×3
  • entrypoints-integration-api-server ×4
  • entrypoints-integration-api-server-generate
  • entrypoints-integration-api-server-openai-chat_completion
  • entrypoints-integration-api-server-openai-completion
  • entrypoints-integration-llm
  • entrypoints-integration-multimodal
  • entrypoints-integration-pooling
  • entrypoints-integration-responses-api
  • entrypoints-integration-speech_to_text
  • fusion-e2e-quick-h100
  • fusion-e2e-tp2-b200
  • fusion-e2e-tp2-quick-h100
  • kernels-fla-ops-test-b200
  • kernels-mhc-test-b200
  • kernels-root-misc-test-b200
  • language-models-tests-extra-standard ×2
  • language-models-tests-granite-l4-compatibility
  • language-models-tests-hybrid ×2
  • language-models-tests-standard
  • metrics-tracing-2-gpus
  • model-executor
  • multi-modal-models-standard-1-qwen2
  • multi-modal-models-standard-2-qwen3-gemma
  • multi-modal-models-standard-3-llava-qwen2-vl
  • multi-modal-models-standard-4-other-whisper
  • multi-modal-processor-cpu ×4
  • pipeline-context-parallelism-4-gpus
  • pytorch-compilation-dynamic-shapes
  • pytorch-compilation-passes-unit-tests
  • pytorch-compilation-unit-tests
  • pytorch-compilation-unit-tests-h100
  • pytorch-fullgraph-cudagraph-l4-compatibility
  • pytorch-fullgraph-test
  • regression
  • rl-entrypoints-tests
  • v1-core
  • v1-executor-worker
  • v1-kv-connectors ×4
  • v1-kv-offload
  • v1-logits-oracle
  • v1-metrics-lmeval
  • v1-sample
  • v1-spec-decode
Would add (today's rules do not run them) (3)
  • arm-cpu-test ×3 (code map)
  • cpu-multi-modal-model-tests-n ×4 (code map)
  • cpu-spec-decode-tests (code map)
AMD mirrors: would skip (56)
  • async-engine-inputs-utils-worker
  • basic-correctness ×2
  • basic-correctness-cpu-offload
  • basic-correctness-cumem
  • basic-correctness-prefetch-offload
  • basic-correctness-sleep-mode
  • basic-models-tests-initialization
  • basic-models-tests-other
  • benchmarks-cli-test
  • distributed-model-tests-2-gpus ×3
  • entrypoints-integration-api-server ×4
  • entrypoints-integration-api-server-generate
  • entrypoints-integration-api-server-openai-chat_completion
  • entrypoints-integration-api-server-openai-completion
  • entrypoints-integration-llm
  • entrypoints-integration-multimodal
  • entrypoints-integration-pooling
  • entrypoints-integration-responses-api
  • entrypoints-integration-speech_to_text
  • fusion-e2e-quick-h100
  • fusion-e2e-tp2-ar-rms-config-sweep-h100
  • fusion-e2e-tp2-b200
  • fusion-e2e-tp2-quick-h100
  • kernels-fla-ops-test-b200
  • kernels-mhc-test-b200
  • kernels-root-misc-test-b200
  • language-models-tests-extra-standard ×2
  • language-models-tests-granite-l4-compatibility
  • language-models-tests-hybrid ×2
  • language-models-tests-standard
  • lm-eval-small-models
  • metrics-tracing-2-gpus
  • model-executor
  • mrcr-eval-small-models
  • multi-modal-models-standard-1-qwen2
  • multi-modal-models-standard-2-qwen3-gemma
  • multi-modal-models-standard-3-llava-qwen2-vl
  • multi-modal-models-standard-4-other-whisper
  • pipeline-context-parallelism-4-gpus
  • platform-tests
  • pytorch-compilation-dynamic-shapes
  • pytorch-compilation-passes-unit-tests
  • pytorch-compilation-unit-tests
  • pytorch-compilation-unit-tests-h100
  • pytorch-fullgraph-cudagraph-l4-compatibility
  • pytorch-fullgraph-test
  • regression
  • rl-entrypoints-tests
  • v1-core
  • v1-executor-worker
  • v1-kv-connectors ×4
  • v1-kv-offload
  • v1-logits-oracle
  • v1-metrics-lmeval
  • v1-sample
  • v1-spec-decode
AMD mirrors: would add (0)

none

2 changed files · base 56e3b081ae · head d547393364 · Python record: build 93039 at 1e5d0ea888 · kernel record: table 74f4404 (build 94125), map 74f4404 · not counted: 11 build steps, 5 A100 steps the generator no longer emits, 8 optional steps the selector would also run

@Godmook

Godmook commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor Author

I think CI is green. @cjackal Could you kindly merge it? Thanks!

@Isotr0py
Isotr0py merged commit 5555a2d into vllm-project:main Oct 13, 2026
153 checks passed
@Godmook
Godmook deleted the fix/exaone4_5-mm-input-norm branch October 13, 2026 05:13
AndreasKaratzas pushed a commit to AndreasKaratzas/vllm that referenced this pull request Oct 16, 2026
…ed pixels (vllm-project#61104)

Signed-off-by: godmook <cmoh4135@naver.com>
Co-authored-by: cjackal <44624812+cjackal@users.noreply.github.com>

Signed-off-by: Andreas Karatzas <AndreasKaratzas@users.noreply.github.com>
michael-gpu pushed a commit to practical-inference/vllm-ampere-extended that referenced this pull request Oct 20, 2026
…ed pixels (vllm-project#61104)

Signed-off-by: godmook <cmoh4135@naver.com>
Co-authored-by: cjackal <44624812+cjackal@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ready ONLY add when PR is ready to merge/full CI is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: EXAONE-4.5 Vision — unexpected keyword argument 'sequence_lengths' in Exaone4_5_VisionBlock.forward()

4 participants