PhysicsNeMo PEFT - LoRA#1691
Conversation
Greptile SummaryThis PR adds
Important Files Changed
Reviews (2): Last reviewed commit: "minor bug fixes" | Re-trigger Greptile |
|
The general implementation structure looks modular and good to me. register_lora_wrappers will be useful. You may want to consider putting lora-related items into a folder called lora in case there will be non-lora peft approaches in the future. Utils can likely stay outside. The implementation differs in style compared to existing finetuning implementation in Alchemi. The closest one, for example, is patching module and it looks like this. This potentially needs to be resolved on the Alchemi side. In any case, your modular implementation should help. |
Thanks for your comment. I would hold the lora/ split until we add a second, non-variant method — at which point the clean factoring is method-agnostic core (targeting, I/O, registry, freeze, utils) vs. tuners/lora, tuners/, not just renaming files. Since the public API is the package |
|
Feature request to be added: Combining multiple LoRA adapters |
laserkelvin
left a comment
There was a problem hiding this comment.
I think on the whole, the general functionality makes sense to me - I've made some suggestions and raised some questions about the scope of the support (i.e. what kind of layers can we apply LoRA to and customizability)
The one other thing I wanted to ask about is user-facing documentation: I understand that the module is in experimental right now, but would be helpful to have something to specify user entrypoints into the interface, how it works, and what is and what isn't supported
|
@laserkelvin @ys-teh Thanks for thoroughly reviewing the PR and for your great comments. All of those are addressed now. The user documentation is also ready and will have its own PR to physicsnemo-docs. |
laserkelvin
left a comment
There was a problem hiding this comment.
LGTM, thanks for working through my comments!
ys-teh
left a comment
There was a problem hiding this comment.
Thanks for addressing the suggestions. Looks good.
|
/ok to test 4056322 |
|
/blossom-ci |
|
/ok to test 28fa765 |
|
/ok to test 0cd6ecc |
coreyjadams
left a comment
There was a problem hiding this comment.
Hi @mnabian overall I think the PR looks fine. Please add CODEOWNERS and consider where peft will eventually land in importlinter hierarchy in a release or two - probably right at the top?
To be concrete, though, the only change I request is codeowners.
|
/ok to test 515127e |
* peft initial commit * docstring enhancement * modify extension * formatting * minor bug fixes * address greptile comments * address review comments * address initialization issue * address docstring and other minor comments * address LinearLike comment * is_compatible check * update tests * update example, fix pickle issue in a test * make te optional * fix lint * add codeowner
PhysicsNeMo Pull Request
Description
Adds a native, self-contained Low-Rank Adaptation (LoRA) subpackage for
parameter-efficient fine-tuning of PhysicsNeMo models, shipped under
physicsnemo.experimental.peft, plus an end-to-end example and a user-guide page.LoRA freezes a pretrained model and trains only small low-rank adapter matrices
injected beside selected layers. This adapts a model to a new dataset at a
fraction of the cost of full fine-tuning, produces a tiny adapter checkpoint, lowers memory (frozen layers drop saved
activations), and reduces overfitting/forgetting in the small-data regime typical
of SciML.
Motivation
adapt a foundation checkpoint to a new vehicle class / chemistry / operating
condition from a handful of samples.
What's included
Package —
physicsnemo/experimental/peft/config.pyLoRAConfigdataclass + validationlora.pyLoRALayermixin,LoRALinear,LoRA_te_Linear,LoRA_te_LayerNormMLP, and the type→wrapper registry (register_lora_wrapper/get_wrapper_for)apply.pyapply_lora,resolve_targets,ApplyResult, freeze logic, guardsmerge.pymerge_loraio.pysave_adapter/load_adapter(adapter archive)utils.pysplit_params_for_optimizer,print_trainable_parameters,set_adapter_enabled,compute_base_fingerprintPublic API:
End-to-end example —
examples/cfd/external_aerodynamics/transformer_models/A separate, runnable LoRA recipe living alongside the existing GeoTransolver
training example (
train.pyis not modified):src/finetune.py— load a pretrained base →apply_lora→ train only theadapters (AdamW,
find_unused_parameters=True,DistributedSamplersharding)→
save_adapter.src/deploy.py—load_adapter(adapter-swap) ormerge_lora(fold in).conf/finetune_lora.yaml— reuses the example's model/data/training configgroups + a
peft:block.FINETUNE_LORA.md— full walkthrough; the main README cross-references it.Documentation
physicsnemo-docs/docs/user-guide/peft.rst— user-guide page (overview, when touse, the LoRA math, quickstart, layer targeting, optimizer setup, save/load,
merge, Transformer Engine support, extensibility, API reference), wired into the
User Guide toctree.
Quickstart
Layer targeting
A
LoRAConfigsets exactly one selector, matched against fully-qualifiedmodule names (leaf names are not unique):
target_modules— explicit list of namestarget_pattern— regex (re.search)target_filter— predicate(name, module) -> boolPlus two modifiers:
wrap_mlp(additively adapt the transformer feed-forwardsub-block) and
extras_trainable(modules to train fully, not low-rank). Onlyregistered layer types are eligible; a selector matching zero wrappable layers
raises (no silent misses).
Key design decisions
PeftModelwrapper.apply_loraswaps matchedleaves for LoRA wrappers and freezes the base; the model keeps its class and
identity, so existing
.mdluscheckpoint/inference tooling still works.torch.nn.Module— no dependency onphysicsnemo.Moduleorthe
.mdlusformat (a plain-PyTorch user can adapt their own model).te.Linearadapts per-matrix; the fusedte.LayerNormMLP(no addressable child Linears) adapts via a single rank-rresidual across the FFN sub-block (kept un-mergeable). The
te.LayerNormLinearoutput head is not wrapped in v1 (documented; future
register_lora_wrapper).adapter_config.json+adapter_model.pt+metadata.json) holding only the trainable slice. Disambiguated from full modelcheckpoints by
metadata.kind == "lora_adapter"and a structuralbase_fingerprint. Loaded only byload_adapter(withweights_only=True);recommended extension
.lora(any extension works) since it is neither atorch.savefile nor aModulecheckpoint.orthogonalization is degenerate on low-rank factors) — via
split_params_for_optimizer.type (equivariant, MoE, …) is one
register_lora_wrapper(type, wrapper)call,with no changes to targeting / apply / save / merge.
Validation
Tests (
test/experimental/peft/)42 tests across 7 files, run in-container on GPU + Transformer Engine; the
TE/GeoTransolver tests skip cleanly on CPU-only CI.
test_config.pyLoRAConfigvalidation (selectors, rank, dropout, reserved init)test_lora_linear.pyte.Linear+ fusedte.LayerNormMLPresidualtest_apply.pyextras_trainablenot unfreezing nested base, optimizer split,wrap_mlpexpansiontest_merge.pytest_io.pykindcheck, fingerprint mismatch,weights_onlyrejection of unsafe pickles, save-after-merge guardtest_smoke.pytest_geotransolver_lora.pyapply_lora+wrap_mlpon a real TE GeoTransolver (GPU+TE)Checklist
Dependencies
Review Process
All PRs are reviewed by the PhysicsNeMo team before merging.
Depending on which files are changed, GitHub may automatically assign a maintainer for review.
We are also testing AI-based code review tools (e.g., Greptile), which may add automated comments with a confidence score.
This score reflects the AI’s assessment of merge readiness and is not a qualitative judgment of your work, nor is
it an indication that the PR will be accepted / rejected.
AI-generated feedback should be reviewed critically for usefulness.
You are not required to respond to every AI comment, but they are intended to help both authors and reviewers.
Please react to Greptile comments with 👍 or 👎 to provide feedback on their accuracy.