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 |
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.