在AI视觉领域,图像恢复(去雨、去模糊)长期面临一个两难选择:要么模型太笨重(Transformer),要么效率高但效果差(CNN)。CVPR 2025的论文《ACL: Activating Capability of Linear Attention for Image Restoration》给出了一个巧妙的折中方案——用线性注意力替代Mamba和Softmax Attention,在保持高精度的同时大幅降低计算成本。本文带你拆解其核心思路与工程价值。
1️⃣ 问题背景:图像恢复的“不可能三角”
图像恢复任务(如去雨、去模糊)要求模型同时具备大感受野(捕捉全局上下文)和低计算量(便于部署)。过去几年,主流方案大致分为三类:
- CNN路线:局部建模强,但长距离依赖弱。
- Transformer路线:全局建模强,但Softmax Attention的计算量随分辨率平方增长。
- Mamba路线:试图平衡效率与全局建模,但原始结构是为一维序列设计的,直接用于二维图像会带来三个问题:
⚠️ 一维扫描不天然适合图像空间关系
⚠️ 多方向扫描补丁让结构复杂化
⚠️ 递归式计算仍影响效率
ACL的核心问题就是:
能不能保留 Mamba 风格的高效框架,同时用线性注意力来承担更自然的全局像素依赖建模?
2️⃣ 核心思路:全局+局部的清晰分工
ACL的答案可以概括为一句话:
用 Linear Attention 替换 Mamba 中的 SSM 核心,再用多尺度空洞卷积补足局部细节恢复能力。
具体来说,它设计了两个核心模块:
- LAMA (LA-based Mamba Module):将线性注意力嵌入Mamba风格框架,负责建立全局像素依赖。
- MDC (Multi-Dilated Convolutions Module):通过多尺度空洞卷积增强局部细节(边缘、纹理)建模。
这种分工非常清晰:全局关系交给线性注意力,局部细节交给多尺度卷积。它没有把所有能力塞进一个模块,而是让每个组件做自己最擅长的事。
3️⃣ 模型结构:Encoder-Decoder + 三尺度输出
ACL整体是一个标准的编码器-解码器框架,采用三尺度输出设计。其结构可以理解为:
输入退化图像
↓
Conv Stem
↓
Encoder 1 ── LAMA × N + MDC
↓
Encoder 2 ── LAMA × N + MDC
↓
Encoder 3 ── LAMA × N
↓
Bottleneck
↓
Decoder 3 ── LAMA × N
↓
Decoder 2 ── LAMA × N + Skip + MDC
↓
Decoder 1 ── LAMA × N + Skip + MDC
↓
多尺度重建输出
关键特点包括:
- 编码器逐步聚合更大范围信息。
- 解码器逐步恢复空间分辨率。
- 跳跃连接保留浅层细节(边缘、纹理)。
- MDC主要放在高分辨率阶段,针对性增强局部信息。
4️⃣ LAMA模块:线性注意力如何“激活”能力?
LAMA是ACL的核心创新。它将输入特征分为两条路径:
- 残差分支:生成门控信息(类似调制项)。
- 主分支:先做特征映射和卷积,再进入线性注意力部分,建立大范围依赖。
与标准Softmax Attention相比,线性注意力的核心优势是计算复杂度线性增长,非常适合大分辨率图像。两条分支融合后,通过线性层和前馈网络输出,既利用注意力建立全局依赖,又保持模块稳定性。
为什么线性注意力以前不够强?ACL认为:问题不在LA本身,而在于它没被放在合适的框架里。
5️⃣ MDC模块:为什么局部细节不能少?
很多人容易把重点全放在线性注意力上,但MDC同样重要。原因很简单:
图像恢复不只是“看得远”,还要“看得细”。
注意力擅长建立大范围依赖,但图像恢复的视觉质量还取决于:
- 边缘锐度
- 纹理连续性
- 高频细节
- 局部噪声与伪影处理
MDC通过多尺度空洞卷积,在较低成本下增强这些局部能力。ACL没有让attention解决所有问题,而是让卷积回到自己最擅长的位置。
6️⃣ 实验效果:平衡性能与复杂度
ACL在去雨和去模糊任务上验证了效果:
- 去雨任务:在Rain100L、Rain100H等数据集上取得强PSNR/SSIM,优于多种经典模型。
- 去模糊任务:在GoPro数据集上,以较低参数量和FLOPs取得不错结果,实现性能-复杂度平衡。
消融实验进一步说明:
- LAMA单独就能带来明显提升。
- MDC还能继续补涨。
- ACL的LA-based Mamba结构优于普通LA和扫描式Mamba,说明:
问题不一定是线性注意力本身不行,而可能是以前没有放在合适的结构里。
7️⃣ 亮点与不足:工程思维的胜利
最大亮点:
ACL 不是单纯换一个注意力模块,而是重新分配了“线性注意力”和“卷积”在图像恢复里的角色。
具体来说:
- 给线性注意力找到新落点:过去LA被认为“上限有限”,ACL展示了合适的框架可以激活其能力。
- 结构设计清晰:全局LAMA,局部MDC,职责明确。
- 工程思维:不只讲效果,也强调参数量和FLOPs。
不足:
- 任务范围有限(仅去雨、去模糊),需要更多验证(去噪、去雾等)。
- 并非所有指标绝对第一,而是“综合平衡型”。
- 部署复杂度仍高于纯CNN。
8️⃣ 简化复现代码(教学版)
下面是一份PyTorch教学代码,保留LAMA-like全局建模和MDC-like多尺度空洞卷积的核心思路,帮助你快速理解ACL:
import torch
import torch.nn as nn
import torch.nn.functional as F
class SimpleLinearAttention(nn.Module):
def __init__(self, dim, heads=4):
super().__init__()
self.dim = dim
self.heads = heads
self.head_dim = dim // heads
self.q = nn.Linear(dim, dim)
self.k = nn.Linear(dim, dim)
self.v = nn.Linear(dim, dim)
self.proj = nn.Linear(dim, dim)
def forward(self, x):
# x: [B, N, C]
B, N, C = x.shape
q = self.q(x).reshape(B, N, self.heads, self.head_dim).transpose(1, 2)
k = self.k(x).reshape(B, N, self.heads, self.head_dim).transpose(1, 2)
v = self.v(x).reshape(B, N, self.heads, self.head_dim).transpose(1, 2)
q = F.elu(q) + 1
k = F.elu(k) + 1
kv = torch.matmul(k.transpose(-2, -1), v)
out = torch.matmul(q, kv)
out = out.transpose(1, 2).reshape(B, N, C)
out = self.proj(out)
return out
class LAMALite(nn.Module):
def __init__(self, dim):
super().__init__()
self.norm = nn.LayerNorm(dim)
self.main_fc = nn.Linear(dim, dim)
self.res_fc = nn.Linear(dim, dim)
self.dwconv = nn.Conv2d(dim, dim, 3, padding=1, groups=dim)
self.attn = SimpleLinearAttention(dim)
self.out_fc = nn.Linear(dim, dim)
self.ffn = nn.Sequential(
nn.LayerNorm(dim),
nn.Linear(dim, dim * 4),
nn.GELU(),
nn.Linear(dim * 4, dim)
)
def forward(self, x, h, w):
# x: [B, N, C]
identity = x
x = self.norm(x)
res = F.silu(self.res_fc(x))
main = self.main_fc(x)
B, N, C = main.shape
main_2d = main.transpose(1, 2).reshape(B, C, h, w)
main_2d = F.silu(self.dwconv(main_2d))
main = main_2d.flatten(2).transpose(1, 2)
attn_out = self.attn(main)
out = self.out_fc(attn_out * res)
x = identity + out
x = x + self.ffn(x)
return x
class MDC(nn.Module):
def __init__(self, dim):
super().__init__()
self.conv1 = nn.Conv2d(dim, dim, 3, padding=1)
self.dilated1 = nn.Conv2d(dim, dim, 3, padding=2, dilation=2)
self.dilated2 = nn.Conv2d(dim, dim, 5, padding=4, dilation=2)
self.fuse = nn.Conv2d(dim * 3, dim, 1)
def forward(self, x):
a = self.conv1(x)
b = self.dilated1(x)
c = self.dilated2(x)
out = torch.cat([a, b, c], dim=1)
out = self.fuse(out)
return out + x
class ACLLite(nn.Module):
def __init__(self, in_ch=3, dim=32):
super().__init__()
self.stem = nn.Conv2d(in_ch, dim, 3, padding=1)
self.enc1 = LAMALite(dim)
self.mdc1 = MDC(dim)
self.down1 = nn.Conv2d(dim, dim * 2, 3, stride=2, padding=1)
self.enc2 = LAMALite(dim * 2)
self.mdc2 = MDC(dim * 2)
self.down2 = nn.Conv2d(dim * 2, dim * 4, 3, stride=2, padding=1)
self.bottleneck = LAMALite(dim * 4)
self.up2 = nn.Sequential(
nn.Upsample(scale_factor=2, mode="bilinear", align_corners=False),
nn.Conv2d(dim * 4, dim * 2, 3, padding=1)
)
self.dec2 = LAMALite(dim * 2)
self.up1 = nn.Sequential(
nn.Upsample(scale_factor=2, mode="bilinear", align_corners=False),
nn.Conv2d(dim * 2, dim, 3, padding=1)
)
self.dec1 = LAMALite(dim)
self.head = nn.Conv2d(dim, in_ch, 3, padding=1)
def forward(self, x):
inp = x
x1 = self.stem(x)
B, C, H, W = x1.shape
t1 = x1.flatten(2).transpose(1, 2)
t1 = self.enc1(t1, H, W)
x1 = t1.transpose(1, 2).reshape(B, C, H, W)
x1 = self.mdc1(x1)
x2 = self.down1(x1)
B, C2, H2, W2 = x2.shape
t2 = x2.flatten(2).transpose(1, 2)
t2 = self.enc2(t2, H2, W2)
x2 = t2.transpose(1, 2).reshape(B, C2, H2, W2)
x2 = self.mdc2(x2)
x3 = self.down2(x2)
B, C3, H3, W3 = x3.shape
t3 = x3.flatten(2).transpose(1, 2)
t3 = self.bottleneck(t3, H3, W3)
x3 = t3.transpose(1, 2).reshape(B, C3, H3, W3)
y2 = self.up2(x3) + x2
B, C2, H2, W2 = y2.shape
t4 = y2.flatten(2).transpose(1, 2)
t4 = self.dec2(t4, H2, W2)
y2 = t4.transpose(1, 2).reshape(B, C2, H2, W2)
y1 = self.up1(y2) + x1
B, C1, H1, W1 = y1.shape
t5 = y1.flatten(2).transpose(1, 2)
t5 = self.dec1(t5, H1, W1)
y1 = t5.transpose(1, 2).reshape(B, C1, H1, W1)
out = self.head(y1)
return out + inp
if __name__ == "__main__":
model = ACLLite()
x = torch.randn(1, 3, 256, 256)
y = model(x)
print("input :", x.shape)
print("output:", y.shape)
[AFFILIATE_SLOT_2]
9️⃣ 总结:ACL的启示
ACL是一篇“问题抓得准”的论文。它没有沿着“更复杂的扫描策略”或“更重的Softmax Attention”去卷,而是换了一个角度:
既然 Mamba 的整体框架适合高效建模,那就把真正不适合图像的那部分换掉。
最终,ACL用LAMA负责全局依赖,MDC负责局部细节,让线性注意力在图像恢复中真正发挥作用。它的价值不只是“分数涨了”,而是提醒我们:
模型设计里,真正重要的不一定是某个模块是不是最新,而是它有没有被放在合适的位置上。
如果你正在研究图像恢复或高效注意力机制,ACL值得认真读一遍。
浙公网安备 33010602011771号