9 年前这篇论文悄悄给 LoRA 打了地基:1 个骨干 + 10 个"小挂件"就能服务 10 个视觉任务
- 关联论文:1705.08045
你有没有这种感觉——
你公司想做一个「能识别 100 类商品」的视觉模型。市面上每个公开数据集都只解决一小块:ImageNet 识别物体、交通标志识别、花卉识别、车型识别……
传统做法:为每个任务训一个完整模型,存 100 份权重,部署 100 个推理服务。
但你隐约觉得:这 100 个模型 90% 的参数应该都是一样的吧? 为什么不能共享?
arXiv 1705.08045(Residual Adapters, Rebuffi et al., Oxford VGG, NIPS 2017, 被引 1097 次)做了一件在 2017 年就给出 2025 年答案的事——
用一个共享骨干 + 每个任务不到 10% 的小适配器(adapter),让 1 个模型同时服务 10 个视觉任务,存储省 5 倍,效果还更好。
这套思路比 LoRA(2021)早了 4 年,比 Vision Transformer 适配器早了 3 年。 今天所有「参数高效微调」(PEFT)工具的祖宗,藏在这篇 9 年前的论文里。
为什么这件事值得大众关注
这套思路现在统治了整个 AI 工业界——
- 你手机里跑的「图像识别」APP,背后可能是同一套骨干 + 不同 adapter
- 大模型微调(LoRA / Adapter Tuning)的基本思想就是这套
- 多任务学习、参数高效迁移学习、模块化架构设计——全部可以追溯到 2017 年这篇论文
它解决的问题非常具体:「1 个模型如何同时学会 10 件事而不互相干扰」。
一句话故事
想象你是一个厨师,要会做 10 种菜:川菜、粤菜、湘菜、淮扬菜……
传统做法:学完川菜,脑子里全是川菜味;学粤菜,把川菜忘一半。10 种菜学完,前面 9 种都串味了。
Residual Adapters 的做法:你的「刀工」「火候」「调味」这些基本功(共享骨干)只练一次;每种菜的「独门配方」(adapter 参数)只有一点点。基本功共享,独门配方切换——10 种菜都做得好,脑子还没爆。
为什么 10 个独立模型是个问题
2017 年的标准范式是「ImageNet 预训练 + 任务 finetune」:
任务 1(识别猫狗)→ 训 ResNet-101 → 模型副本 1(4500 万参数)
任务 2(识别花卉)→ 训 ResNet-101 → 模型副本 2(4500 万参数)
...
任务 10(识别交通标志)→ 训 ResNet-101 → 模型副本 10(4500 万参数)
痛点:
- 存储爆炸:10 个任务 = 10 倍参数 = 4.5 亿参数只为 10 个分类器
- 推理路径无法共享:每来一张图,得想清楚走哪个模型,调度复杂
- 新任务加一个模型副本:永远线性增长
核心观察:这 10 个 ResNet-101 虽然是分开训的,但前 90% 的层学到的「视觉特征」几乎一样——边缘、纹理、形状——都是相通的。只有最后几层在适应每个任务的「特化」。
Residual Adapters 到底做了什么
核心思想:主干共享 + 小挂件特化
论文把标准 ResNet 的残差块(residual block)改造成这样:
原来的 ResNet 块: 改造后的 ResNet-Adapter 块:
y = ReLU(w2 · ReLU(w1·x)) y = ReLU(共享(w1,w2) + α_任务 × 适配器分支 + x)
↑ ↑
主干 90% 参数 每任务 <10% 参数
关键设计:
- 共享主干(w1, w2):90% 的参数,所有任务共用
- 任务特异 adapter(α):每个任务独立的一小组参数(<10%)
- 推理时切换:换任务只换 α,不换主干
伪代码(核心 10 行)
class ResidualAdapterBlock(nn.Module):
def __init__(self):
self.shared = 主干卷积(w1, w2) # 90% 参数,所有任务共用
self.adapters = {任务ID: α_w, α_bn} # 每个任务一组小参数
def forward(self, x, task_id):
# 共享路径(与任务无关)
shared = self.shared(x)
# 适配器路径(按任务 ID 切换)
α = self.adapters[task_id]
adapted = F.relu(α.bn(α.conv(x)))
# 残差合并
return F.relu(shared + adapted + x)
看起来简单,但带来了三个革命性的好处:
- 参数省 5 倍:1 个主干(4500 万)+ 10 个 adapter(每任务 450 万)= 9000 万 vs 10 个独立模型 4.5 亿
- 运行时切换:部署时只换 α,不重新加载模型
- 训练友好:adapter 用更高学习率,骨干用原学习率微调——收敛更快
Visual Decathlon:论文自带的「奥运会」基准
光说参数省不行,得证明效果也保得住。论文设计了 Visual Decathlon——10 个视觉数据集的「十项全能」比赛:
| 数据集 | 任务类型 |
|---|---|
| ImageNet | 通用物体分类(1000 类) |
| Omniglot | 手写字符(小样本) |
| Traffic Signs | 交通标志 |
| Aircraft | 飞机型号细粒度 |
| VGG Flowers | 花卉分类 |
| Cars | 车型识别 |
| Leaves-Plants | 叶片植物分类 |
| Caltech-101 | 通用物体(101 类) |
| Caltech-256 | 通用物体(256 类) |
| SVHN | 街景门牌号 |
评分公式 S = 1000 × Σ (e_max / e_model),满分 10000:
- 基线 2500:10 个独立 finetune 模型的总分
- S = 2113:只共享骨干(无 adapter)——低于基线
- S = 2641:Residual Adapter 联合训练——超过 2500 基线
关键结论:一个模型 + 10 个小 adapter,「标称性能」比 10 个独立模型还强。这不是「差不多」,是「更好」。
它跟同类工作的关系
前驱 / 同期
- Hard Parameter Sharing(多任务经典方法):所有层共享,简单但任务多时负迁移
- Cross-Stitch Networks(Misra 2017):同年工作,用 α 矩阵线性组合多个网络
- PackNet(2017):同期「剪枝 + 冻结」做序列多任务
Residual Adapters 的差异化:用「残差分支」而不是「线性组合」或「剪枝」,结构更简单,参数更省。
后续发展(这条思路至今仍在演化)
- LoRA(Microsoft 2021):把 adapter 思想搬到 LLM,用「低秩矩阵」替代卷积分支,参数效率更进一步
- Adapter Tuning(Houlsby 2019, NLP):在 Transformer 里插 bottleneck MLP(降维 → ReLU → 升维)
- Prefix Tuning / Prompt Tuning(2021):不训 adapter,改训 prompt 前缀,更省参数
- Vision Transformer Adapters(2021-):把 adapter 思想搬到 ViT,现在是主流
- QLoRA / LongLoRA / DoRA:各种 LoRA 变体,2024-2026 仍在持续改进
结论:2017 年这篇论文的思想,是今天所有 PEFT(参数高效微调)技术的「祖宗」。
对工程落地的启发
启发 1:1 个骨干服务 N 个任务的部署范式
如果你公司有多个视觉任务(产品分类、缺陷检测、文字识别……),不要为每个任务训一个完整模型。
正确做法:
1 个骨干(4500 万参数)
+ N 个 adapter(每任务 450 万参数)
= 总参数 9000 万
= 原本 10 个模型(4.5 亿)的 1/5
部署侧:服务侧 N 个任务只需 N × 10% 的额外显存,骨干权重复用 → 存储减少 5 倍。
启发 2:用「统一评分」比较多任务系统
论文提的 S 评分(一个标量就能比 N 个独立模型)值得在自家多任务系统里复用:
S = 1000 × Σ (基线误差 / 当前模型误差)
好处:不必每个任务都画 ROC,一个数就能说清「联合训练比单任务好多少」。
启发 3:adapter 的「通道压缩」是省参关键
如果你要复现 adapter 思想,最容易踩的坑是:
- 错误实现:adapter 通道数 = 主干通道数 → adapter 参数膨胀到 15-20% → 失去「省参数」卖点
- 正确实现:用 bottleneck adapter(通道压到 1/r,r=4 或 8)→ adapter 参数降至 ~5%
细节决定成败。
启发 4:BN 必须按任务独立
多任务同时训练时,每个任务的 BN(Batch Normalization)统计量会被其他任务污染,验证精度会掉 1-3pp。
正确做法:保留任务独立 BN(每个任务 α_BN_scale/bias 各一组),推理时按 task_id 切换。
启发 5:联合训练 ≠ 顺序训练
如果你想「先训任务 A,再训任务 B」——会灾难遗忘:A 上精度掉 20%+。
正确做法:必须用联合训练(每 batch 从 10 个任务采样),或加 EWC/MAS 风格正则。
⚠️ 边界坑(部署前必看)
- S 评分的 ×2 系数未经验证:论文把「单任务误差 ×2」作为基线误差,但这个系数是自定义的,未有后续工作系统性验证。若有人复现 S=2400 可能是系数选择不同而非方法差。
- 10 个数据集规模差异导致 S 评分被大任务主导:ImageNet(130 万)对 S 贡献 ≈ 10× Omniglot(3.2 万),小任务几乎不影响 S 总量。建议同时报告 per-task accuracy。
- 联合训练 FLOPs 无节省:论文方法的训练成本与顺序全量 finetune 等量级——并没有「省训」,只是「省推理参数」。
- GitHub 代码链接状态不明:原文只说「matconvnet + PyTorch 参考实现」,未给出明确 URL。优先参考 2018 TPAMI 版(serial adapter 改进版)。
- 任务域单一:10 个数据集全是图像分类,未验证检测/分割/视频等 dense prediction 任务。
- adapter 推理路径未真正「切换」:用 for 循环按任务切换 α,每次前向重新装参,吞吐下降。修复:把 N 个 α 拼成 batch 维度一次性前向,或用 task_id → α_lookup 表预编译。
- 学习率策略敏感:α 参数与骨干用同一学习率时,α 收敛慢、骨干过拟合。修复:α 用更高学习率(激进更新),骨干用原 lr 微调。
🎯 你能立即做的事
- 如果你公司有 N 个视觉分类任务:评估是否可以用 1 个骨干 + N 个 adapter 替代 N 个独立模型
- 如果用 LoRA 微调大模型:回看一下 2017 年这篇,理解「参数高效」的本质是「主干共享 + 小特化」
- 如果做多任务评测:用 S 评分公式(误差比例聚合)替代每个任务单独画图,一个数就能说清整体水平
- 如果做 vision PEFT 工具:把 bottleneck adapter(1/r 通道压缩)作为默认实现,避免参数膨胀
一句话总结
Residual Adapters 用 1 个共享骨干 + 10 个任务特异的小挂件(<10% 参数),让 1 个模型同时服务 10 个视觉任务,存储省 5 倍,效果比 10 个独立模型还好——这套思路比 LoRA 早 4 年,是今天所有参数高效微调(PEFT)技术的祖宗。一篇 9 年前的论文,至今仍在 GPT / ViT / 多模态模型的工程实践中发挥影响。
三个标题变体
- LoRA 的「爷爷」长什么样:9 年前这篇论文,用 1 个骨干 + 10 个小挂件省了 5 倍存储 🧬
- 1 个模型打 10 个任务,效果比 10 个独立模型还好:Oxford 团队 2017 年的工程范式革命 🚀
- 你手机里的 AI 视觉识别,背后可能就是这套 2017 年的设计 —— 它比 LoRA 还早 4 年 📱
📱 小红书风格卡片文案(直接可用)
姐妹们听我说 🧬
你公司想做一个「能识别 100 类商品」的视觉模型,传统做法是训 100 个独立模型,存 100 份权重。
但你隐约觉得 —— 这 100 个模型 90% 参数应该都一样吧?
arXiv 1705.08045(Residual Adapters, Oxford VGG, NIPS 2017)说:
1 个共享骨干(90% 参数)+ 10 个任务小挂件(每任务 <10% 参数)= 1 个模型同时打 10 个任务,存储省 5 倍,效果还更好。
就这么简单 ✨
📊 关键数字:Visual Decathlon 评分 2641 > 2500 基线 —— 一个模型比 10 个独立模型还强。
这套思路:
- 比 LoRA(2021)早 4 年 🏆
- 比 Vision Transformer 适配器早 3 年 🏆
- 是今天所有 PEFT(参数高效微调) 技术的祖宗
今天 GPT / ViT / 多模态模型的工程实践,都有这篇 9 年前论文的影子。
NeurIPS 2017 · 被引 1097 次 · 一个模型 = 10 个模型 + 更好的效果 🚀
⚠️ 注意:S 评分基线系数未经验证,单任务精度需独立报告
LoRA #PEFT #多任务学习 #视觉模型 #深度学习 #ResNet #论文解读 #AI #arXiv #Adapter #参数高效 #Oxford
关联论文:1705.08045(点格式)
科普版:/shared/research-kb/organized/promo/popular/1705-08045.md