2024年夏季《深度学习》学习报告

本实验属于哪门课程中国海洋大学24夏《深度学习》
学习内容卷积神经网络

一、学习目标

1、掌握深度学习基础知识;2、熟练使用深度学习框架;3、实施和优化经典神经网络架构

二、学习内容

MNIST 数据集分类:

数据加载部分

input_size  = 28*28   # MNIST上的图像尺寸是 28x28
output_size = 10      # 类别为 0 到 9 的数字,因此为十类
​
train_loader = torch.utils.data.DataLoader(
    datasets.MNIST('./data', train=True, download=True,
        transform=transforms.Compose(
            [transforms.ToTensor(),
             transforms.Normalize((0.1307,), (0.3081,))])),
    batch_size=64, shuffle=True)
​
test_loader = torch.utils.data.DataLoader(
    datasets.MNIST('./data', train=False, transform=transforms.Compose([
             transforms.ToTensor(),
             transforms.Normalize((0.1307,), (0.3081,))])),
    batch_size=1000, shuffle=True)
  • input_sizeoutput_size 分别定义了输入图像的特征维度和输出类别的数量。

  • train_loadertest_loader 是 PyTorch 的 DataLoader 实例,用于加载 MNIST 数据集。DataLoader 将数据集分成小批次,并可选地打乱数据(shuffle=True)。数据通过 transforms.Compose 进行预处理,包括将图像转换为 Tensor 和标准化。

FC2Layer 类

class FC2Layer(nn.Module):
    def __init__(self, input_size, n_hidden, output_size):
        super(FC2Layer, self).__init__()
        self.input_size = input_size
        self.network = nn.Sequential(
            nn.Linear(input_size, n_hidden), 
            nn.ReLU(), 
            nn.Linear(n_hidden, n_hidden), 
            nn.ReLU(), 
            nn.Linear(n_hidden, output_size), 
            nn.LogSoftmax(dim=1)
        )
        
    def forward(self, x):
        x = x.view(-1, self.input_size)
        return self.network(x)
  • FC2Layer 是一个全连接神经网络(Feedforward Neural Network),由多个全连接层(nn.Linear)和激活函数(nn.ReLU)组成。nn.LogSoftmax 是最后的激活函数,用于多分类任务。

  • forward 方法定义了数据流经网络的过程。x.view(-1, self.input_size) 将输入展平为二维矩阵,self.network(x) 对展平后的数据进行前向传播。

CNN 类

class CNN(nn.Module):
    def __init__(self, input_size, n_feature, output_size):
        super(CNN, self).__init__()
        self.n_feature = n_feature
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=n_feature, kernel_size=5)
        self.conv2 = nn.Conv2d(n_feature, n_feature, kernel_size=5)
        self.fc1 = nn.Linear(n_feature*4*4, 50)
        self.fc2 = nn.Linear(50, 10)    
    
    def forward(self, x, verbose=False):
        x = self.conv1(x)
        x = F.relu(x)
        x = F.max_pool2d(x, kernel_size=2)
        x = self.conv2(x)
        x = F.relu(x)
        x = F.max_pool2d(x, kernel_size=2)
        x = x.view(-1, self.n_feature*4*4)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        x = F.log_softmax(x, dim=1)
        return x
  • CNN 是一个卷积神经网络(Convolutional Neural Network),包括卷积层(nn.Conv2d)、激活函数(F.relu)、池化层(F.max_pool2d)和全连接层(nn.Linear)。

  • forward 方法定义了数据在网络中的流动过程,包括卷积操作、激活、池化、展平以及最终的全连接层。

训练函数

def train(model):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % 100 == 0:
            print('Train: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))
  • train 函数用于训练模型。它遍历 train_loader 中的批次数据,将数据送到 GPU 上,计算损失,进行反向传播和参数更新。

测试函数

def test(model):
    model.eval()
    test_loss = 0
    correct = 0
    for data, target in test_loader:
        data, target = data.to(device), target.to(device)
        output = model(data)
        test_loss += F.nll_loss(output, target, reduction='sum').item()
        pred = output.data.max(1, keepdim=True)[1]
        correct += pred.eq(target.data.view_as(pred)).cpu().sum().item()
​
    test_loss /= len(test_loader.dataset)
    accuracy = 100. * correct / len(test_loader.dataset)
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        accuracy))
  • test 函数用于测试模型。它计算测试数据集上的总损失和准确率。

训练和测试模型

