这是一个非常核心的深度学习实践问题。将注意力机制加入已有模型,本质上是为模型赋予“动态权重”或“聚焦能力”,使其能自动关注输入中更重要的部分。
核心思想与通用步骤
-
识别“关注对象”:明确你希望模型关注什么。常见的有:
- 序列内部:如一句话中词与词之间的关系(自注意力)。
- 编码器-解码器之间:如机器翻译中,生成当前目标词时关注源语句的哪些部分(交叉注意力)。
- 特征图空间/通道:如图像中不同空间位置或不同特征通道的重要性。
-
计算注意力权重:这是关键步骤。通过一个可学习的小型网络(通常只是线性变换+激活函数),计算出一个权重分布。这个分布满足:
- 权重之和为1(通常用Softmax实现)。
- 权重高低代表重要性大小。
-
加权求和:用计算出的权重对原始特征进行加权求和,生成一个上下文向量。这个向量集成了所有信息,但按重要性进行了聚焦。
-
整合回原模型:将生成的上下文向量以某种方式(如拼接、相加)整合到原有模型的数据流中,让后续层能利用这个“聚焦后”的信息。
举例阐述:为图像分类CNN添加通道注意力(SE模块)
假设我们有一个用于图像分类的经典CNN(如ResNet),我们想让它学会关注哪些特征通道更重要。
步骤1:识别关注对象
我们关注的是卷积层输出的特征通道。例如,某个卷积块输出一个形状为 [H, W, C] 的特征图,其中C是通道数。有些通道可能编码了“纹理”,有些编码了“颜色”,有些编码了“形状”。我们希望模型能动态地重新校准这些通道的重要性。
步骤2:加入注意力模块(SE Block)
我们可以在原有卷积块(如Residual Block)中,插入一个Squeeze-and-Excitation 模块。
- Squeeze(压缩):对特征图进行全局平均池化(Global Average Pooling),将每个通道的
[H, W] 空间信息压缩成一个标量。输出一个长度为 C 的向量,它捕获了每个通道的全局响应。
- Excitation(激励):将这个C维向量输入一个小型的两层全连接网络(瓶颈结构)。第一个FC层降维(如减少到C/16),使用ReLU激活;第二个FC层升维回C,使用Sigmoid激活。这个网络的输出就是一个0到1之间的权重向量,长度为C,代表每个通道的重要性(注意力权重)。
- Scale(重标定):将得到的注意力权重向量,按通道乘回到原始的特征图
[H, W, C] 上。重要的通道被放大,不重要的通道被抑制。
步骤3:使其发挥作用
- 训练:这个SE模块中的两个FC层参数是随整个CNN一起从头开始训练的。损失函数(如交叉熵)的梯度会通过这个模块反向传播,指导它学会为当前任务(分类)分配正确的通道权重。
- 效果:在训练过程中,对于一张“猫”的图片,模型可能会学会给编码“胡须纹理”和“耳朵形状”的通道分配更高的权重,而给无关的背景纹理通道分配较低的权重。这实现了动态的、数据驱动的特征选择,增强了模型的表征能力。
另一个例子:为序列模型加入自注意力
如果你有一个基于RNN的文本分类模型,你可以在RNN层之上加入一个自注意力层。
- 让RNN输出所有时间步的隐藏状态作为序列。
- 将这些隐藏状态输入一个自注意力层,计算每个时间步隐藏状态相对于其他所有时间步的重要性(权重)。
- 用这些权重对所有隐藏状态进行加权求和,得到一个聚焦了全文关键信息的固定长度向量,再送入分类器。
- 这样,模型就不会过分依赖最后一个隐藏状态,而是能主动找到文中决定分类的关键词(如情感词),即使它们在句首或句末。
总结
将注意力加入已有模型,就像给模型安装了一个“可调节的聚光灯”。你通过设计一个能生成权重的小型可学习结构,并将其插入到原始数据流的关键位置,使模型学会在决策时“有选择地关注”。成功的关键在于:明确关注什么(Query, Key, Value),以及将注意力输出如何集成回主干网络。