[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)

contents

  • 卷积神经网络(part 5) - 使用预训练ResNet18实现CIFAR-10分类
    • 写在开头
    • 基于ResNet18网络完成图像分类任务
      • 库文件和初始化
      • 数据处理
      • 模型构建
      • 模型训练
        • 预训练和迁移学习
        • 模型训练
        • 比较
      • 模型预测
    • 一些小题
      • 5种深度的ResNet
      • LeNet、AlexNet、VGG、GoogLeNet、ResNet
    • 写在最后
    • References

卷积神经网络(part 5) - 使用预训练ResNet18实现CIFAR-10分类

写在开头

在经历了数据->黑白图像的应用实验后,我们在本次实验中将使用CIFAR10数据集进行多通道的彩色图像的分类。由于彩色图像内容更多,在模型训练时将更加收到数据集特性(大小、图像质量等)的影响,模型的效果也会有很大不同。我们在本次实验中,将分别使用经过预训练的和未经过与训练的ResNet18网络进行训练和评估。

基于ResNet18网络完成图像分类任务

库文件和初始化

import torch #PyTorch
import torch.nn as nn #PyTorch算子等
import numpy as np # numpy,用于数据处理
import matplotlib.pyplot as plt # matplotlib,用于图像绘制

from torchvision.datasets.cifar import CIFAR10 # CIFAR10数据集
from torchvision.models import resnet18 # resnet18网络
from torchvision.transforms import ToTensor # 图像转换函数
from torch.utils.data import DataLoader # 数据加载器
%matplotlib inline

plt.rcParams['font.family'] = 'Microsoft YaHei'

device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 使用GPU加速
transform = ToTensor()

import ssl
ssl._create_default_https_context = ssl._create_unverified_context # 由于证书问题,我们需要屏蔽ssl验证

数据处理

作为一个经典的数据集,cifar也在torchvision库中包含。我们使用如下代码即可加载数据集:

dataset_train = CIFAR10(
    './data/cifar', # 下载或加载的地址
    True, # 是否为训练集(用于梯度追踪设置)
    transform, # 数据转化
    download=True # 是否下载
)
dataset_test = CIFAR10(
    './data/cifar',
    False,
    transform
)

dataloader_train = DataLoader(dataset_train, 32)
dataloader_test = DataLoader(dataset_test, 32)