n_hidden = 8 # number of hidden units
​
model_fnn = FC2Layer(input_size, n_hidden, output_size)
model_fnn.to(device)
optimizer = optim.SGD(model_fnn.parameters(), lr=0.01, momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_fnn)))
​
train(model_fnn)
test(model_fnn)
  • 创建一个 FC2Layer 模型,设置隐藏层单元数为 8,优化器使用 SGD。然后进行训练和测试。

n_features = 6 # number of feature maps
​
model_cnn = CNN(input_size, n_features, output_size)
model_cnn.to(device)
optimizer = optim.SGD(model_cnn.parameters(), lr=0.01, momentum=0.5)
print('Number of parameters: {}'.format(get_n_params(model_cnn)))
​
train(model_cnn)
test(model_cnn)
  • 创建一个 CNN 模型,设置特征图数量为 6,优化器使用 SGD。然后进行训练和测试。

像素打乱示例

perm = torch.randperm(784)
plt.figure(figsize=(8, 4))
for i in range(10):
    image, _ = train_loader.dataset.__getitem__(i)
    image_perm = image.view(-1, 28*28).clone()
    image_perm = image_perm[:, perm]
    image_perm = image_perm.view(-1, 1, 28, 28)
    plt.subplot(4, 5, i + 1)
    plt.imshow(image.squeeze().numpy(), 'gray')
    plt.axis('off')
    plt.subplot(4, 5, i + 11)
    plt.imshow(image_perm.squeeze().numpy(), 'gray')
    plt.axis('off')
  • 随机打乱 MNIST 图像的像素顺序并可视化原图和打乱后的图像。

打乱像素顺序函数

def perm_pixel(data, perm):
    data_new = data.view(-1, 28*28)
    data_new = data_new[:, perm]
    data_new = data_new.view(-1, 1, 28, 28)
    return data_new
  • perm_pixel 函数用于对图像数据的像素顺序进行打乱。perm 是一个打乱的像素索引顺序。

训练和测试打乱像素的模型

def train_perm(model, perm):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        data = perm_pixel(data, perm)
        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % 100 == 0:
            print('Train: [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))
​
def test_perm(model, perm):
    model.eval()
    test_loss = 0
    correct = 0
    for data, target in test_loader:
        data, target = data.to(device), target.to(device)
        data = perm_pixel(data, perm)
        output = model(data)
        test_loss += F.nll_loss(output, target, reduction='sum').item()
        pred = output.data.max(1, keepdim=True)[1]
        correct += pred.eq(target.data.view
​
_as(pred)).cpu().sum().item()
​
    test_loss /= len(test_loader.dataset)
    accuracy = 100. * correct / len(test_loader.dataset)
    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        accuracy))
  • train_permtest_perm 函数分别对打乱像素顺序的模型进行训练和测试。它们在每个训练和测试批次中都会对图像数据进行像素顺序打乱。

CIFAR10 数据集分类:

这段代码是一个完整的 PyTorch 示例,展示了如何使用卷积神经网络(CNN)在 CIFAR-10 数据集上进行训练和测试。以下是对每一部分代码的解释:

数据加载和预处理

import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
​
# 使用GPU训练,可以在菜单 "代码执行工具" -> "更改运行时类型" 里进行设置
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
​
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
​
# 训练和测试数据集的下载和加载
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64,
                                          shuffle=True, num_workers=2)
​
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                       download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=8,
                                         shuffle=False, num_workers=2)
  • 通过 torchvision 下载 CIFAR-10 数据集。

  • 使用 transforms.Compose 对图像进行转换,包括将图像转换为 Tensor 和标准化。

  • trainloadertestloader 是 PyTorch 的 DataLoader 实例,分别用于训练和测试数据集。shuffle=True 表示训练数据会被打乱顺序,shuffle=False 表示测试数据不需要打乱。

可视化函数

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
​
def imshow(img):
    plt.figure(figsize=(8,8))
    img = img / 2 + 0.5     # 转换到 [0,1] 之间
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()
​
# 得到一组图像
images, labels = iter(trainloader).next()
# 展示图像
imshow(torchvision.utils.make_grid(images))
# 展示第一行图像的标签
for j in range(8):
    print(classes[labels[j]])
  • imshow 函数用于显示图像。将图像的像素值从 [-1, 1] 转换到 [0, 1] 之间,并显示图像。

  • 从训练数据集中提取一批图像,展示这些图像及其标签。

定义卷积神经网络

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)
​
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(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
  • Net 是一个简单的卷积神经网络(CNN),包括两层卷积层(nn.Conv2d)、最大池化层(nn.MaxPool2d)、和全连接层(nn.Linear)。

  • forward 方法定义了数据在网络中的流动过程,包括卷积、激活、池化、展平和全连接操作。

训练和测试模型

# 网络放到GPU上
net = Net().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.001)
​
for epoch in range(10):  # 重复多轮训练
    for i, (inputs, labels) in enumerate(trainloader):
        inputs = inputs.to(device)
        labels = labels.to(device)
        # 优化器梯度归零
        optimizer.zero_grad()
        # 正向传播 + 反向传播 + 优化
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        # 输出统计信息
        if i % 100 == 0:
            print('Epoch: %d Minibatch: %5d loss: %.3f' %(epoch + 1, i + 1, loss.item()))
​
print('Finished Training')
  • 创建一个 Net 模型并将其转移到 GPU(如果可用)。

  • 使用交叉熵损失函数(nn.CrossEntropyLoss)和 Adam 优化器(optim.Adam)。

  • 训练模型 10 个 epoch。在每个 epoch 中,遍历训练数据并执行前向传播、计算损失、反向传播和优化。

测试模型

# 得到一组图像
images, labels = iter(testloader).next()
# 展示图像
imshow(torchvision.utils.make_grid(images))
# 展示图像的标签
for j in range(8):
    print(classes[labels[j]])
outputs = net(images.to(device))
_, predicted = torch.max(outputs, 1)
​
# 展示预测的结果
for j in range(8):
    print(classes[predicted[j]])
  • 从测试数据集中提取一批图像,展示这些图像及其标签。

  • 使用训练好的模型进行预测,并展示预测的标签。

计算模型准确率

correct = 0
total = 0
​
for data in testloader:
    images, labels = data
    images, labels = images.to(device), labels.to(device)
    outputs = net(images)
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted == labels).sum().item()
​
print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))
  • 遍历测试数据集,计算模型在测试集上的总正确预测数和总样本数。

  • 计算并打印模型在测试集上的准确率。

使用 VGG16 对 CIFAR10 分类

这段代码展示了如何使用 PyTorch 实现和训练一个 VGG 风格的卷积神经网络(CNN)在 CIFAR-10 数据集上。以下是代码的详细解释:

数据加载和预处理

import torch
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
​
# 使用GPU训练,可以在菜单 "代码执行工具" -> "更改运行时类型" 里进行设置
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
​
transform_train = transforms.Compose([
    transforms.RandomCrop(32, padding=4),
    transforms.RandomHorizontalFlip(),
    transforms.ToTensor(),
    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])
​
transform_test = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))])
​
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,  download=True, transform=transform_train)
testset  = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)
​
trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=2)
testloader = torch.utils.data.DataLoader(testset, batch_size=128, shuffle=False, num_workers=2)
​
classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
  • transform_traintransform_test 分别用于训练集和测试集的数据预处理。

    • transforms.RandomCrop(32, padding=4):对图像进行随机裁剪,并在边缘添加填充。

    • transforms.RandomHorizontalFlip():随机水平翻转图像,以增加数据的多样性。

    • transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)):对图像进行归一化处理。

  • 训练集和测试集的数据加载器使用 batch_size=128,并设置 shuffle=True 以打乱训练数据。

定义 VGG 网络

class VGG(nn.Module):
    def __init__(self):
        super(VGG, self).__init__()
        self.cfg = [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M']
        self.features = self._make_layers(cfg)
        self.classifier = nn.Linear(2048, 10)
​
    def forward(self, x):
        out = self.features(x)
        out = out.view(out.size(0), -1)
        out = self.classifier(out)
        return out
​
    def _make_layers(self, cfg):
        layers = []
        in_channels = 3
        for x in cfg:
            if x == 'M':
                layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
            else:
                layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1),
                           nn.BatchNorm2d(x),
                           nn.ReLU(inplace=True)]
                in_channels = x
        layers += [nn.AvgPool2d(kernel_size=1, stride=1)]
        return nn.Sequential(*layers)
  • VGG 类定义了一个类似 VGG 的网络架构。

  • cfg 列表定义了网络的层级结构,其中 'M' 代表最大池化层(nn.MaxPool2d),其他数字代表卷积层的输出通道数。

  • self.features 包含了卷积层和池化层,通过 _make_layers 方法构建。

  • self.classifier 是一个全连接层,用于分类输出。

训练模型

# 网络放到GPU上
net = VGG().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(net.parameters(), lr=0.001)
​
for epoch in range(10):  # 重复多轮训练
    for i, (inputs, labels) in enumerate(trainloader):
        inputs = inputs.to(device)
        labels = labels.to(device)
        # 优化器梯度归零
        optimizer.zero_grad()
        # 正向传播 + 反向传播 + 优化
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        # 输出统计信息
        if i % 100 == 0:   
            print('Epoch: %d Minibatch: %5d loss: %.3f' %(epoch + 1, i + 1, loss.item()))
