llm.core.peft — Parameter-Efficient Fine-Tuning¶
The PEFT subpackage implements parameter-efficient fine-tuning methods
that train only a small set of additional parameters while keeping the
pretrained model frozen. All methods register into PEFT_REGISTRY and
can be applied via the training task configuration.
Overview¶
| Method | Paper | Trainable Parameters |
|---|---|---|
| LoRA | Hu et al. 2021 | Low-rank decomposition |
| QLoRA | Dettmers et al. 2023 | 4-bit NF4 + LoRA |
| AdaLoRA | He et al. 2022 | Adaptive rank LoRA |
| Prefix Tuning | Li & Liang 2021 | Virtual prefix tokens |
| IA³ | Liu et al. 2021 | Multiplicative scaling |
| BitFit | Zaken et al. 2021 | Bias-only |
| Adapter | Houlsby et al. 2019 | Bottleneck layers |
| Pfeiffer Adapter | Pfeiffer et al. 2021 | FFN-only bottleneck |
Registry¶
registry
¶
PEFT method registry and dispatch (T2 PEFT #43).
Mirrors :mod:llm.export.registry so third-party PEFT methods can
plug in via the llm.peft_methods setuptools entry-point group
without forking :mod:llm.core.peft.
Built-in methods
lora, qlora, adalora, prefix_tuning, ia3,
bitfit, adapter — registered eagerly by
:func:ensure_methods_registered.
Usage
import torch from llm.core.peft import apply_peft, count_peft_parameters model = torch.nn.Linear(10, 10) _ = apply_peft(model, "lora", rank=2, alpha=8.0) # wraps model in-place trainable, total = count_peft_parameters(model, "lora") trainable > 0, total > 0 (True, True)
Plugin authors register a method via pyproject.toml::
[project.entry-points."llm.peft_methods"]
my_method = "my_pkg.peft:build_my_peft_method"
The factory build_my_peft_method() must return a
:class:llm.core.peft.PEFTMethod instance. Built-ins are registered
before the entry-point load — a plugin claiming a built-in name is
silently skipped (matches the EXPORT_REGISTRY convention;
overwrite=True is reserved for explicit override paths).
ensure_methods_registered
¶
Idempotently register built-in methods and load entry points.
Built-ins are registered before the entry-point load so a
plugin that claims a built-in name raises / is silently skipped —
the built-in is the source of truth. This matches the convention
in :func:llm.export.registry.ensure_exporters_registered and
:func:llm.generation.registry.ensure_backends_registered.
源代码位于: src/llm/core/peft/registry.py
apply_peft
¶
Apply a registered PEFT method to model (in-place).
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
model
|
Module
|
The model to adapt. Modified in place by the per-method
|
必需 |
name
|
str
|
Registered method name (e.g. |
必需 |
**kwargs
|
Any
|
Method-specific kwargs forwarded verbatim to the
per-method |
{}
|
返回:
| 类型 | 描述 |
|---|---|
Module
|
The same |
引发:
| 类型 | 描述 |
|---|---|
ValueError
|
If |
TypeError
|
If the method's wrapper rejects the model shape (e.g. Prefix Tuning on a non-MHA base). |
源代码位于: src/llm/core/peft/registry.py
get_peft_parameters
¶
Yield the trainable parameters added by method name.
引发:
| 类型 | 描述 |
|---|---|
NotImplementedError
|
If the method doesn't expose a parameter
iterator (callers should fall back to
|
ValueError
|
If |
源代码位于: src/llm/core/peft/registry.py
count_peft_parameters
¶
Return (trainable, total) parameter counts for method name.
引发:
| 类型 | 描述 |
|---|---|
NotImplementedError
|
If the method doesn't expose a count helper. |
ValueError
|
If |
源代码位于: src/llm/core/peft/registry.py
merge_peft
¶
Inference-time fold of the adapter into the base weight.
引发:
| 类型 | 描述 |
|---|---|
NotImplementedError
|
For methods that don't fold (bitfit / qlora / prefix_tuning). |
ValueError
|
If |
源代码位于: src/llm/core/peft/registry.py
unmerge_peft
¶
Reverse a previous :func:merge_peft call.
引发:
| 类型 | 描述 |
|---|---|
NotImplementedError
|
For methods that don't expose merge / unmerge. |
ValueError
|
If |
源代码位于: src/llm/core/peft/registry.py
disable_peft
¶
Disable the adapter (e.g. for ablation studies).
引发:
| 类型 | 描述 |
|---|---|
NotImplementedError
|
For methods that don't expose a disable helper (bitfit / qlora / prefix_tuning). |
ValueError
|
If |
源代码位于: src/llm/core/peft/registry.py
enable_peft
¶
Re-enable a previously disabled adapter.
引发:
| 类型 | 描述 |
|---|---|
NotImplementedError
|
For methods that don't expose an enable helper (bitfit / qlora / prefix_tuning). |
ValueError
|
If |
源代码位于: src/llm/core/peft/registry.py
Method Types¶
types
¶
Public types for the PEFT registry (T2 PEFT #43).
The :class:PEFTMethod dataclass is the contract every PEFT method —
built-in or third-party plugin — must satisfy to register with
:data:llm.core.peft.registry.PEFT_REGISTRY.
Built-in PEFT methods expose asymmetric API surfaces:
lora/adalora/ia3/adapter: apply / get_parameters / count_parameters / merge / unmerge / disable / enable — the full setbitfit: apply / get_parameters / count_parameters — no merge (biases are kept at inference, no fold step)qlora: apply / get_parameters — no merge (NF4 quantized base cannot be re-folded into a float tensor)prefix_tuning: apply / get_parameters — inference-time fold is :func:llm.core.prefix_tuning.fold_reparameterization, not the merge/unmerge protocol
The dataclass accommodates all of these by making get_parameters /
count_parameters / merge / unmerge / disable / enable
:data:Optional. Callers that hit a None helper get a loud
NotImplementedError (see :mod:llm.core.peft.registry) instead of a
silent skip — the failure mode is the same as the per-method
apply_* raising TypeError on a non-MHA base.
TargetModuleFilter
¶
Bases: StrEnum
What kind of submodules a PEFT method targets.
Used as metadata only — the actual filter logic lives in the
per-method apply_* function (which already accepts a
target_modules substring list). The enum lets introspection /
docs report "this method wraps Linear layers" vs "this method
wraps Multi-Head Attention" without importing the method module.
Inherits from :class:enum.StrEnum so the values serialize
naturally to JSON strings (e.g. in the docs build or in
metadata.json snapshots).
源代码位于: src/llm/core/peft/types.py
PEFTMethod
dataclass
¶
The contract every PEFT method registers with the registry.
属性:
| 名称 | 类型 | 描述 |
|---|---|---|
name |
str
|
Unique registry name (e.g. |
apply |
Callable[..., Module]
|
|
get_parameters |
Callable[[Module], Iterator[Parameter | Tensor]] | None
|
|
count_parameters |
Callable[[Module], tuple[int, int]] | None
|
|
merge |
Callable[[Module], Module] | None
|
|
unmerge |
Callable[[Module], Module] | None
|
|
disable |
Callable[[Module], None] | None
|
|
enable |
Callable[[Module], None] | None
|
|
requires_callback |
bool
|
Whether the method needs a periodic trainer
callback. Currently only |
target_module_filter |
TargetModuleFilter
|
What kind of submodule the method
wraps. |
is_applied |
Callable[[Module], bool] | None
|
|
Notes
The dataclass is frozen=True — methods are registered
once at module import and never mutated. apply and the
helpers are stored as raw callables, not bound to the dataclass,
so is identity comparisons with the per-module functions
succeed (PEFT_REGISTRY.get("lora").apply is apply_lora).
源代码位于: src/llm/core/peft/types.py
Built-in Methods¶
methods
¶
Built-in PEFT method registrations (T2 PEFT #43).
Each entry is a thin wrapper around the existing module-level
apply_* / merge_* / etc. functions in llm.core.{lora, qlora,
adalora, prefix_tuning, ia3, bitfit, adapter}. The wrappers exist so
the registry can hold a uniform :class:PEFTMethod record for every
built-in — no behaviour is duplicated, and the per-method API surface
(asymmetric: lora has merge, bitfit doesn't, prefix_tuning has
fold_reparameterization instead of merge, etc.) is faithfully
recorded via the dataclass's Optional fields.
This module is imported lazily by :func:ensure_methods_registered —
not at package import time — so the PEFT registry stays opt-in and a
user who never touches PEFT pays no import cost.
iter_builtin_methods
¶
Return the list of built-in :class:PEFTMethod records.
Returned by value (not a generator) so callers can iterate
multiple times — used by :func:ensure_methods_registered to
populate the registry idempotently.
源代码位于: src/llm/core/peft/methods.py
Checkpoint Helpers¶
checkpoint
¶
PEFT adapter-only checkpoint save/load (T2 PEFT #47).
Saves ONLY the trainable adapter parameters added by a PEFT method — not the full model state — so adapters can be shared across runs (across checkpoints, across base models, across teams) without copying the (usually huge) base weights every time.
Storage format (torch.save):
{
"format_version": PEFT_CHECKPOINT_FORMAT_VERSION, # "1.0"
"method_name": "lora",
"peft_kwargs": {"rank": 8, "alpha": 16.0}, # informational
"state_dict": {
# positional keys: f"{method_name}.{idx}" for each adapter param
"lora.0": tensor,
"lora.1": tensor,
...
},
}
The keys are positional because the structural identity of adapter
parameters is unstable across processes (id() changes), but the
ORDER of :func:PEFTMethod.get_parameters output is deterministic
for the same model architecture + same apply kwargs. Loading matches
by position: saved tensor at index i lands in the model's
adapter parameter at index i.
The peft_kwargs dict is informational — :func:load_peft uses
it to re-apply the method when the model hasn't been wrapped yet
(common case for adapter sharing). The user can override individual
kwargs via :func:load_peft's **override_kwargs, but only
shape-preserving ones (e.g. alpha); a shape-defining override
(e.g. rank) raises a clear mismatch error — widening is not
implemented (RIL ISS-210).
Forward compatibility: bumping :data:PEFT_CHECKPOINT_FORMAT_VERSION
is the supported migration path. :func:load_peft rejects unknown
versions with a loud :class:ValueError.
save_peft
¶
Save only the adapter parameters added by method_name.
Writes a single torch.save-compatible file containing:
format_version: :data:PEFT_CHECKPOINT_FORMAT_VERSIONmethod_name: registered name (e.g."lora")peft_kwargs: kwargs the caller used (informational; used by :func:load_peftto re-apply the method on a fresh model)state_dict: the adapter parameters, keyed by position
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
model
|
Module
|
PEFT-applied model. Must have |
必需 |
path
|
str | Path
|
Destination path. Parent directories are created if they don't exist. |
必需 |
method_name
|
str
|
Registered method name (e.g. |
必需 |
**peft_kwargs
|
Any
|
Method-specific kwargs — stored in the
metadata envelope so :func: |
{}
|
返回:
| 类型 | 描述 |
|---|---|
Path
|
The resolved |
引发:
| 类型 | 描述 |
|---|---|
ValueError
|
If |
NotImplementedError
|
If the method doesn't expose
|
源代码位于: src/llm/core/peft/checkpoint.py
load_peft
¶
Load adapter parameters from path into model.
If the model hasn't had method_name applied yet (no wrappers
of the expected type), :func:apply_peft is called first using
the kwargs stored in the checkpoint — caller-supplied
override_kwargs take precedence over the saved kwargs.
参数:
| 名称 | 类型 | 描述 | 默认 |
|---|---|---|---|
model
|
Module
|
Destination model. If PEFT is not yet applied, it is
applied automatically using the checkpoint's saved
kwargs (overridable via |
必需 |
path
|
str | Path
|
Path to a file written by :func: |
必需 |
method_name
|
str
|
Expected method name — must match the
|
必需 |
**override_kwargs
|
Any
|
Override individual |
{}
|
返回:
| 类型 | 描述 |
|---|---|
Module
|
The same |
Module
|
byte-identically (chainable). |
引发:
| 类型 | 描述 |
|---|---|
FileNotFoundError
|
If |
ValueError
|
If the method name, format version, or parameter count doesn't match expectations. |
RuntimeError
|
If the model's adapter parameter count doesn't match the checkpoint (after re-applying if needed) — usually a sign the destination architecture differs from the source. |
源代码位于: src/llm/core/peft/checkpoint.py
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | |