论文《Attention Is All You Need》
1、作用:
缩放点积注意力(Scaled Dot-Product Attention)是 Transformer 模型的核心组件,旨在解决序列建模中长距离依赖关系捕捉的问题。传统的循环神经网络(RNN)在处理长序列时存在梯度消失或爆炸的问题,且并行性较差。该模块通过计算查询(Query)、键(Key)和值(Value)之间的相似度,实现对输入序列中重要信息的聚焦,同时支持高效的并行计算,为 Transformer 在自然语言处理、计算机视觉等领域的成功奠定了基础。
2、机制
缩放点积注意力的核心机制是通过向量点积计算查询与键的相似度,再经过缩放和 softmax 归一化得到注意力权重,最后用权重对值进行加权求和。具体步骤如下:
3、独特优势
4、代码
import torch
import torch.nn as nn
import torch.nn.functional as F
class ScaledDotProductAttention(nn.Module):
"""
缩放点积注意力模块(Scaled Dot-Product Attention)
实现查询、键、值之间的注意力计算
"""
def __init__(self):
super().__init__()
def forward(self, q, k, v, mask=None):
"""
参数说明:
q: 查询张量,形状为 [batch_size, n_heads, seq_len_q, d_k]
k: 键张量,形状为 [batch_size, n_heads, seq_len_k, d_k]
v: 值张量,形状为 [batch_size, n_heads, seq_len_v, d_v](通常seq_len_k = seq_len_v)
mask: 掩码张量,形状为 [batch_size, 1, seq_len_q, seq_len_k] 或类似,用于掩盖无效位置
返回:
output: 注意力输出,形状为 [batch_size, n_heads, seq_len_q, d_v]
attn_weights: 注意力权重,形状为 [batch_size, n_heads, seq_len_q, seq_len_k]
"""
d_k = q.size(-1) # 键的维度
# 计算Q与K的点积并缩放
scores = torch.matmul(q, k.transpose(-2, -1)) / torch.sqrt(torch.tensor(d_k, dtype=torch.float32))
# 应用掩码(若有)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9) # 掩码位置设为负无穷
# 计算注意力权重
attn_weights = F.softmax(scores, dim=-1)
# 加权求和得到输出
output = torch.matmul(attn_weights, v)
return output, attn_weights
# 测试代码
if __name__ == '__main__':
# 实例化注意力模块
model = ScaledDotProductAttention()
# 生成随机输入(batch_size=2, n_heads=8, seq_len=10, d_k=d_v=64)
q = torch.randn(2, 8, 10, 64)
k = torch.randn(2, 8, 10, 64)
v = torch.randn(2, 8, 10, 64)
# 生成掩码(掩盖后5个位置)
mask = torch.ones(2, 1, 10, 10)
mask[:, :, :, 5:] = 0
# 前向传播
output, attn_weights = model(q, k, v, mask)
# 验证输出形状
print(f"输出形状: {output.shape}") # 预期: torch.Size([2, 8, 10, 64])
print(f"注意力权重形状: {attn_weights.shape}") # 预期: torch.Size([2, 8, 10, 10])
论文《MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications》
1、作用:
深度可分离卷积(Depthwise Separable Convolution)是为移动端和嵌入式设备设计的高效卷积操作,旨在解决传统卷积神经网络计算量大、参数过多的问题。传统卷积在提取空间特征和通道特征时存在冗余计算,该模块通过将卷积操作分解为深度卷积(Depthwise Convolution)和逐点卷积(Pointwise Convolution),在保持相似特征提取能力的同时,大幅减少计算量(FLOPs)和模型参数,使神经网络能够在资源受限的设备上高效运行。
2、机制
深度可分离卷积由两个连续的操作组成,具体机制如下:
相比之下,传统卷积的计算量为Cout×H×W×K×K×Cin,深度可分离卷积的计算量约为传统卷积的1/Cout+1/(K2),当K=3时,计算量可减少至约 1/9~1/8。
3、独特优势
4、代码
import torch
import torch.nn as nn
class DepthwiseSeparableConv(nn.Module):
"""
深度可分离卷积模块(Depthwise Separable Convolution)
由深度卷积和逐点卷积组成,减少计算量和参数
"""
def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1):
"""
参数说明:
in_channels: 输入特征图的通道数
out_channels: 输出特征图的通道数
kernel_size: 深度卷积的卷积核大小
stride: 深度卷积的步长
padding: 深度卷积的填充
"""
super().__init__()
# 深度卷积:每个通道单独卷积
self.depthwise = nn.Conv2d(
in_channels=in_channels,
out_channels=in_channels, # 输出通道数与输入相同
kernel_size=kernel_size,
stride=stride,
padding=padding,
groups=in_channels, # 分组数等于输入通道数,实现每个通道单独卷积
bias=False
)
# 逐点卷积:1x1卷积融合通道特征
self.pointwise = nn.Conv2d(
in_channels=in_channels,
out_channels=out_channels,
kernel_size=1,
stride=1,
padding=0,
bias=False
)
# 批归一化和激活函数
self.bn = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
def forward(self, x):
# 深度卷积
x = self.depthwise(x)
# 逐点卷积
x = self.pointwise(x)
# 批归一化和激活
x = self.bn(x)
x = self.relu(x)
return x
# 测试代码
if __name__ == '__main__':
# 实例化深度可分离卷积模块(输入通道32,输出通道64,3x3卷积)
model = DepthwiseSeparableConv(in_channels=32, out_channels=64, kernel_size=3).cuda()
# 创建随机输入张量 [batch_size=2, channels=32, height=64, width=64]
input_tensor = torch.randn(2, 32, 64, 64).cuda()
# 前向传播
output_tensor = model(input_tensor)
# 验证输出形状
print(f"输入形状: {input_tensor.shape}")
print(f"输出形状: {output_tensor.shape}") # 预期: torch.Size([2, 64, 64, 64])
论文《An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale》
1、作用: Patch Embedding 是视觉 Transformer(Vision Transformer, ViT)中将图像转换为 Transformer 可处理序列的核心模块。传统的 Transformer 模型主要用于处理文本序列,而图像是二维网格结构,无法直接输入 Transformer。该模块通过将图像分割为固定大小的非重叠补丁(Patches),并将每个补丁线性投影为固定维度的向量,从而将图像转换为一维序列,使 Transformer 能够应用于图像识别等视觉任务,打破了卷积神经网络在视觉领域的垄断地位。
2、机制 Patch Embedding 的具体机制如下:
例如,对于 224x224x3 的图像,使用 16x16 的补丁分割,可得到\(14 \times 14 = 196\)个补丁,每个补丁展平后长度为\(16 \times 16 \times 3 = 768\),通过线性投影至\(D=768\)维度,最终得到 196+1(加上类别嵌入)个向量的序列。
3、独特优势
4、代码
import torch
import torch.nn as nn
class PatchEmbedding(nn.Module):
"""
视觉Transformer的Patch Embedding模块
将图像分割为补丁并转换为嵌入序列
"""
def __init__(self, img_size=224, patch_size=16, in_channels=3, embed_dim=768):
"""
参数说明:
img_size: 输入图像的大小(假设为正方形)
patch_size: 每个补丁的大小(假设为正方形)
in_channels: 图像的通道数(如RGB图像为3)
embed_dim: 补丁嵌入的维度
"""
super().__init__()
self.img_size = img_size
self.patch_size = patch_size
# 计算补丁数量
self.num_patches = (img_size // patch_size) **2
# 定义补丁投影层(使用卷积实现,等价于线性投影)
self.proj = nn.Conv2d(
in_channels=in_channels,
out_channels=embed_dim,
kernel_size=patch_size,
stride=patch_size # 步长等于补丁大小,确保非重叠分块
)
# 定义位置编码(可学习的位置嵌入)
self.pos_embed = nn.Parameter(torch.randn(1, self.num_patches, embed_dim))
def forward(self, x):
"""
参数x: 输入图像张量,形状为 [batch_size, in_channels, img_size, img_size]
返回: 补丁嵌入序列,形状为 [batch_size, num_patches, embed_dim]
"""
batch_size = x.shape[0]
# 补丁投影:[batch_size, in_channels, H, W] -> [batch_size, embed_dim, num_patches^(1/2), num_patches^(1/2)]
x = self.proj(x)
# 展平为序列:[batch_size, embed_dim, num_patches] -> [batch_size, num_patches, embed_dim]
x = x.flatten(2).transpose(1, 2)
# 添加位置编码
x = x + self.pos_embed
return x
# 测试代码
if __name__ == '__main__':
# 实例化Patch Embedding模块(224x224图像,16x16补丁,3通道,768维嵌入)
model = PatchEmbedding(img_size=224, patch_size=16, in_channels=3, embed_dim=768).cuda()
# 创建随机输入张量 [batch_size=2, channels=3, height=224, width=224]
input_tensor = torch.randn(2, 3, 224, 224).cuda()
# 前向传播
output_tensor = model(input_tensor)
# 验证输出形状
print(f"输入形状: {input_tensor.shape}")
print(f"输出形状: {output_tensor.shape}") # 预期: torch.Size([2, 196, 768])(196=14x14)
论文《MobileNetV2: Inverted Residuals and Linear Bottlenecks》
1、作用: 倒置残差块是 MobileNetV2 中提出的核心模块,旨在解决移动端神经网络中特征表达能力与计算效率的平衡问题。传统的残差块(如 ResNet 中的残差块)采用 “降维 - 卷积 - 升维” 的结构,而倒置残差块创新性地使用 “升维 - 卷积 - 降维” 的结构,配合线性瓶颈(Linear Bottleneck),在减少计算量的同时,有效缓解了特征信息在低维空间的损失,显著提升了轻量级模型的性能。
2、机制 倒置残差块的机制主要包括以下步骤:
与传统残差块相比,倒置残差块在高维空间进行卷积操作,避免了低维空间的信息损失,同时通过深度卷积保持计算效率。
3、独特优势
4、代码
import torch
import torch.nn as nn
class InvertedResidual(nn.Module):
"""
倒置残差块(Inverted Residual Block)
采用"升维-深度卷积-降维"结构,配合残差连接
"""
def __init__(self, in_channels, out_channels, stride, expansion_factor=6):
"""
参数说明:
in_channels: 输入特征通道数
out_channels: 输出特征通道数
stride: 深度卷积的步长(1或2,决定是否改变空间尺寸)
expansion_factor: 升维的扩展因子
"""
super().__init__()
self.stride = stride
self.use_residual = (stride == 1) and (in_channels == out_channels)
# 升维通道数
expanded_channels = in_channels * expansion_factor
# 升维:1x1卷积
self.expand = nn.Conv2d(
in_channels=in_channels,
out_channels=expanded_channels,
kernel_size=1,
stride=1,
padding=0,
bias=False
)
self.bn1 = nn.BatchNorm2d(expanded_channels)
self.relu6 = nn.ReLU6(inplace=True) # 限制ReLU的最大值为6,增强稳定性
# 深度卷积:3x3卷积(每个通道单独卷积)
self.depthwise = nn.Conv2d(
in_channels=expanded_channels,
out_channels=expanded_channels,
kernel_size=3,
stride=stride,
padding=1,
groups=expanded_channels, # 分组数等于输入通道数
bias=False
)
self.bn2 = nn.BatchNorm2d(expanded_channels)
# 降维:1x1卷积(线性瓶颈,无激活函数)
self.project = nn.Conv2d(
in_channels=expanded_channels,
out_channels=out_channels,
kernel_size=1,
stride=1,
padding=0,
bias=False
)
self.bn3 = nn.BatchNorm2d(out_channels)
def forward(self, x):
residual = x
# 升维
x = self.expand(x)
x = self.bn1(x)
x = self.relu6(x)
# 深度卷积
x = self.depthwise(x)
x = self.bn2(x)
x = self.relu6(x)
# 降维(线性操作)
x = self.project(x)
x = self.bn3(x)
# 残差连接(若满足条件)
if self.use_residual:
x += residual
return x
# 测试代码
if __name__ == '__main__':
# 实例化倒置残差块(输入32通道,输出16通道,步长1,扩展因子6)
model = InvertedResidual(in_channels=32, out_channels=16, stride=1).cuda()
# 创建随机输入张量 [batch_size=2, channels=32, height=64, width=64]
input_tensor = torch.randn(2, 32, 64, 64).cuda()
# 前向传播
output_tensor = model(input_tensor)
# 验证输出形状
print(f"输入形状: {input_tensor.shape}")
print(f"输出形状: {output_tensor.shape}") # 预期: torch.Size([2, 16, 64, 64])
论文《MLP-Mixer: An all-MLP Architecture for Vision》
1、作用: Mixer 块是 MLP-Mixer 模型的核心组件,该模型完全摒弃了卷积和自注意力机制,仅通过多层感知机(MLP)实现图像识别任务。Mixer 块的设计旨在证明纯 MLP 架构也能有效捕捉图像中的空间和通道特征,挑战了卷积神经网络和视觉 Transformer 在视觉领域的主导地位。其作用是通过两种类型的 MLP(token-mixing MLP 和 channel-mixing MLP)分别建模空间维度和通道维度的特征交互,从而实现对图像特征的有效提取。
2、机制 Mixer 块的机制围绕 “混合”(Mixing)操作展开,具体包括:
通过交替进行 token-mixing 和 channel-mixing,Mixer 块能够同时捕捉空间和通道特征的交互信息。
3、独特优势
4、代码
import torch
import torch.nn as nn
class MixerBlock(nn.Module):
"""
MLP-Mixer的Mixer块
包含Token-Mixing MLP和Channel-Mixing MLP,用于混合空间和通道特征
"""
def __init__(self, num_patches, hidden_dim, mlp_dim):
"""
参数说明:
num_patches: 补丁(token)的数量(N)
hidden_dim: 补丁嵌入的维度(D)
mlp_dim: MLP的隐藏层维度
"""
super().__init__()
# Token-Mixing MLP:混合不同补丁(空间维度)
self.token_mixing = nn.Sequential(
nn.LayerNorm(hidden_dim), # 层归一化
nn.Linear(num_patches, mlp_dim), # 扩展维度
nn.GELU(),
nn.Linear(mlp_dim, num_patches) # 压缩回原维度
)
# Channel-Mixing MLP:混合不同通道
self.channel_mixing = nn.Sequential(
nn.LayerNorm(hidden_dim), # 层归一化
nn.Linear(hidden_dim, mlp_dim), # 扩展维度
nn.GELU(),
nn.Linear(mlp_dim, hidden_dim) # 压缩回原维度
)
def forward(self, x):
"""
参数x: 输入张量,形状为 [batch_size, num_patches, hidden_dim]
返回: 输出张量,形状与输入相同
"""
# Token-Mixing:先转置,处理后再转置回来,添加残差
residual = x
x = x.transpose(1, 2) # [batch_size, hidden_dim, num_patches]
x = self.token_mixing(x)
x = x.transpose(1, 2) # [batch_size, num_patches, hidden_dim]
x += residual
# Channel-Mixing:直接处理,添加残差
residual = x
x = self.channel_mixing(x)
x += residual
return x
# 测试代码
if __name__ == '__main__':
# 实例化Mixer块(196个补丁,768维嵌入,3072维MLP隐藏层)
model = MixerBlock(num_patches=196, hidden_dim=768, mlp_dim=3072).cuda()
# 创建随机输入张量 [batch_size=2, num_patches=196, hidden_dim=768]
input_tensor = torch.randn(2, 196, 768).cuda()
# 前向传播
output_tensor = model(input_tensor)
# 验证输出形状
print(f"输入形状: {input_tensor.shape}")
print(f"输出形状: {output_tensor.shape}") # 预期: torch.Size([2, 196, 768])