LoRA
低秩自适应(LoRA)是一种 PEFT 方法,它将注意力层中的大型矩阵分解为两个较小的低秩矩阵。 这大大减少了需要微调的参数数量。
论文摘要如下:
我们提出了一种基于低秩自适应 (LoRA) 的神经语言建模系统,用于语音识别输出重评分。 尽管 BERT 等预训练语言模型 (LM) 在二次回合重评分中表现出优异的性能,但扩展预训练阶段和将预训练模型适应特定领域的巨大计算成本限制了它们在重评分中的实际应用。 在这里,我们提出了一种基于低秩分解的方法来训练重评分 BERT 模型,并使用仅占预训练参数一小部分 (0.08%) 的参数将其适应新领域。 这些插入的矩阵通过判别式训练目标以及基于相关性的正则化损失进行优化。 提出的低秩自适应 Rescore-BERT (LoRB) 架构在 LibriSpeech 和内部数据集上进行了评估,训练时间减少了 5.4 到 3.6 倍。.
LoraConfig
class peft.LoraConfig
< source >( peft_type: Union = None auto_mapping: Optional = None base_model_name_or_path: Optional = None revision: Optional = None task_type: Union = None inference_mode: bool = False r: int = 8 target_modules: Optional[Union[list[str], str]] = None lora_alpha: int = 8 lora_dropout: float = 0.0 fan_in_fan_out: bool = False bias: Literal['none', 'all', 'lora_only'] = 'none' use_rslora: bool = False modules_to_save: Optional[list[str]] = None init_lora_weights: bool | Literal['gaussian', 'olora', 'pissa', 'pissa_niter_[number of iters]', 'loftq'] = True layers_to_transform: Optional[Union[list[int], int]] = None layers_pattern: Optional[Union[list[str], str]] = None rank_pattern: Optional[dict] = <factory> alpha_pattern: Optional[dict] = <factory> megatron_config: Optional[dict] = None megatron_core: Optional[str] = 'megatron.core' loftq_config: Union[LoftQConfig, dict] = <factory> use_dora: bool = False layer_replication: Optional[list[tuple[int, int]]] = None runtime_config: LoraRuntimeConfig = <factory> )
参数
- r (
int
) — Lora 注意力维度(“秩”)。 - target_modules (
Optional[Union[List[str], str]]
) — 要应用适配器的模块名称。 如果指定了此参数,则仅替换具有指定名称的模块。 传递字符串时,将执行正则表达式匹配。 传递字符串列表时,将执行精确匹配,或者检查模块名称是否以传递的任何字符串结尾。 如果将其指定为“all-linear”,则选择所有线性/Conv1D 模块,但排除输出层。 如果未指定此参数,则将根据模型架构选择模块。 如果未知架构,则会引发错误 - 在这种情况下,您应该手动指定目标模块。 - lora_alpha (
int
) — Lora 缩放的 alpha 参数。 - lora_dropout (
float
) — Lora 层的 dropout 概率。 - fan_in_fan_out (
bool
) — 如果要替换的层存储类似 (fan_in, fan_out) 的权重,则将其设置为 True。 例如,gpt-2 使用Conv1D
,它存储类似 (fan_in, fan_out) 的权重,因此应将其设置为True
。 - bias (
str
) — LoRA 的偏差类型。 可以是 ‘none’、‘all’ 或 ‘lora_only’。 如果是 ‘all’ 或 ‘lora_only’,相应的偏差将在训练期间更新。 请注意,这意味着即使禁用了适配器,模型也不会产生与没有适应时的基本模型相同的输出。 - use_rslora (
bool
) — 当设置为 True 时,使用 Rank-Stabilized LoRA,它将适配器缩放因子设置为lora_alpha/math.sqrt(r)
,因为事实证明它效果更好。 否则,它将使用lora_alpha/r
的原始默认值。 - modules_to_save (
List[str]
) — 除了适配器层之外,要在最终检查点中设置为可训练并保存的模块列表。 - init_lora_weights (
bool
|Literal["gaussian", "olora", "pissa", "pissa_niter_[number of iters]", "loftq"]
) — 如何初始化适配器层的权重。 传入 True(默认值)会导致来自 Microsoft 参考实现的默认初始化。 传入 ‘gaussian’ 会导致按 LoRA 秩缩放的线性层和高斯初始化。 将初始化设置为 False 会导致完全随机的初始化,并且不建议这样做。 传递'loftq'
以使用 LoftQ 初始化。 传递'olora'
以使用 OLoRA 初始化。 传入 ‘pissa’ 会导致 Principal Singular values and Singular vectors Adaptation (PiSSA) 的初始化,它比 LoRA 收敛得更快,并且最终能获得更好的性能。 此外,与 QLoRA 相比,PiSSA 降低了量化误差,从而带来了进一步的增强。 传入'pissa_niter_[number of iters]'
会启动基于 Fast-SVD 的 PiSSA 初始化,其中[number of iters]
表示要执行 FSVD 的子空间迭代次数,并且必须是非负整数。 当[number of iters]
设置为 16 时,它可以在几秒钟内完成 7B 模型的初始化,并且训练效果与使用 SVD 大致相同。 - layers_to_transform (
Union[List[int], int]
) — 要转换的层索引。 如果传递了一个整数列表,它将对指定列表中的层索引应用适配器。 如果传递了一个整数,它将在该索引的层上应用转换。 - layers_pattern (
str
) — 层模式名称,仅在layers_to_transform
与None
不同时使用。 - rank_pattern (
dict
) — 来自层名称或正则表达式映射到与r
指定的默认秩不同的秩。 - alpha_pattern (
dict
) — 来自层名称或正则表达式映射到与lora_alpha
指定的默认 alpha 不同的 alpha。 - megatron_config (
Optional[dict]
) — Megatron 的 TransformerConfig 参数。用于创建 LoRA 的并行线性层。您可以像这样获取它,core_transformer_config_from_args(get_args())
,这两个函数来自 Megatron。这些参数将用于初始化 Megatron 的 TransformerConfig。当您想将 LoRA 应用于 megatron 的 ColumnParallelLinear 和 RowParallelLinear 层时,您需要指定此参数。 - megatron_core (
Optional[str]
) — 要使用的 Megatron 核心模块,默认为"megatron.core"
。 - loftq_config (
Optional[LoftQConfig]
) — LoftQ 的配置。如果它不为 None,则 LoftQ 将用于量化骨干权重并初始化 Lora 层。也传递init_lora_weights='loftq'
。请注意,在这种情况下,您不应该传递量化的模型,因为 LoftQ 会自己量化模型。 - use_dora (
bool
) — 启用“权重分解低秩自适应”(DoRA)。此技术将权重更新分解为两个部分,幅度和方向。方向由普通的 LoRA 处理,而幅度由单独的可学习参数处理。这可以提高 LoRA 的性能,尤其是在低秩的情况下。目前,DoRA 仅支持线性层和 Conv2D 层。DoRA 比纯 LoRA 引入了更大的开销,因此建议将权重合并以进行推断。有关更多信息,请参阅 https://arxiv.org/abs/2402.09353。 - layer_replication (
List[Tuple[int, int]]
) — 通过根据指定的范围堆叠原始模型层来构建新的层堆栈。这允许扩展(或缩小)模型而无需复制基本模型权重。所有新层都将有单独的 LoRA 适配器附加到它们。 - runtime_config (
LoraRuntimeConfig
) — 运行时配置(不会被保存或恢复)。
这是用于存储 LoraModel 配置的配置类。
将适配器模型的配置作为字典返回。删除运行时配置。
LoraModel
class peft.LoraModel
< source >( model config adapter_name ) → torch.nn.Module
从预训练的 transformers 模型创建低秩适配器 (LoRA) 模型。
该方法在 https://arxiv.org/abs/2106.09685 中有详细描述。
示例
>>> from transformers import AutoModelForSeq2SeqLM
>>> from peft import LoraModel, LoraConfig
>>> config = LoraConfig(
... task_type="SEQ_2_SEQ_LM",
... r=8,
... lora_alpha=32,
... target_modules=["q", "v"],
... lora_dropout=0.01,
... )
>>> model = AutoModelForSeq2SeqLM.from_pretrained("t5-base")
>>> lora_model = LoraModel(model, config, "default")
>>> import torch
>>> import transformers
>>> from peft import LoraConfig, PeftModel, get_peft_model, prepare_model_for_kbit_training
>>> rank = ...
>>> target_modules = ["q_proj", "k_proj", "v_proj", "out_proj", "fc_in", "fc_out", "wte"]
>>> config = LoraConfig(
... r=4, lora_alpha=16, target_modules=target_modules, lora_dropout=0.1, bias="none", task_type="CAUSAL_LM"
... )
>>> quantization_config = transformers.BitsAndBytesConfig(load_in_8bit=True)
>>> tokenizer = transformers.AutoTokenizer.from_pretrained(
... "kakaobrain/kogpt",
... revision="KoGPT6B-ryan1.5b-float16", # or float32 version: revision=KoGPT6B-ryan1.5b
... bos_token="[BOS]",
... eos_token="[EOS]",
... unk_token="[UNK]",
... pad_token="[PAD]",
... mask_token="[MASK]",
... )
>>> model = transformers.GPTJForCausalLM.from_pretrained(
... "kakaobrain/kogpt",
... revision="KoGPT6B-ryan1.5b-float16", # or float32 version: revision=KoGPT6B-ryan1.5b
... pad_token_id=tokenizer.eos_token_id,
... use_cache=False,
... device_map={"": rank},
... torch_dtype=torch.float16,
... quantization_config=quantization_config,
... )
>>> model = prepare_model_for_kbit_training(model)
>>> lora_model = get_peft_model(model, config)
属性:
- 模型 (PreTrainedModel) — 要适配的模型。
- peft_config (LoraConfig): Lora 模型的配置。
add_weighted_adapter
< 源代码 > ( adapters: list[str] weights: list[float] adapter_name: str combination_type: str = 'svd' svd_rank: int | None = None svd_clamp: int | None = None svd_full_matrices: bool = True svd_driver: str | None = None density: float | None = None majority_sign_method: Literal['total', 'frequency'] = 'total' )
参数
- 适配器 (
list
) — 要合并的适配器名称列表。 - 权重 (
list
) — 每个适配器的权重列表。 - 适配器名称 (
str
) — 新适配器的名称。 - 合并类型 (
str
) — 合并类型可以是 [svd
,linear
,cat
,ties
,ties_svd
,dare_ties
,dare_linear
,dare_ties_svd
,dare_linear_svd
,magnitude_prune
,magnitude_prune_svd
] 之一。当使用cat
合并类型时,生成的适配器的秩等于所有适配器秩的总和(混合适配器可能太大,导致 OOM 错误)。 - svd_rank (
int
, 可选) — svd 的输出适配器秩。如果未提供,将使用合并适配器的最大秩。 - svd_clamp (
float
, 可选) — 用于对 SVD 分解输出进行钳位的分位数阈值。如果提供 None,则不执行钳位。默认为 None。 svd_driver ( str
, 可选) — 要使用的 cuSOLVER 方法的名称。此关键字参数仅在 CUDA 上合并时有效。可以是 [None,gesvd
,gesvdj
,gesvda
] 之一。有关更多信息,请参考torch.linalg.svd
文档。默认值为 None。- density (
float
, 可选) — 0 到 1 之间的值。0 表示所有值都被修剪,1 表示没有值被修剪。应与 [ties
,ties_svd
,dare_ties
,dare_linear
,dare_ties_svd
,dare_linear_svd
,magnintude_prune
,magnitude_prune_svd
] 一起使用 - majority_sign_method (
str
) — 该方法应是 [“total”, “frequency”] 之一,用于获取符号值的幅度。应与 [ties
,ties_svd
,dare_ties
,dare_ties_svd
] 一起使用
此方法通过将给定的适配器与给定的权重合并来添加一个新的适配器。
使用 cat
combination_type 时,请注意,生成的适配器的秩将等于所有适配器秩的总和。因此,混合适配器可能变得太大,从而导致 OOM 错误。
删除现有适配器。
合并并卸载
< 源代码 > ( progressbar: bool = False safe_merge: bool = False adapter_names: Optional[list[str]] = None )
此方法将 LoRa 层合并到基础模型中。如果有人想将基础模型用作独立模型,则需要执行此操作。
示例
>>> from transformers import AutoModelForCausalLM
>>> from peft import PeftModel
>>> base_model = AutoModelForCausalLM.from_pretrained("tiiuae/falcon-40b")
>>> peft_model_id = "smangrul/falcon-40B-int4-peft-lora-sfttrainer-sample"
>>> model = PeftModel.from_pretrained(base_model, peft_model_id)
>>> merged_model = model.merge_and_unload()
set_adapter
< 源代码 > ( adapter_name: str | list[str] )
设置活动适配器。
此外,此函数将指定适配器设置为可训练的(即,requires_grad=True)。如果不需要,请使用以下代码。
subtract_mutated_init
< 源代码 > ( output_state_dict: dict[str, torch.Tensor] adapter_name: str kwargs = None )
此函数可以通过比较 output_state_dict
中的 [PiSSA | OLoRA] 适配器的参数与 adapter_name
中的 [PiSSA | OLoRA] 的初始值来计算 [PiSSA | OLoRA] 的更新,从而将 [PiSSA | OLoRA] 转换为 LoRA。
通过移除所有 LoRA 模块而不合并,来获取基础模型。这将返回原始的基础模型。
实用程序
peft.replace_lora_weights_loftq
< 源代码 > ( peft_model model_path: Optional[str] = None adapter_name: str = 'default' callback: Optional[Callable[[torch.nn.Module, str], bool]] = None )
使用 LoftQ 技术替换使用 bitsandbytes 量化的模型的 LoRA 权重。
替换是通过加载本地存储的 safetensors 模型文件中的非量化权重并在运行时初始化 LoRA 权重来完成的,从而最小化原始权重和量化权重之间的量化误差。
由于 pickle 不支持延迟加载,因此不支持正常的 PyTorch 检查点文件。
根据模型大小,调用此函数可能需要一些时间才能完成。