Repository navigation
[Bugfix] Don't override an explicit text_config.tie_word_embeddings on transformers v5 multimodal configs - #46288
Closed
wentian-byte wants to merge 1 commit into
Conversation
wentian-byte
requested review from
ApostaC,
NickLucche,
ProExpertProg,
WoosukKwon,
houseroad,
mgoin,
njhill,
orozery,
robertgshaw2-redhat,
tlrmchlsmth,
xuechendi,
yewentao256 and
youkaichao
as code owners
June 21, 2026 13:49
When the multimodal hf_config's tie_word_embeddings differs from its text_config's, the latter is the one that reflects the checkpoint (Qwen2-Audio has an independent lm_head.weight, so text_config sets tie_word_embeddings=False even though the top-level Qwen2AudioConfig defaults to True). Blindly propagating the top-level default forces vLLM to alias lm_head to embed_tokens and skip lm_head weights, which breaks generation: the model emits prompt-special tokens (audio_bos / audio_eos) forever instead of text. Keep the propagation as a default-fill only when text_config is silent or already agrees. Signed-off-by: wentian-byte <192079369+wentian-byte@users.noreply.github.com>
wentian-byte
force-pushed
the
fix/qwen2-audio-mm-tie-word-embeddings-v2
branch
from
June 22, 2026 04:23
39faf3b to
25d37d3
Compare
Contributor
Author
|
Closing this in favor of a model-scoped fix.
|
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.
Purpose
On
transformers >= 5.0.0,Qwen/Qwen2-Audio-7B-Instruct(and any multimodal model whose top-leveltie_word_embeddingsdefaults differ from itstext_config's) produces garbage output: greedy decoding emits<|audio_bos|>/<|audio_eos|>repeatedly instead of text. This also makestests/samplers/test_beam_search.py::test_beam_search_passes_multimodal_datafail on transformers 5.x.The bug is not audio-specific — a plain text prompt to the same model (e.g.
"What is 2+2?") also emits 20 consecutive<|audio_eos|>tokens. I verifiedaudio_tower → multi_modal_projectorproduces byte-identical embeddings on4.55.0and5.10.2, so the audio path is fine.Root cause
VllmConfig.with_hf_confighas a transformers-v5 branch that propagates the top-leveltie_word_embeddingsflag onto the language-model'stext_config:That logic is correct when
text_configdoesn't already know the right answer. For Qwen2-Audio it backfires: the checkpoint ships an independentlm_head.weight, HF logs "both are present in the checkpoints with different values, so we will NOT tie them", andtext_config.tie_word_embeddings = Falsealready reflects that. But the top-levelQwen2AudioConfig.tie_word_embeddingsdefaults toTrue, so the unconditional propagation flips text_config fromFalse→True. vLLM's Qwen2 LM then takes thatTrueand goes down thelm_head = self.model.embed_tokens+skip_prefixes=["lm_head."]path, aliasinglm_head.weightin memory toembed_tokens.weightand silently dropping the reallm_head.weightfrom the safetensors. The result is logits in input-embedding space, which repeatedly re-emits whatever token last appeared in the prompt (here, the audio special tokens).Verified by reading
data_ptr()on the live model with the same checkpoint:embed_tokens.data_ptr == lm_head.data_ptrlm_headweight norm meanFix
Only propagate when
text_configis silent or already agrees with the top-level value. If they actively disagree, trusttext_config— that's the value vLLM's language-model code path reads when deciding how to buildlm_head, and for models like Qwen2-Audio it's the one that matches the checkpoint.if model_config.is_multimodal_model and hasattr( model_config.hf_config, "tie_word_embeddings" ): tie_word_embeddings = model_config.hf_config.tie_word_embeddings - hf_config.get_text_config().tie_word_embeddings = tie_word_embeddings + text_cfg = hf_config.get_text_config() + existing = getattr(text_cfg, "tie_word_embeddings", None) + if existing is None or existing == tie_word_embeddings: + text_cfg.tie_word_embeddings = tie_word_embeddingsThe original intent — fill
text_configwhen it would otherwise be missing the flag — is preserved.Test Plan
On
transformers==5.10.2, 1 × NVIDIA H20:vLLM output now matches the HF runner output for both beams; beam-0 transcribes the test audio correctly. Plain text prompt
"What is 2+2?"also recovers (was 20×<|audio_eos|>, now"2+2 equals 4.").Risk
top-level == text_config: unchanged.top-levelis set andtext_config.tie_word_embeddings is None(the case the existing code comment describes): unchanged — the propagation still fills it in.top-level != text_config.tie_word_embeddingsand both are set — precisely the Qwen2-Audio case. Here we respecttext_config, which is what the language-model code reads when buildinglm_head.