前言:在上一期我们构建了基本的卷积神经网络之后,接下来我们将学习一些提升网络性能的技巧和方法。这些优化技术包括 数据增强、网络架构的改进、正则化技术 。
数据增强是提升深度学习模型泛化能力的一种常见手段。通过对训练数据进行各种随机变换,可以生成更多的训练样本,帮助模型避免过拟合。
from torchvision import transforms
# 定义数据增强的变换过程
transform = transforms.Compose([
transforms.RandomHorizontalFlip(), # 随机水平翻转
transforms.RandomRotation(15), # 随机旋转,角度范围为 -15 到 15 度
transforms.RandomCrop(32, padding=4), # 随机裁剪,裁剪大小为 32,边缘加 4 像素的填充
transforms.ToTensor(), # 转换为张量
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # 归一化
])
transforms.RandomHorizontalFlip()
:随机水平翻转图像,有助于增加训练样本的多样性。transforms.RandomRotation(15)
:随机旋转图像,旋转角度在 -15 到 15 度之间。transforms.RandomCrop(32, padding=4)
:随机裁剪图像的部分区域并填充边缘,以获得不同的视角。transforms.ToTensor()
:将图像从 PIL 格式转换为 PyTorch 的 Tensor 格式。transforms.Normalize()
:对图像进行标准化,使其均值和标准差分别为 0.5。卷积神经网络可以通过调整网络的层数、卷积核大小、通道数等来改进其性能。以下是一些常见的改进方式:
增加卷积层的数量:
增加卷积核的数量:
使用较大的卷积核:
使用深度可分离卷积(Depthwise Separable Convolution):
使用更高级的激活函数:
class ImprovedCNN(nn.Module):
def __init__(self):
super(ImprovedCNN, self).__init__()
# 第一层卷积层
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
# 第二层卷积层
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
# 第三层卷积层
self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
# 池化层
self.pool = nn.MaxPool2d(2, 2)
# 全连接层
self.fc1 = nn.Linear(128 * 8 * 8, 512)
self.fc2 = nn.Linear(512, 10)
def forward(self, x):
# 卷积层 + 激活函数 + 池化
x = self.pool(torch.relu(self.conv1(x)))
x = self.pool(torch.relu(self.conv2(x)))
x = self.pool(torch.relu(self.conv3(x)))
# 展平数据
x = x.view(-1, 128 * 8 * 8)
# 全连接层
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return x
正则化是防止模型过拟合的关键。以下是几种常见的正则化技术:
Dropout:
L2 正则化(权重衰减):
class CNNWithDropout(nn.Module):
def __init__(self):
super(CNNWithDropout, self).__init__()
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)
self.pool = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(32 * 8 * 8, 512)
self.fc2 = nn.Linear(512, 10)
self.dropout = nn.Dropout(p=0.5) # Dropout 层,丢弃 50% 的神经元
def forward(self, x):
x = self.pool(torch.relu(self.conv1(x)))
x = self.pool(torch.relu(self.conv2(x)))
x = x.view(-1, 32 * 8 * 8)
x = torch.relu(self.fc1(x))
x = self.dropout(x) # 在全连接层前应用 Dropout
x = self.fc2(x)
return x
self.dropout = nn.Dropout(p=0.5)
:在全连接层之前添加 Dropout 层,丢弃一半神经元。注:针对于以上更多修改,大家可以修改参数调试观察更多不同的效果,从而使得自己有一个对优化的大概了解