Lora - #1647
Open
mi804 wants to merge 3 commits into
Open
Conversation
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.
PR Description: Replace peft with an in-repo LoRA training implementation
Summary
This PR removes the
peftdependency. LoRA training is now handled by a 60-line implementation inside the repository (diffsynth/core/lora_train/), which is behavior-equivalent topeftwhile dropping thedefaultadapter-name segment from checkpoint keys.Changes
1. In-repo LoRA injection
New
diffsynth/core/lora_train/patch.py(60 lines, depends only ontorch):LoRALinear: wraps the target layer asbase_layer, pluslora_A/lora_Bas plainnn.Linear(bias=False). NoModuleDict, sostate_dictkeys arelora_A.weightinstead of peft'slora_A.default.weight.inject_lora_into_model(): replaces matched modules in place, freezes everything else, and marks only the LoRA submodules trainable.lora_bias(zero-initialized bias onlora_B, mirroring peft) is supported at the layer level; nothing wires it yet.Details kept intentionally identical to peft, because they change results:
kaiming_uniform_(A, a=√5)+zeros_(B)performed on CPU in fp32, then cast — matching peft's RNG stream and rounding.base_out + lora_B(lora_A(x)) * scalingpromotes to the LoRA dtype and only casts back at the end. Rounding the delta first differs by ~0.03 in bf16.re.fullmatchpattern, a list matches by exact name or.-suffix.Two deliberate deviations from peft:
--lora_target_modules "to_q"matched nothing and raised.2. Checkpoint keys no longer contain
defaultDiffusionTrainingModule.add_lora_to_model()delegates to the new implementation; LoRA weights are created directly in the requested dtype instead of being injected and cast afterwards.mapping_lora_state_dict()now strips.default., so--lora_checkpointstill accepts checkpoints produced before this change.z_image_image2lora.py/qwen_image_image2lora.pyfollow the new naming.SdxlLoRAConverter/Krea2LoRAConverteropensource-format exporters (--align_to_opensource_format) updated to the new naming. Under the old naming these two crashed withUnboundLocalError, so this path is fixed rather than merely migrated.SingleMMDiTConfig.get()stub inkrea2_dit.py, which existed only for peft's config probing.peftremoved frompyproject.tomldependencies.Inference-side loading is unchanged and accepts both namings:
GeneralLoRALoader.get_name_dict()already dropped the adapter-name segment, which is why previously trained LoRAs still load for inference and for--lora_checkpointresume.3. Incidental fix: SDXL alpha key
In
SdxlLoRAConverter.align_to_diffsynth_format(),.replace("lora_A.weight", ".alpha")was missing a leading dot, so the alpha entry collided with thelora_Akey. When.alphawas iterated after.lora_down.weight, the alpha scalar overwrote thelora_Aweight (reproduced: shape became()). Fixed, so alpha is now applied asweight * alpha / rank.Verification
Unit level:
AutoWrappedLinear(VRAM management) as base layer, mixed dtype, fp8 base weights, optionallora_bias.torch.equal..default.; both namings resolve to the same 238 target modules.nn.Linearin default training,bitsandbytes.nn.Linear4bit(uint8 weights) under nf4, andAutoWrappedLinearonly under--fp8_models/--offload_models.Full trainings (official scripts, unmodified hyperparameters, 5 epochs):
defaultAlso run: Z-Image nf4 quantized training on 2 GPUs with DeepSpeed-free DDP, plus fuse / hot-load / legacy-checkpoint hot-load inference paths.
peft regression baselines (same official scripts, 5 epochs, injection monkeypatched back to
inject_adapter_in_model):.default., with no shape or dtype differences.Training flags and special paths (7 runs):
--enable_lora_hot_loading,--lora_checkpointresume from both new and legacy checkpoints,--preset_lora_path,--fp8_models, DeepSpeed ZeRO-2, andtask=trajectory_imitation(which deep-copies the whole pipeline after injection). All pass.Notes
--lora_checkpoint. They are not accepted by--resume_from_checkpoint, which does not normalize keys.examples/lingbot_video/model_training/scripts/prompt_rewriter.pystill importspeftlazily for a third-party VLM adapter; using that rewriter now requires installingpeftmanually.