实验目的:掌握增强卷积神经网络性能的方法,包括 Dropout、BatchNorm 以及残差连接,学会使用 PyTorch 框架以现有的 LeNet 为基础实现相应的改进。

实验内容:

以 LeNet 为基础,分别实现如下几种改进,并比较改进前与改进后模型的性能。6 与 7 为扩展任务

  1. 激活函数的改进:将 LeNet 中的激活函数替换为 ReLU。
  2. 池化方式:平均池化改为最大池化。
  3. 卷积核大小:将其中一个 55 的卷积核修改为 77。
  4. 正则化方法 1:在全连接层后加入 Dropout 层(中间的全连接层可增加维度)
  5. 正则化方法 2:卷积层后加入 BatchNorm 层
  6. 将卷积核从 55 修改为 33,但增加网络的层数(注意调整步长)
  7. 残差连接:选择一条跨层的路径(跨一层或跨多层均可),加入残差连接。注意需要用 1*1 卷积使维度相匹配

代码实现:

以下是基于 LeNet 的改进代码,包括 ReLU 激活函数、最大池化、7x7 卷积核、Dropout、BatchNorm 和 残差连接。其中,对于不同的改进,只需要将相应的代码注释取消即可。

import torch
import torch.nn as nn
import torch.nn.functional as F

class LeNet(nn.Module):
    def __init__(self, num_classes=10):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, kernel_size=5)
        self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(6, 16, kernel_size=5)
        self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, num_classes)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = self.pool1(x)
        x = F.relu(self.conv2(x))
        x = self.pool2(x)
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

class LeNet_ReLU(nn.Module):
    def __init__(self, num_classes=10):
        super(LeNet_ReLU, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, kernel_size=5)
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(6, 16, kernel_size=7)    # 修改为 7x7 卷积核
        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(16*3*3, 120)    # 根据卷积层大小修改全连接层维度
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, num_classes)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = self.pool1(x)
        x = F.relu(self.conv2(x))
        x = self.pool2(x)
        x = x.view(-1, 16*3*3)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

class LeNet_Dropout(nn.Module):
    def __init__(self, num_classes=10):
        super(LeNet_Dropout, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, kernel_size=5)
        self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(6, 16, kernel_size=5)
        self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.dropout1 = nn.Dropout(p=0.5)    # 加入 Dropout 层
        self.fc2 = nn.Linear(120, 84)
        self.dropout2 = nn.Dropout(p=0.5)    # 加入 Dropout 层
        self.fc3 = nn.Linear(84, num_classes)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = self.pool1(x)
        x = F.relu(self.conv2(x))
        x = self.pool2(x)
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = self.dropout1(x)    # 加入 Dropout 层
        x = F.relu(self.fc2(x))
        x = self.dropout2(x)    # 加入 Dropout 层
        x = self.fc3(x)
        return x

class LeNet_BatchNorm(nn.Module):
    def __init__(self, num_classes=10):
        super(LeNet_BatchNorm, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, kernel_size=5)
        self.bn1 = nn.BatchNorm2d(6)    # 加入 BatchNorm 层
        self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(6, 16, kernel_size=5)
        self.bn2 = nn.BatchNorm2d(16)    # 加入 BatchNorm 层
        self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, num_classes)

    def forward(self, x):
        x = F.relu(self.bn1(self.conv1(x)))    # 加入 BatchNorm 层
        x = self.pool1(x)
        x = F.relu(self.bn2(self.conv2(x)))    # 加入 BatchNorm 层
        x = self.pool2(x)
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

class LeNet_Residual(nn.Module):
    def __init__(self, num_classes=10):
        super(LeNet_Residual, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, kernel_size=5)
        self.bn1 = nn.BatchNorm2d(6)
        self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.conv2 = nn.Conv2d(6, 16, kernel_size=3)    # 修改为 3x3 卷积核
        self.bn2 = nn.BatchNorm2d(16)
        self.conv3 = nn.Conv2d(16, 32, kernel_size=3)    # 新增卷积层
        self.bn3 = nn.BatchNorm2d(32)
        self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2)
        self.fc1 = nn.Linear(32*3*3, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, num_classes)
        self.conv_res = nn.Conv2d(6, 32, kernel_size=1)    # 1x1 卷积核使维度相匹配

    def forward(self, x):
        x_res = x    # 保存输入的残差连接
        x = F.relu(self.bn1(self.conv1(x)))
        x = self.pool1(x)
        x = F.relu(self.bn2(self.conv2(x)))
        x = F.relu(self.bn3(self.conv3(x)))    # 新增卷积层
        x_res = self.conv_res(x_res)    # 1x1 卷积核使维度相匹配
        x = x + x_res    # 残差连接
        x = self.pool2(x)
        x = x.view(-1, 32*3*3)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

实验结果与分析:

(此处应加入实验结果表格或图表,并进行详细分析)

LeNet 改进:使用 Dropout、BatchNorm 和 残差连接增强卷积神经网络性能

原文地址: https://www.cveoy.top/t/topic/n0z5 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录