fig, *ax = plt.subplots(2,4)
for i in range(8):
    ax[0][i//4][i%4].set_xticks([])
    ax[0][i//4][i%4].set_yticks([])
    ax[0][i//4][i%4].imshow(dataset_train.data[i])
    ax[0][i//4][i%4].set_xlabel(dataset_train.classes[i])

print('train size:%s'%(','.join(torch.tensor(dataset_train.data.shape).numpy().astype(np.str_))))
print('test size:%s'%(','.join(torch.tensor(dataset_test.data.shape).numpy().astype(np.str_))))

输出结果如下:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第1张图片

模型构建

模型我们在前面一个实验中已经构建完毕,这边我们给出网络结构:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第2张图片
勘误: 在前一篇中,我的模型代码写错了,正确的模型初始化部分代码应当修改为:

def __init__(self, in_channels=1, num_classes=10, with_residual=True):
        super(ResNet18, self).__init__()
        self.sec1 = torch.nn.Sequential(
            torch.nn.Conv2d(in_channels, 64, 7, stride=2, padding=3),
            torch.nn.BatchNorm2d(64), 
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        )
        self.sec2 = torch.nn.Sequential(
            ResBlock(64,     64,     1, with_residual)
        )
        self.sec3 = torch.nn.Sequential(
            ResBlock(64,     128,    2, with_residual)
        )
        self.sec4 = torch.nn.Sequential(
            ResBlock(128,    256,    2, with_residual)
        )
        self.sec5 = torch.nn.Sequential(
            ResBlock(256,    512,    2, with_residual)
        )
        self.pool = torch.nn.AdaptiveAvgPool2d(1)
        self.flatten = torch.nn.Flatten()
        self.linear = torch.nn.Linear(512, num_classes)

这边我们不需要再自己写模型了,只需要使用torchvision中内置的resnet18模型即可:

model_not_pre = resnet18(pretrained=False).to(device) # 未预训练的模型
model_yet_pre = resnet18(pretrained=True).to(device) # 预训练好的模型

这边,我们发现了一个新的东西:预训练。这是什么呢?

模型训练

预训练和迁移学习

预训练就是使用别人已经训练了一部分的模型,迁移学习因此是使用其他数据集进行预训练后、再自己的数据集上使用这个预训练模型再训练的学习过程。
这边找到一个非常好的解释:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第3张图片在这里插入图片描述

模型训练

由于疫情原因,我的2080Ti被囚禁在出租屋了,因此本次训练使用的电脑是商务本,使用MX250显卡进行模型训练,本次训练两个模型,训练的代码如下:

crit = nn.CrossEntropyLoss()
opti = torch.optim.SGD(model_not_pre.parameters(), 0.01)
losses_not_pre = []
for epoch in range(8):
    sum_loss = 0.0
    for i, data in enumerate(dataloader_train):

        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)
        opti.zero_grad()
        outputs = model_not_pre(inputs)
        loss = crit(outputs, labels)
        loss.backward()
        opti.step()
        sum_loss += loss.item()
        if i % 100 == 99:
            print('[%d, %d] loss: %.03f'
                  % (epoch + 1, i + 1, sum_loss / 100))
            losses_not_pre.append(sum_loss)
            sum_loss = 0.0
        with torch.no_grad():
            correct = 0
            total = 0
            for data in dataloader_test:
                images, labels = data
                images, labels = images.to(device), labels.to(device)
                outputs = model_not_pre(images)
                _, predicted = torch.max(outputs.data, 1)
                total += labels.size(0)
                correct += (predicted == labels).sum()
            print('第%d个epoch的识别准确率为:%d%%' % (epoch + 1, (100 * correct / total)))
    torch.save(model_not_pre.state_dict(), 'model_not_pre_%03d.pth' % ( epoch + 1))

结果如下。花了非常非常多的时间,效果还不好:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第4张图片
训练有预训练版本代码类似,这边给出训练结果:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第5张图片

比较

我们将训练时的损失通过折线图的方式绘制出来:

plt.plot(losses_not_pre, label='pretrain = False', color='#cc0000', alpha=0.5)
plt.plot(losses_yet_pre, label='pretrain = True', color='#00cc00', alpha=0.5)
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend()
plt.title('comparison of "pretrain"')
plt.show()

输出结果如下:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第6张图片

由对比图我们发现。尽管一开始的损失,预训练后的模型还略高于没有预训练的模型,但是在后续训练的过程中,我们明显可以看出,预训练模型收敛速度更快,模型效果更好。
**分析:**预训练就像老师教课,可能用到自己的题目上刚开始可能不太好,但是老师教过之后更容易融会贯通,因此表现会越来越好且远高于没有预训练。

模型预测

我们依然直接调用系统摄像头进行测试:

import cv2 
from PIL import Image
import numpy as np
import torch
import torch.nn as nn
import datetime


cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
FPS = 24
cap.set(cv2.CAP_PROP_FPS, FPS)
model_yet_pre = model_yet_pre.eval()

while True:
    ret, frame = cap.read()
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break
    frame = Image.fromarray(frame)
    frame = frame.resize((32,32),Image.BICUBIC)
    frame = np.asarray(frame)
    frame = np.array([frame])
    frame = frame.transpose(0,3,1,2)
    try:
        print(datetime.datetime.now(),dataset_train.classes[torch.argmax(model_yet_pre(torch.tensor(frame,dtype=torch.float).to(device)))],end='\r')
    except:
        pass
    cv2.namedWindow('frame', cv2.WND_PROP_FULLSCREEN)
    cv2.imshow('frame', frame.transpose(0,2,3,1).squeeze(0))
    if cv2.waitKey(1) == ord('q'):  break
cap.release()
cv2.destroyAllWindows()

行吧,依然不准:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第7张图片

一些小题

5种深度的ResNet

通过阅读论文(传送门),我们了解到了几种不同深度的ResNet。汇总表格如下:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第8张图片
首先是共同点:无论是深度为多少的ResNet都将网络分成了五部分。分别是:conv1,conv2_x,conv3_x,conv4_x,conv5_x。
然后是显而易见的不同点:每个网络深度不同。
那么,深度更深有什么作用呢?随着深度的加深,ResNet对于抽象特征的提取能力加强,因而能够在更加复杂精细的分类任务上展现优越的性能。但是,随着网络一同增加的还有计算量,因此:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第9张图片

LeNet、AlexNet、VGG、GoogLeNet、ResNet

看了很多论文,最终找到如下思维导图,觉得是对这些网络一个非常好的概括了:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第10张图片

写在最后

本次实验是卷积神经网络的最后一个实验了。在经过前面的这些学习后,我们对卷积神经网络从概念、原理、实现等多方面进行了学习,通过自己动手搭建一个个网络,我们了解了其中部分的奥秘。当然,卷积神经网络由于其不保存历史输入,在一些时间关联性大的预测上效果不佳。因此,我们即将学习循环神经网络。
然后,关于CNN的思维导图如下:
[2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)_第11张图片

References

1 — https://arxiv.org/pdf/1512.03385.pdf
2 — https://arxiv.org/pdf/1603.05027.pdf
3 — https://arxiv.org/pdf/1605.07146.pdf
4 — https://arxiv.org/pdf/1603.09382.pdf

你可能感兴趣的:([DL]神经网络与深度学习,深度学习,神经网络,cnn)