这篇文章我们将深入探讨深度学习领域的三大核心模型:卷积神经网络(CNN)、循环神经网络(RNN)以及Transformer。可以说,这三大架构构成了现代深度学习的主干,各自在不同数据类型和任务场景中展现出卓越性能。下面,我们将从原理结构、关键要点、典型应用场景,再到基于PyTorch的代码实现,逐一进行详细解析。
一、卷积神经网络(Convolutional Neural Network, CNN)
1. 基本原理与结构
CNN的诞生,可以说是专门为“视觉”任务而设计的。它天然适用于处理图像这类具有网格结构的数据。整个网络架构围绕以下几个核心组件构成:
- 卷积层(Conv Layer):通过小尺寸滤波器(kernel)在图像上滑动,提取局部特征,例如边缘、纹理等。
- 池化层(Pooling Layer):对特征图进行降采样,保留最主要的信息,同时降低计算复杂度。
- 激活函数(如ReLU):为网络引入非线性,使其能够学习更复杂的模式。
- 全连接层(Fully Connected Layer):通常位于网络末端,用于最终分类或回归决策。
2. 关键点与注意点
对于CNN,有几个核心设计理念需要特别留意:
- 局部感受野:每个神经元只关注图像的一小块区域,而非全局。卷积核尺寸不宜过大,否则计算量会迅速失控。
- 参数共享:同一个滤波器在整个图像上滑动,极大减少了参数量。但这也可能带来过拟合风险,通常需要配合Dropout或BatchNorm等正则化手段。
- 多通道输入输出:彩色图像包含RGB三个通道,卷积核的通道数必须与输入通道数保持一致,在实现时这一点需要特别注意。
3. 应用场景
CNN的应用如今已无处不在:图像分类(ResNet、VGG)、目标检测(YOLO、Faster R-CNN)、图像分割(U-Net),甚至在视频分析和医疗影像诊断中都扮演着核心角色。
4. 示例代码(PyTorch 实现一个简单的 CNN 分类器)
下面是一个简单的CNN模型,用于图像分类。代码中包含了完整的注释,方便理解每一步的作用:
import torch
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self, num_classes=10):
super(SimpleCNN, self).__init__()
# 特征提取部分
self.features = nn.Sequential(
nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(16, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2)
)
# 分类器部分
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(32 * 8 * 8, 128),
nn.ReLU(),
nn.Linear(128, num_classes)
)
def forward(self, x):
x = self.features(x)
x = self.classifier(x)
return x
model = SimpleCNN()
x = torch.randn(16, 3, 32, 32)
output = model(x)
print(output.shape) # 输出: torch.Size([16, 10])
5. 重点语句解读
nn.Conv2d(...):定义卷积层,in_channels=3表示RGB三通道输入,out_channels=16表示输出16个特征图。nn.MaxPool2d(...):最大池化,在降采样的同时保留主要特征。nn.Linear(32*8*8, 128):卷积结果展平后送入全连接层,注意展平后的维度必须与输入尺寸严格匹配。
二、循环神经网络(Recurrent Neural Network, RNN)
1. 基本原理与结构
如果说CNN是为“看”图而生,那么RNN的核心使命就是处理“序列”数据——文本、时间序列、语音等。它通过隐藏状态(Hidden State)记忆过去的信息,从而捕捉数据中的时序依赖关系。
当然,传统RNN容易遭遇梯度消失或梯度爆炸的问题,因此在实际应用中,更常见的是它的两个经典变种:LSTM(长短期记忆)和GRU(门控循环单元)。它们通过精巧的门控机制,有效缓解了长序列学习的困难。
2. 关键点与注意点
- 能建模序列依赖:这是RNN的基本能力,但普通RNN对于长距离依赖建模效果不佳,推荐使用LSTM或GRU。
- 单向与双向:如果任务需要同时考虑上下文信息,例如命名实体识别,可以选用双向RNN。
- 输入为序列形式:批次内的序列长度很可能不固定,此时需要使用
pack_padded_sequence来处理变长输入,否则会引入大量无意义的填充数据。
3. 应用场景
- 文本分类、机器翻译
- 时间序列预测(股票、天气等)
- 语音识别
4. 示例代码(PyTorch 实现一个简单的 LSTM 分类器)
import torch
import torch.nn as nn
class TextClassifier(nn.Module):
"""简单的基于 LSTM 的文本分类模型"""
def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes):
super(TextClassifier, self).__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
self.lstm = nn.LSTM(embed_dim, hidden_dim, bidirectional=False, batch_first=True)
self.fc = nn.Linear(hidden_dim, num_classes)
def forward(self, x):
x = self.embedding(x)
lstm_out, (h_n, c_n) = self.lstm(x)
out = self.fc(h_n[-1])
return out
# 测试代码
vocab_size, embed_dim, hidden_dim, num_classes = 10000, 128, 256, 2
model = TextClassifier(vocab_size, embed_dim, hidden_dim, num_classes)
x = torch.randint(0, vocab_size, (32, 20))
output = model(x)
print(output.shape) # 输出: torch.Size([32, 2])
5. 重点语句解读
nn.Embedding(...):将词索引映射为密集向量表示。nn.LSTM(...):定义LSTM层,bidirectional=True可开启双向模式,batch_first=True则意味着输入的维度顺序是[batch_size, seq_len, features]。lstm_out, (h_n, c_n):返回值中,lstm_out是所有时间步的输出,h_n和c_n分别代表最后一个时间步的隐藏状态和细胞状态。
三、Transformer
1. 基本原理与结构
Transformer的横空出世,彻底改变了序列建模的格局。它完全摒弃了循环结构,转而依赖一种全新的机制——自注意力(Self-Attention)。
其核心组件包括:
- 自注意力机制:让序列中的每个位置,都能直接关注到所有其他位置的信息。
- 多头注意力(Multi-head Attention):从多个子空间并行进行注意力计算,丰富表达能力。
- 位置编码(Positional Encoding):由于没有循环结构,必须额外注入位置信息,否则序列的顺序将丢失。
- 前馈网络(Feed Forward Network):在每个位置独立进行非线性变换。
2. 关键点与注意点
- 并行计算能力强:与RNN必须串行计算不同,Transformer可以一次性处理整个序列,训练效率极高。
- 长距离依赖建模:这是自注意力的天然优势,但代价是计算复杂度与序列长度的平方成正比(O(n²)),因此处理超长序列时需注意计算资源。
- 容易过拟合:Transformer参数量巨大,Dropout等正则化手段几乎是标配。
3. 应用场景
- 自然语言处理(BERT、GPT系列)
- 图像处理(Vision Transformer)
- 视频理解、音频识别,几乎渗透到了所有序列相关的领域。
4. 示例代码(PyTorch 实现一个简化版 Transformer 编码器)
import torch
import torch.nn as nn
class PositionalEncoding(nn.Module):
def __init__(self, d_model, dropout=0.1, max_len=5000):
super(PositionalEncoding, self).__init__()
self.dropout = nn.Dropout(p=dropout)
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-torch.log(torch.tensor(10000.0)) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0)
self.register_buffer('pe', pe)
def forward(self, x):
x = x + self.pe[:, :x.size(1)]
return self.dropout(x)
class TransformerModel(nn.Module):
def __init__(self, vocab_size, embed_dim, num_heads, num_layers, num_classes):
super(TransformerModel, self).__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
self.positional_encoding = PositionalEncoding(embed_dim, dropout=0.1)
encoder_layer = nn.TransformerEncoderLayer(d_model=embed_dim, nhead=num_heads)
self.transformer_encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
self.fc = nn.Linear(embed_dim, num_classes)
def forward(self, src):
batch_size, seq_len = src.shape
x = self.embedding(src)
x = self.positional_encoding(x)
x = x.permute(1, 0, 2) # Transformer要求序列维度在前
x = self.transformer_encoder(x)
x = x.mean(dim=0) # 取平均作为句子表示
out = self.fc(x)
return out
# 超参数与测试
vocab_size, embed_dim, num_heads, num_layers, num_classes = 10000, 512, 8, 3, 2
model = TransformerModel(vocab_size, embed_dim, num_heads, num_layers, num_classes)
x = torch.randint(0, vocab_size, (32, 20))
output = model(x)
print(output.shape) # 输出: torch.Size([32, 2])
5. 重点语句解读
- PositionalEncoding:通过正余弦函数为每个位置生成独特的编码,因为Transformer本身不感知顺序。
- nn.TransformerEncoderLayer(...):PyTorch内置的Transformer编码层,内部包含自注意力、前馈网络和残差连接。
x = x.permute(1, 0, 2):调整维度顺序,以匹配PyTorch内置Transformer模块的输入格式——序列长度在前。x.mean(dim=0):对序列维度取平均,得到一个句子级别的向量表示,用于后续分类。
总结对比表
| 特性 | CNN | RNN | Transformer |
|---|---|---|---|
| 输入类型 | 图像、网格数据 | 序列 | 序列 |
| 并行性 | 强 | 弱(串行) | 极强 |
| 序列建模能力 | 差 | 中 | 强 |
| 计算复杂度 | O(n) | O(n) | O(n²) |
| 典型应用 | 图像分类 | 文本处理 | NLP、视觉 |
—— The END ——
