从重参数走到高效:AI IA3笔记

LoRA 已经用了一阵,参数省了不少,但当我看到 IA3(Infused Adapter by Inhibiting and Amplifying Internal Activations)只给每个注意力头和前馈层加几个可学习的缩放向量时,我很好奇——这真的够用吗?

我遇到的情况很典型:有个 7B 规模的基础模型,需要在特定领域做微调,但只有一张 24GB 显存的卡。

背景与问题

我遇到的情况很典型:有个 7B 规模的基础模型,需要在特定领域做微调,但只有一张 24GB 显存的卡。用全量微调直接爆显存,用 LoRA 虽然能跑,但 rank 设置和位置选择是个玄学。

这个时候 IA3 进入了视野。它的核心想法非常直接:

  • 不要给模型加额外的层(像传统 Adapter)
  • 也不要引入低秩分解(像 LoRA)
  • 而是在注意力机制的 Q、K、V 以及前馈网络的中间层上,直接乘以一个可学习的缩放向量

人话讲就是:原始模型的权重冻结不动,只学几个"放大/缩小"系数,通过这些系数来控制每个维度的重要性。

这个想法听起来太简单了,简单到让人怀疑它的有效性。但看到它只增加了不到 0.1% 的参数量就能取得接近全量微调的效果时,我还是决定试一试。

实现思路

核心原理

在 Transformer 的注意力层和前馈层中,IA3 引入了可学习的缩放向量 l

  • 对于注意力层,在 Q、K、V 计算后分别乘以对应的缩放向量
  • 对于前馈层,在第一个线性变换的输出后乘以缩放向量
  • 所有原始权重保持冻结,只训练这些缩放向量

用个简单的示意来表示:

graph LR A[输入] --> B[原始 Q 投影] B --> C[× l_Q] C --> D[注意力计算] A --> E[原始 K 投影] E --> F[× l_K] F --> D A --> G[原始 V 投影] G --> H[× l_V] H --> D D --> I[前馈网络] I --> J[× l_ffn] J --> K[输出]

这个图的意思是:原始的计算路径不变,只是在一些关键位置插入了可学习的缩放。训练时只更新这些 l 向量,推理时把它们"融合"进原始权重,保持计算效率。

为什么要这么做

理解这一点很重要:缩放向量本质上是让模型"学会"应该放大哪些特征、抑制哪些特征。在某些任务上,有些维度可能根本不重要,只需要把它们压到接近 0;而在关键维度上,可能需要更强的激活。

这和传统的 Dropout 或 LayerNorm 有个本质区别:这里的缩放是任务相关的、可学习的,而不是数据无关的正则。

实践过程

环境与准备

我用的环境比较常规:

  • PyTorch 2.1.0
  • Transformers 4.35.0
  • PEFT 库(已经内置了 IA3 支持)
  • 单张 RTX 3090(24GB)

数据集是一个中文领域的问答任务,训练样本约 5 万条。

模型选择与配置

一开始我犯了个错:直接用了一个较大的模型(13B),结果显存虽然勉强够用,但训练速度太慢。后来换回 7B 规模才找到平衡点。

from peft import IA3Config, get_peft_model

# IA3 配置
ia3_config = IA3Config(
    target_modules=["k_proj", "v_proj", "down_proj"],  # 选择应用位置
    feedforward_modules=["down_proj"],  # 前馈层的位置
    ia3_dropout=0.05,  # 适度 dropout 防止过拟合
    fan_in_fan_out=False,  # 跟随原模型配置
    init_ia3_weights=True,  # 初始化为 1,保证初期行为接近原始模型
)

这里的 target_modules 选择是个重点。我一开始想把所有 Q、K、V 都加上,后来发现只保留 K 和 V 就够了,Q 的影响相对较小。前馈层只选了 down_proj,因为这里的维度变化更关键。

训练配置

训练参数的调整过程有点曲折:

  • 学习率:从 1e-4 开始,训练了几个 epoch 后发现收敛太慢,调到 3e-4 效果更好
  • Batch size:受限于显存,只能设到 8,用梯度累积等效到 32
  • Epoch:跑了 3 个 epoch,第 2 个 epoch 后性能就基本稳定了
  • Warmup:用了 10% 的步数,发现不 warmup 直接训容易前期震荡
