Fix LoRA IndexError when syncing weights to vLLM for Qwen models in GRPO colocate mode - #9946
Open
jinchenyu wants to merge 1 commit into
Open
Conversation
patched_load_adapter uses the model's hf_to_vllm_mapper as-is when building a LoRAModel from in-memory tensors, but for models like Qwen (whose mapper stacks q_proj/k_proj/v_proj into a single qkv_proj name for base-weight loading), this collapses the three distinct LoRA tensor names into one, silently overwriting each other. The result is a malformed LoRAModel that later raises "IndexError: tuple index out of range" from ColumnParallelLinearWithLoRA.set_lora() when the LoRA adapter is synced into the vLLM engine in GRPO colocate mode. vllm's own worker_manager._load_adapter already calls get_unstacked_mapper() before using the mapper for LoRA name parsing, so that constituent module names survive instead of being rewritten to the stacked vLLM name. Apply the same fix here.
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.
patched_load_adapter uses the model's hf_to_vllm_mapper as-is when building a LoRAModel from in-memory tensors, but for models like Qwen (whose mapper stacks q_proj/k_proj/v_proj into a single qkv_proj name for base-weight loading), this collapses the three distinct LoRA tensor names into one, silently overwriting each other. The result is a malformed LoRAModel that later raises
"IndexError: tuple index out of range" from
ColumnParallelLinearWithLoRA.set_lora() when the LoRA adapter is synced into the vLLM engine in GRPO colocate mode.
vllm's own worker_manager._load_adapter already calls get_unstacked_mapper() before using the mapper for LoRA name parsing, so that constituent module names survive instead of being rewritten to the stacked vLLM name. Apply the same fix here.
PR type
PR information
Problem
In GRPO's
vllm_mode=colocatewithvllm_enable_lora=true, syncing a LoRA adapter into the vLLM engine for Qwen-family models (Qwen2/Qwen3, whose base weights fuse q_proj/k_proj/v_proj into a single qkv_proj module) raises:at
ColumnParallelLinearWithLoRA.set_lora()on the very first LoRA sync.Reproduced with
vllm==0.26.0.Root cause
Qwen2Model.hf_to_vllm_mapper(inherited by Qwen3) defines a stacked mapping used for loading base checkpoint weights:patched_load_adapterpasses this mapper as-is viaweights_mapperintoLoRAModel.from_lora_tensors, which uses it to parse LoRA tensor names (parse_fine_tuned_lora_name). Because the mapper rewritesq_proj/k_proj/v_projall to the sameqkv_projname, the three distinct LoRA A/B tensors collapse into a single dict entry and overwrite each other. The resultingLoRAModelends up with a plain 2D tensor instead of thelistof per-shard tensors thatPackedLoRALayerWeights/set_lora()expect, so indexing into it raises theIndexError.This is purely a name-collision bug in the LoRA-name-parsing path — it does not depend on model size, only on the model family defining a stacked
hf_to_vllm_mapper(all Qwen2/Qwen3 sizes share the same mapper structure).Note:
hf_to_vllm_mapperis computed once and shared by both branches ofpatched_load_adapter— the in-memoryfrom_lora_tensorspath (used by GRPO colocate weight sync) and the on-diskfrom_local_checkpointpath — so this fix benefits both, not just the tensor-sync path.Fix
vllm's own
worker_manager._load_adapteravoids exactly this problem by callinghf_to_vllm_mapper.get_unstacked_mapper()before using the mapper for LoRA name parsing — this drops the QKV/MLP-fusion stacked maps while keeping genuine renames/prefixes, soq_proj/k_proj/v_projsurvive as distinct names for the LoRA manager to pack correctly. This PR applies the same call inpatched_load_adapter.get_unstacked_mapper()was introduced in a relatively recent vllm version; this fix guards withhasattr(hf_to_vllm_mapper, 'get_unstacked_mapper')so it stays a no-op (falling back to the original mapper) on older vllm versions that predate this method, rather than raisingAttributeError. For model families whosehf_to_vllm_mapperhas no stacked maps to begin with,get_unstacked_mapper()is itself a no-op, so this change carries no regression risk for non-Qwen models.Experiment results
Ran the LoRA + colocate GRPO smoke test (Qwen3-0.6B, gsm8k,
vllm_enable_lora=true,vllm_mode=colocate, 3 steps) withvllm==0.26.0. Note: the bug is a pure name-mapping collision independent of model scale — the samehf_to_vllm_mappercode path is shared by every Qwen2/Qwen3 size, so a smoke-scale model is sufficient to reproduce and verify the fix.Before the fix:
IndexError: tuple index out of rangeatColumnParallelLinearWithLoRA.set_lora()on the first LoRA sync into vLLM.After the fix: training completes all 3 steps without error, checkpoint saves successfully, loss/reward values are sane (no NaN):
Train: 100%|██████████| 3/3 [00:06<00:00, 2.09s/it]
{'train_runtime': '6.255', 'train_loss': '7.11e-06', ...}
[INFO:swift] Saving model checkpoint to .../checkpoint-3