​
print('Finished Training')
  • net 是定义的 VGG 网络实例,并将其转移到 GPU(如果可用)。

  • 使用交叉熵损失函数(nn.CrossEntropyLoss)和 Adam 优化器(optim.Adam)来训练网络。

  • 训练过程包括前向传播、计算损失、反向传播和优化参数,每 100 个小批量输出一次损失。

测试模型

correct = 0
total = 0
​
for data in testloader:
    images, labels = data
    images, labels = images.to(device), labels.to(device)
    outputs = net(images)
    _, predicted = torch.max(outputs.data, 1)
    total += labels.size(0)
    correct += (predicted == labels).sum().item()
​
print('Accuracy of the network on the 10000 test images: %.2f %%' % (
    100 * correct / total))
  • 在测试集上评估模型的性能。

  • 遍历测试数据集,计算模型的预测准确率。

当然可以!下面是以周报格式呈现的回答:

思考下面的问题
  1. DataLoader 中 shuffle 取不同值的区别

shuffle=True:在每个 epoch 开始前,打乱数据的顺序。此设置用于训练阶段,能够增加数据的多样性,减少模型对数据顺序的依赖,从而提高模型的泛化能力。 shuffle=False:数据按顺序加载。适用于验证和测试阶段,保证数据顺序的一致性,有助于稳定评估模型性能。

  1. transform 中取不同值的区别

数据预处理:transform 用于对输入数据进行标准化、归一化和数据增强。不同的预处理方法会影响模型训练的效果。例如: 标准化和归一化:确保数据尺度统一,能加速收敛,提高模型性能。 数据增强:增加数据集的多样性,帮助模型更好地泛化。

  1. epoch 和 batch 的区别

Epoch:模型在整个训练数据集上训练一次。训练通常需要多个 epoch 以确保模型的收敛。 Batch:训练过程中使用的数据子集。每个 epoch 中,训练数据会被分成多个批次,批次的大小由 batch_size 决定。每个批次用于一次前向和反向传播。

  1. 1x1 的卷积和全连接层的区别及作用

1x1 卷积:用于改变特征图的通道数,不改变空间尺寸。主要用于特征融合、信息压缩和引入非线性变换。 全连接层:将所有输入特征连接到输出层,每个输入都与输出的每个神经元相连。用于进行分类或回归任务。

  1. Residual Learning 为什么能够提升准确率

Residual Learning 通过引入残差连接,使得网络能够学习输入和输出之间的差异。它缓解了梯度消失问题,加速了收敛,提高了训练更深层次网络的能力。

  1. 代码练习二中网络与 LeNet 的区别

LeNet(1989年): 架构:较浅的网络,包含两个卷积层和两个池化层。 特点:较小的卷积核和池化核,网络深度较浅。

代码练习二(例如 VGG): 架构:更深的网络,包含多个卷积层和池化层,卷积核大小为 3x3。 特点:更多的卷积层,提升了模型的表现力。

  1. 卷积以后特征图尺寸变小,如何应用 Residual Learning

特征图尺寸变小:卷积和池化操作会减小特征图的空间尺寸。 应用 Residual Learning:使用 1x1 卷积调整残差连接的维度,确保与输入特征图的维度一致,从而有效应用 Residual Learning。

  1. 提升准确率的方法

增加数据集规模:获取更多数据可以提升模型的泛化能力。 数据增强:使用数据增强技术增加数据多样性,改善模型的鲁棒性。 优化网络结构:尝试更深或更复杂的网络结构,或使用预训练模型进行迁移学习。 超参数调优:调整学习率、批量大小等超参数,以找到最佳训练设置。 正则化技术:使用 Dropout、L2 正则化等方法来减少过拟合。 先进优化算法:如 Adam、RMSprop 等,帮助更快收敛。

三、程序运行结果

列出程序的最终运行结果及截图。

MNIST 数据集分类:

CIFAR10 数据集分类:

使用 VGG16 对 CIFAR10 分类

四、问题总结与体会

收获和体会

  1. 通过实现 VGG 网络并进行训练,深入理解了深度学习框架的核心概念,如卷积层、池化层、全连接层等。

  2. 通过调整数据预处理、学习率和网络结构,体会到了模型调优的复杂性和必要性,掌握了一些常见的调优技巧。

  3. 体验到使用 GPU 进行训练可以显著加速模型训练过程,并理解了如何在代码中设置 GPU 设备。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值