training_args = TrainingArguments(
    output_dir="./ia3-7b-qa",
    learning_rate=3e-4,
    per_device_train_batch_size=8,
    gradient_accumulation_steps=4,
    num_train_epochs=3,
    warmup_steps=0.1,
    logging_steps=10,
    save_steps=500,
    fp16=True,
    gradient_checkpointing=True,  # 节省显存
)

踩坑记录

显存不够

第一轮训练时显存直接爆了。原因是我忘记开启 gradient_checkpointing,而且 ia3_dropout 没设置导致临时显存占用过大。开启 checkpoint 后,训练 batch 8 终于能跑起来了。

收敛慢且不稳定

初期训练 loss 下降很慢,而且波动很大。排查发现:

  1. 学习率太低(1e-4),调到 3e-4 后改善明显
  2. 数据 shuffle 做得不好,有些 batch 质量差异大
  3. 某些任务的样本分布不均,需要做简单的过采样

推理速度慢

训练完成后直接用 PEFT 模型推理,发现比原模型慢了不少。这是因为 PEFT 的推理实现没有做权重融合。后来手动合并权重后,推理速度基本恢复到原模型水平。

from peft import PeftModel

# 加载基础模型
base_model = AutoModelForCausalLM.from_pretrained("base-7b")

# 加载 IA3 权重
model = PeftModel.from_pretrained(base_model, "./ia3-7b-qa")

# 合并权重(推理用)
merged_model = model.merge_and_unload()
merged_model.save_pretrained("./ia3-7b-qa-merged")

结果与对比

训练完成后,我在验证集上测了几个指标:

方法可训练参数准确率显存占用训练时间
全量微调7B87.3%22GB8h
LoRA (rank=64)135M86.5%16GB4h
IA33.5M85.8%14GB3.5h
基础模型(不微调)072.1%12GB-

把准确率与可训练参数量放在同一张图里,能直观看到 IA3 用极少参数逼近 LoRA 和全量微调的表现。

全量微调、LoRA 与 IA3 在验证集准确率和可训练参数量上的对比

IA3 的可训练参数仅为 LoRA 的约 2.6%,准确率差距不到 1 个百分点,对单卡 24GB 场景是很划算的 trade-off。

有趣的是,在特定类型的样本上(比如长文本推理任务),IA3 的表现反而超过了 LoRA。我猜这可能是因为缩放机制在某些维度上能更灵活地调节,而低秩约束可能会限制表达空间。

实际部署中的考虑

真正把模型投入使用时,还有几个细节需要注意:

  1. 权重融合的必要性:如果直接用 PEFT 包装的模型推理,每次前向传播都会有额外的开销。必须提前合并权重,这样推理时的计算图和原模型完全一致。

  2. 多 LoRA 与 IA3 的对比:如果你需要在同一基础模型上适配多个任务,LoRA 的优势在于可以加载不同的 LoRA 权重而不冲突。IA3 虽然参数少,但多任务场景下要分别存储完整的缩放向量集合。

  3. 量化兼容性:在尝试 INT8 量化时,IA3 的表现比 LoRA 稳定一些。这可能是因为缩放向量的数值范围相对可控,不像低秩矩阵那样容易在量化后损失信息。

  4. 训练监控:由于 IA3 可训练参数很少,传统的 weight decay 和正则手段效果有限。更多应该关注训练 loss 的平滑程度和验证集指标的稳定性,而不是盯着权重变化。

写在最后

这次折腾 IA3 的过程,给我最大的感受是:有时候最简单的想法反而最有效。不需要复杂的架构设计,不需要大量的参数,只要在正确的地方施加正确的约束,就能取得不错的效果。

当然,IA3 不是银弹。如果你的任务对表达能力要求很高,或者数据量非常充足,全量微调可能仍然是上限最高的选择。但在资源受限、需要快速迭代、或者需要在同一基础模型上适配多个任务时,IA3 确实提供了一个优雅且实用的方案。

如果你也在为模型微调的参数和效率发愁,不妨试试 IA3。说不定会像我一样,发现"少一点"真的可以"更好一点"。


参考资源:

  • IA3 原始论文:Few-Shot Parameter-Efficient Fine-Tuning is Better and Cheaper than In-Context Learning
  • Hugging Face PEFT 文档
  • 实验代码和配置已整理至项目仓库

版权声明: 本文首发于 指尖魔法屋-从重参数走到高效:AI IA3笔记https://blog.thinkmoon.cn/post/390-ai-ia3-reparameterization-efficient-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!