# LoHa

    

探索文本到图像生成的定制化：从 LyCORIS 微调至模型评估

低秩哈达玛积（[LoHa](https://huggingface.co/papers/2108.06098)）与 LoRA 类似，但它使用更多低秩矩阵来近似大型权重矩阵，并通过哈达玛积将它们组合起来。该方法比 LoRA 具有更高的参数效率，并能实现相当的性能。LoHa 最初是为联邦学习（FedPara）提出的，但作为一种通用的 PEFT 方法表现良好，尤其常用于微调 Stable Diffusion 等图像生成模型。

> **注意：**LoHa 是 [LyCORIS](./adapter_utils) 适配器家族的一部分。其近亲 [LoKr](./lokr) 使用 Kronecker 积而非 Hadamard 积。

该论文的摘要如下：

*在本工作中，我们提出了一种通信高效的参数化方法 FedPara，用于联邦学习（FL），以克服频繁上传和下载模型所带来的负担。我们的方法使用低秩权重，随后进行 Hadamard 积，对层的权重参数进行重参数化。与传统的低秩参数化相比，我们的 FedPara 方法不受低秩约束的限制，因此具有远大的容量。这一特性使其能够在通信成本比原始层模型低 3 到 10 倍的情况下实现可比的性能，而这是传统低秩方法无法实现的。通过将我们的方法与其他高效的 FL 优化器结合，可以进一步提高其效率。此外，我们将该方法扩展到个性化联邦学习应用 pFedPara，该方法将参数分为全局参数和局部参数。我们证明，pFedPara 在参数数量减少三倍以上的前提下，性能优于其他竞争性个性化联邦学习方法。*

低秩分解可能会影响性能，因为权重更新被限制在低秩空间内，这可能会限制模型的表达能力。然而，你并不一定希望使用更大的秩，因为这会增加可训练参数的数量。为了解决这个问题，LoHa 被应用于扩散模型，因为在这些模型中，生成多样化图像的能力是一个重要的考量因素。LoHa 也应该适用于通用模型类型，但 PEFT 目前尚未实现对嵌入层的支持。

LoHa 使用 [Hadamard 积](https://en.wikipedia.org/wiki/Hadamard_product_(matrices))（逐元素乘积）代替矩阵乘积。与 LoRA 类似，$\Delta W$ 由四个较小的矩阵表示，而不是两个，并且这些低秩矩阵中的每一对都通过 Hadamard 积进行组合。因此，$\Delta W$ 可以拥有相同数量的可训练参数，但具有更高的秩和表达能力。

## 何时使用 LoHa

LoHa 在以下情况下是一个不错的选择：

- 您正在微调**图像生成模型**（Stable Diffusion UNet 或文本编码器），这是其最广泛的应用场景。
- 与 LoRA 相比，在相同数量的可训练参数下，你希望获得**更高的有效秩**，因为两个低秩矩阵的哈达玛积所张成的子空间比单个低秩乘积更大。
- 您希望在推理时使用 [`PeftMixedModel`](./peft_model#peft.PeftMixedModel) **组合不同的 PEFT 方法**，例如将 LoHa 与 LoKr 一起使用。

LoHa 支持线性层和 Conv2d 层。对于还需要适配嵌入层的任务，请考虑使用 [LoRA](./lora)。

## 用法

```python
from diffusers import StableDiffusionPipeline
from peft import LoHaConfig, get_peft_model

config_unet = LoHaConfig(
    r=8,
    alpha=8,
    target_modules=[
        "to_k",
        "to_q",
        "to_v",
        "to_out.0",
        "proj_in",
        "proj_out",
    ],
    rank_dropout=0.0,
    module_dropout=0.0,
    use_effective_conv2d=True,
)

pipeline = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
pipeline.unet = get_peft_model(pipeline.unet, config_unet)
pipeline.unet.print_healthcheck()
```

## 基准测试概览

<iframe src="https://peft-internal-testing-peft-method-comparison-embed.hf.space/?highlight[type]=LOHA" frameborder="0" width="850" height="1000"
>

# API

## LoHaConfig[[peft.LoHaConfig]]

#### peft.LoHaConfig[[peft.LoHaConfig]]

```python
peft.LoHaConfig(task_type: Optional[Union[str, TaskType]] = None, peft_type: Optional[Union[str, PeftType]] = None, auto_mapping: Optional[dict] = None, peft_version: Optional[str] = None, base_model_name_or_path: Optional[str] = None, revision: Optional[str] = None, inference_mode: bool = False, rank_pattern: Optional[dict] = <factory>, alpha_pattern: Optional[dict] = <factory>, r: int = 8, alpha: int = 8, rank_dropout: float = 0.0, module_dropout: float = 0.0, use_effective_conv2d: bool = False, target_modules: Optional[Union[list[str], str]] = None, exclude_modules: Optional[Union[list[str], str]] = None, init_weights: bool = True, layers_to_transform: Optional[Union[list[int], int]] = None, layers_pattern: Optional[Union[list[str], str]] = None, modules_to_save: Optional[list[str]] = None)
```

[源代码](https://github.com/huggingface/peft/blob/main/src/peft/tuners/loha/config.py#L24)

**参数：**

r (`int`) : LoHa 秩。

alpha (`int`) : LoHa 缩放的 alpha 参数。

rank_dropout (`float`) : 训练期间秩维度的 dropout 概率。

module_dropout (`float`) : 训练期间禁用 LoHa 模块的 dropout 概率。

use_effective_conv2d (`bool`) : 对 ksize > 1 的 Conv2d（以及 Conv1d）使用参数有效分解（FedPara 论文中的“命题 3”）。

target_modules (`Optional[Union[List[str], str]]`) : 要应用适配器的模块名称。如果指定了此参数，则只有名称匹配的模块会被替换。传入字符串时，将执行正则表达式匹配。传入字符串列表时，将执行精确匹配，或检查模块名称是否以传入的任一字符串结尾。如果指定为 'all-linear'，则选择所有线性/Conv1D 模块，但不包括输出层。如果未指定，则根据模型架构选择模块。如果架构未知，则会引发错误——在这种情况下，应手动指定目标模块。

exclude_modules (`Optional[Union[List[str], str]]`) : 不应用适配器的模块名称。传入字符串时，将执行正则表达式匹配。传入字符串列表时，将执行精确匹配，或检查模块名称是否以传入的任一字符串结尾。

init_weights (`bool`) : 是否执行适配器权重的初始化。默认值为 `True`，不建议传入 `False`。

layers_to_transform (`Union[List[int], int]`) : 要转换的层索引。如果传入一个整数列表，则会将适配器应用于该列表中指定的层索引。如果传入单个整数，则会对该索引处的层应用转换。

layers_pattern (`Optional[Union[List[str], str]]`) : 层模式名称，仅在 `layers_to_transform` 不同于 `None` 时使用。它应指向模型的 `nn.ModuleList`，通常命名为 `'layers'` 或 `'h'`。

rank_pattern (`dict`) : 从层名称或正则表达式到与 `r` 指定的默认 rank 不同的 rank 的映射。例如，`{'^model.decoder.layers.0.encoder_attn.k_proj': 16}`。

alpha_pattern (`dict`) : 从层名称或正则表达式到与 `alpha` 指定的默认 alpha 不同的 alpha 值的映射。例如，`{'^model.decoder.layers.0.encoder_attn.k_proj': 16}`。

modules_to_save (`Optional[List[str]]`) : 除适配器层外，需要设置为可训练并保存在最终检查点中的模块列表。

这是用于存储 [LoHaModel](/docs/peft/main/zh/package_reference/loha#peft.LoHaModel) 配置的类。

## LoHaModel[[peft.LoHaModel]]

#### peft.LoHaModel[[peft.LoHaModel]]

```python
peft.LoHaModel(model, peft_config: Union[PeftConfig, dict[str, PeftConfig]], adapter_name: str, low_cpu_mem_usage: bool = False, state_dict: Optional[dict[str, torch.Tensor]] = None)
```

[源代码](https://github.com/huggingface/peft/blob/main/src/peft/tuners/loha/model.py#L27)

**参数：**

model (`torch.nn.Module`)：将挂载适配器调优层的模型。

config ([LoHaConfig](/docs/peft/main/zh/package_reference/loha#peft.LoHaConfig))：LoHa 模型的配置。

adapter_name (`str`) : 适配器的名称，默认为 `"default"`。

low_cpu_mem_usage (`bool`, `optional`, 默认为 `False`) : 在 meta 设备上创建空的适配器权重。有助于加快加载过程。

**返回：** `torch.nn.Module`

LoHa 模型。

从预训练模型创建低秩哈达玛积（Low-Rank Hadamard Product）模型。该方法在 https://huggingface.co/papers/2108.06098 中有部分描述。当前实现大量借鉴自 https://github.com/KohakuBlueleaf/LyCORIS/blob/eb460098187f752a5d66406d3affade6f0a07ece/lycoris/modules/loha.py

示例：
```py
>>> from diffusers import StableDiffusionPipeline
>>> from peft import LoHaConfig, get_peft_model

>>> config_te = LoHaConfig(
...     r=8,
...     alpha=32,
...     target_modules=["k_proj", "q_proj", "v_proj", "out_proj", "fc1", "fc2"],
...     rank_dropout=0.0,
...     module_dropout=0.0,
...     init_weights=True,
... )
>>> config_unet = LoHaConfig(
...     r=8,
...     alpha=32,
...     target_modules=[
...         "proj_in",
...         "proj_out",
...         "to_k",
...         "to_q",
...         "to_v",
...         "to_out.0",
...         "ff.net.0.proj",
...         "ff.net.2",
...     ],
...     rank_dropout=0.0,
...     module_dropout=0.0,
...     init_weights=True,
...     use_effective_conv2d=True,
... )

>>> model = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
>>> model.text_encoder = get_peft_model(model.text_encoder, config_te)
>>> model.unet = get_peft_model(model.unet, config_unet)
```

**属性**：
- **model** (`~torch.nn.Module`) -- 要适配的模型。
- **peft_config** ([LoHaConfig](/docs/peft/main/zh/package_reference/loha#peft.LoHaConfig)): LoHa 模型的配置。

