# AdaMSS

[AdaMSS](https://openreview.net/forum?id=8ZdWmpYxT0)（AdaMSS: Adaptive Multi-Subspace Approach for Parameter-Efficient Fine-Tuning）是一种参数高效微调方法，它利用 SVD 对权重矩阵进行分解，并将分解后的空间聚类为多个可训练子空间。每个子空间学习独立的低秩更新，同时原始权重保持冻结。AdaMSS 还支持自适应子空间分配（ASA），该方法基于梯度信息在训练过程中动态剪除重要性较低的子空间。

该论文的摘要如下：

> 我们提出了 AdaMSS，一种用于大模型参数高效微调的自适应多子空间方法。与传统在单个大型网络权重子空间内运行的参数高效微调方法不同，AdaMSS 利用子空间分割来获取多个较小的子空间，并在训练过程中自适应地减少可训练参数的数量，最终仅更新与目标下游任务最相关的一小部分子空间所关联的参数。通过使用最低秩表示，AdaMSS 实现了更紧凑的表达力和对模型参数更精细的调整。理论分析表明，与 LoRA、PiSSA 以及其他基于单子空间低秩的方法相比，AdaMSS 具有更好的泛化保证。在图像分类、自然语言理解和自然语言生成任务上的大量实验表明，AdaMSS 在大多数情况下达到了与全量微调相当的性能，并优于其他参数高效微调方法，同时所需的可训练参数更少。值得注意的是，在 ViT-Large 模型上，AdaMSS 在七个任务中的平均准确率比 LoRA 高出 4.7%，而使用的可训练参数仅为后者的 15.4%。在 RoBERTa-Large 上，AdaMSS 在六个任务中的平均准确率比 PiSSA 高出 7%，同时将可训练参数数量减少了约 94.4%。这些结果证明了 AdaMSS 在参数高效微调中的有效性。AdaMSS 的代码可在 https: //github.com/jzheng20/AdaMSS 获取。

AdaMSS 目前存在以下限制：
- 仅支持 `nn.Linear` 层。
- KMeans 聚类步骤需要 scikit-learn。

如果这些约束条件不适用于您的使用场景，请考虑采用其他方法。

## 基准测试概览

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

# API

## AdamssConfig[[peft.AdamssConfig]]

#### peft.AdamssConfig[[peft.AdamssConfig]]

```python
peft.AdamssConfig(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, r: int = 100, num_subspaces: int = 5, subspace_rank: int = 1, target_modules: Optional[Union[list[str], str]] = None, init_weights: Optional[Literal['orthogonal']] = 'orthogonal', modules_to_save: Optional[list[str]] = None, layers_to_transform: Optional[Union[list[int], int]] = None, layers_pattern: Optional[Union[list[str], str]] = None, use_asa: bool = False, asa_target_subspaces: int = 50, init_warmup: int = 50, final_warmup: int = 1000, mask_interval: int = 100, asa_importance_beta: float = 0.85, asa_uncertainty_beta: float = 0.85, asa_schedule_exponent: float = 3.0, use_dynamic_rank: bool = False, svd_threshold: float = 0.1, random_seed: int = 0)
```

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

**参数：**

r (`int`) : SVD 分解的总秩（论文中记为 R）。它决定了在聚类之前用于表示权重矩阵的奇异向量数量。较高的值能捕获原始权重中更多的信息，但需要更多的计算和内存。较低的值提供更强的正则化。典型值范围为 50 到 500。默认值为 100。

num_subspaces (`int`) : 将 SVD 分解空间聚类成的子空间数量 (K)。每个子空间学习独立的低秩更新。增加此值可以实现更细粒度的适应，但可训练参数数量会成比例增加。当使用 ASA（自适应子空间分配）时，此值决定了剪枝前的初始子空间数量。典型取值范围为 3 到 10。默认值为 5。

subspace_rank (`int`) : 每个可训练子空间的秩 (r_i)。这控制每个子空间学习适配的容量。较高的值会增加表达能力，但也会增加可训练参数。总可训练参数按 O(num_subspaces * subspace_rank * (in_dim + out_dim) / num_subspaces) 缩放。对于大多数任务，1-4 的值效果良好。默认为 1。

target_modules (`Optional[Union[list[str], str]]`) : 要应用 AdaMSS 的模块名称。如果指定，则仅会适配这些模块。可以是精确模块名称的列表，也可以是正则表达式。例如，对于注意力层，使用 `['q_proj', 'v_proj']`；对于正则匹配，使用 `'.*decoder.*(SelfAttention|EncDecAttention).*(q|v)$'`。

modules_to_save (`Optional[list[str]]`) : 除 AdaMSS 层外，需要设置为可训练并保存在最终检查点中的模块列表。这些模块将接受完全微调（而不仅仅是低秩微调）。对于分类任务中随机初始化的头部（如 `classifier` 或 `score`），此项为必填。

init_weights (`Literal["orthogonal"]`) : AdaMSS 可训练权重的初始化方法。目前仅支持 "orthogonal"，该方法对 B 矩阵（输出投影）使用正交初始化。A 矩阵初始化为零，以确保模型从预训练权重开始。从检查点加载时，将其设置为 None 可跳过初始化。默认值为 "orthogonal"。

layers_to_transform (`Optional[Union[list[int], int]]`) : 要应用 AdaMSS 的特定层索引。如果指定，则仅这些层会被适配，适用于实验哪些层从适配中获益最多。可以是单个整数或整数列表。

layers_pattern (`Optional[Union[list[str], str]]`) : 当指定 `layers_to_transform` 时，用于匹配层名称的模式。用于从不符合常见模式的模块名称中提取层索引。

use_asa (`bool`) : 是否启用自适应子空间分配（ASA）。启用后，ASA 会根据梯度信息在训练过程中动态剪枝重要性较低的子空间，在保持性能的同时减少有效参数量。需要与训练回调集成。默认值为 False。

asa_target_subspaces (`int`) : 当启用 ASA 时，所有层中活跃子空间的总目标数量。ASA 会逐步修剪子空间，直到达到此目标。值越低，修剪越激进，可训练参数越少。该值应小于 `num_subspaces * num_target_modules`。根据模型大小，典型值范围在 20 到 100 之间。默认值为 50。当 `use_asa=True` 时，必须为正整数。

init_warmup (`int`) : 开始 ASA 剪枝前需要等待的训练步数。在预热期间，所有子空间保持激活状态，以便重要性分数趋于稳定。较高的值能为准确的重要性估计提供更多时间，但会延迟剪枝。典型值范围为 50 到 200。默认值为 50。当 `use_asa=True` 时，必须小于 `final_warmup`。

final_warmup (`int`) : ASA 完成剪枝并达到 `asa_target_subspaces` 个活跃子空间的训练步数。剪枝过程分布在 `init_warmup` 和 `final_warmup` 之间。应根据总训练步数进行设置；通常为总训练步数的 1/3 到 1/2。默认值为 1000。当 `use_asa=True` 时，必须大于 `init_warmup`。

mask_interval (`int`) : ASA 掩码更新之间的训练步数。较小的值允许更频繁的自适应，但会增加开销。较大的值在更新之间提供更稳定的重要性估计。典型值范围为 50 到 200。默认值为 100。当 `use_asa=True` 时，必须为正整数。

asa_importance_beta (`float`) : 用于平滑子空间重要性分数的指数移动平均（EMA）系数。较高的值（接近 1.0）会赋予历史重要性更高的权重，从而提供稳定性。较低的数值会使重要性对近期梯度更加敏感。典型取值范围为 0.8 到 0.95。默认值为 0.85。

asa_uncertainty_beta (`float`) : 用于平滑重要性不确定性估计的 EMA 系数。控制不确定性对梯度方差的适应速度。与 asa_importance_beta 类似，较高的值可提供更稳定的估计。典型取值范围为 0.8 到 0.95。默认值为 0.85。

asa_schedule_exponent (`float`) : 控制 ASA 预热期间从总子空间衰减至 `asa_target_subspaces` 的速率的调度指数。较高的值会导致更快的初始剪枝（更激进的早期缩减），而较低的值则提供更平缓、类似线性的衰减。公式为：current_active_subspaces = asa_target_subspaces + (asa_total_subspaces - asa_target_subspaces) * (progress ** exponent)。典型值范围从 1.0（线性）到 5.0（激进）。默认值为 3.0。当 `use_asa=True` 时，必须为正数（零或负指数要么使调度退化为永久无效操作，要么在 `progress` 恰好达到 0.0 时引发 `ZeroDivisionError`）。

use_dynamic_rank (`bool`) : 是否根据奇异值的大小动态确定子空间秩。当为 True 时，每个子空间的秩通过统计高于阈值的奇异值数量来确定，从而允许不同子空间具有不同的有效秩。当为 False 时，所有子空间均使用固定的 `subspace_rank`。默认值为 False。

svd_threshold (`float`) : 动态秩选择的阈值比率，仅在 `use_dynamic_rank=True` 时使用。如果奇异值超过 `threshold * max_singular_value`，则被视为显著。较高的值会导致更低的实际秩（更激进的截断）。典型值范围为 0.05 到 0.2。默认值为 0.1（最大值的 10%）。

Adamss（自适应多子空间）方法的配置类。

AdaMSS 是一种参数高效微调方法，它使用 SVD 分解权重矩阵，并将分解后的空间聚类为多个可训练子空间。它在这些子空间内学习低秩更新，同时保持原始权重冻结。

## AdamssModel[[peft.AdamssModel]]

#### peft.AdamssModel[[peft.AdamssModel]]

```python
peft.AdamssModel(model, config, adapter_name, low_cpu_mem_usage: bool = False, state_dict: Optional[dict] = None)
```

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

**参数：**

model (`torch.nn.Module`)：要适配的模型。

config (`AdamssConfig`)：Adamss 模型的配置。

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

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

Adamss 模型。

从预训练模型创建 Adamss（自适应多子空间）模型。

该方法使用 SVD 分解权重矩阵，并将分解后的空间聚类为多个可训练子空间，以实现参数高效微调。

示例：
```python
>>> from transformers import AutoModelForImageClassification
>>> from peft import AdamssConfig, get_peft_model

>>> config = AdamssConfig(
...     r=500,
...     num_subspaces=5,
...     target_modules=["query", "value"],
... )

>>> model = AutoModelForImageClassification.from_pretrained("google/vit-base-patch16-224")
>>> adamss_model = get_peft_model(model, config)
```

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

#### update_and_allocate[[peft.AdamssModel.update_and_allocate]]

```python
update_and_allocate(global_step: int)
```

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

**参数：**

global_step (*int*) : 当前训练步数。

更新重要性分数并应用 ASA 掩码（如果已启用）。

启用 ASA 时，应在 `loss.backward()` 之后、`optimizer.zero_grad()` 之前，在 **每个** 训练步骤中调用此方法。其内部执行以下操作：

1. 在预热期间，每个步骤都通过 EMA 累积重要性分数。
2. 在掩码间隔处，应用全局 top-K 掩码并重置重要性。

这是 ASA 的唯一入口点 – 在 HuggingFace `Trainer` 中使用 `AdamssAsaCallback` 时，只是简单地委托给此方法。对于自定义训练循环，请直接调用此方法，而不是使用回调。

示例：

```python
for step, batch in enumerate(dataloader):
loss = model(**batch).loss loss.backward() optimizer.step() model.base_model.update_and_allocate(step)
optimizer.zero_grad()
```

