fix(lora): write exported adapters in PEFT's key layout - #262
Open
SakaiXue6666 wants to merge 1 commit into
Open
fix(lora): write exported adapters in PEFT's key layout#262SakaiXue6666 wants to merge 1 commit into
SakaiXue6666 wants to merge 1 commit into
Conversation
_save_lora_to_checkpoint documents lora_adapter/ as a portable artifact for external use, loadable with peft.PeftModel.from_pretrained, but write_hf_peft_adapter saved AutoBridge's bare parameter names. PEFT keys carry the base_model.model. prefix of the wrapper module, so from_pretrained matches none of them: it warns about missing adapter keys and leaves every lora_B at zero, loading an adapter that does nothing. Normalize the keys on write. The transform is idempotent, so a state dict that is already in PEFT form passes through unchanged, and the SGLang transports are unaffected because they match on suffixes and a layer-index regex.
SakaiXue6666
force-pushed
the
fix/lora-adapter-peft-prefix
branch
from
August 11, 2026 14:38
9c3f0d6 to
547648f
Compare
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.
What
write_hf_peft_adapternow writes adapter tensors under PEFT'sbase_model.model.key layout, via a small idempotent helper (to_peft_state_dict). The exported directory becomes a standard PEFT adapter rather than one that only looks like it.Why
_save_lora_to_checkpointstates the contract for the directory it produces:The docs repeat it in
docs/{en,zh}/guide/low-rank-adaptation-training.md. The second sentence holds; the first does not.AutoBridge.export_adapter_weightsyields bare HF parameter names —model.layers.0.self_attn.q_proj.lora_A.weight, orthinker.model.layers...for a multimodal base such as Qwen3-Omni — andwrite_hf_peft_adapterhands them tosave_fileunchanged. PEFT, however, writes every key under the wrapper module it inserts, so its own files readbase_model.model.model.layers.0.self_attn.q_proj.lora_A.weight.The result is worse than a load error. Measured with
peft 0.20.0/transformers 5.6.0,PeftModel.from_pretrainedaccepts the directory, emits a singleUserWarning: Found missing adapter keys, and leaves everylora_Bat zero — an adapter that loads successfully and changes nothing. A user who exports a trained adapter and evaluates it through PEFT measures the base model and has only a warning to explain the result.The blast radius is narrow and worth stating explicitly:
torch_distcheckpoint, exactly as documentedlayers.(\d+)regex, so the prefix is immaterialSo the only behavior that changes is the one the artifact advertises and currently fails to deliver.
How
Add
PEFT_STATE_DICT_PREFIXandto_peft_state_dict, and apply the latter inwrite_hf_peft_adapterjust before serialization.The transform is idempotent: keys already carrying the prefix pass through untouched, so callers that hand over an exporter's output and callers that hand over an existing PEFT state dict converge on the same file. A submodel prefix such as Qwen3-Omni's
thinker.is part of the parameter path and stays inside the PEFT prefix, matching what PEFT itself would write for that base model.Scope was kept deliberately tight. The in-memory transport (
load_lora_adapter_from_tensors) is untouched, since SGLang is prefix-agnostic and there is no reason to perturb the per-step sync path to fix an artifact contract. Normalizing at the single point where bytes hit disk covers both writers — the checkpoint export and the live adapter directory — without changing any caller.Testing
Run inside the Relax training image (
sglang 0.5.12.post1,megatron.bridge 0.5.0,torch 2.11.0+cu129):Added
TestToPeftStateDict(bare names, a multimodalthinker.path, idempotency, tensor identity) and awrite_hf_peft_adaptercase asserting the exact key set on disk for a bare-named export. The existing round-trip test already passes prefixed keys and still passes unchanged, which is the idempotency guarantee stated above.ruff format --checkandruff checkare clean on both touched files.pre-commit run --all-filespasses (ruff format + ruff check run directly, see above)pytest tests/)Type of Change
Screenshots / Logs
Keys in
adapter_model.safetensorsfor the same exported adapter:Loading the "before" layout with PEFT, which is what the docstring recommends: