首页人工智能Pytorch【深度学习(PyTorch...

【深度学习(PyTorch篇)】32.使用卷积神经网络完成图像分类任务(CIFAR-10数据集)

本系列文章配套代码获取有以下两种途径:

  • 通过百度网盘获取:
链接:https://pan.baidu.com/s/1XuxKa9_G00NznvSK0cr5qw?pwd=mnsj 提取码:mnsj
  • 前往GitHub获取
https://github.com/returu/PyTorch





在前一篇文章中,我们使用全连接网络完成基于CIFAR-10数据集的图像分类任务,最后在测试集上的预测准确率为49.46%。
【深度学习(PyTorch篇)】31.使用全连接网络完成图像分类任务(CIFAR-10数据集)
01

卷积神经网络


积神经网络(Convolutional Neural Networks,CNN)是一种初期为了处理图像数据而设计的一种神经网络模型。由于其具有很强的特征提取及泛化能力,现阶段已被广泛应用于计算机视觉领域,并且已经变得非常主流,以至于今天几乎没有人会在不基于卷积神经网络模型的基础上开发与图像处理、图像识别、物体检测或图像语义分割相关的商业应用或参与图像处理相关的数据竞赛。随着研究的深入,卷积神经网络甚至在音频、文本和时间序列分析等领域都有很抢眼的表现。
卷积神经网络本质上也是一个多层感知器,也是通过一个个网络层的组装来搭建出完整的网络结构。不同的是全连接神经网络模型都是基于全连接层(Fully Connected Layer)搭建的,而卷积神经网络的核心层出现了卷积层(Convolution Layer)和池化层(Pooling Layer)。关于卷积神经网络模型中的各个网络层的具体内容会在后续文章中依次介绍。
之所以这样设计,是因为全连接层会将图像的空间结构扁平化成一维向量,从而会忽视图像中像素点之间的空间结构和关系信息,因为全连接层对图像数据特征的处理的顺序是不变的,无论我们是否预先保留了图像像素之间的空间结构顺序,或者在输入模型之前对像素矩阵进行排列,也就是说全连接层从输入数据中学习到的是全局模式。相对应的,卷积神经网络正是为了解决上述问题而被设计,网络模型中的卷积层中每个神经元的输入与上一层图像数据的局部区域相连接,因此在计算过程中会保留图像像素点之间的相关关联性,从而能够从图像数据中学习到局部模式,例如图像的边缘、纹理等。
卷积神经网络模型在图像中一旦学习到某个局部模式之后,它就可以在图像的任何地方业识别出这种模式,这种现象就是卷积神经网络的平移不变性。另外,卷积神经网络模型随着卷积层的叠加,可以有效地学习到更加复杂更加抽象的模式:前面的卷积层会学习到诸如边缘等较小的局部模式,后面的卷积层将会学习到前一层卷积层学习到的模式特征,以此类推。
例如,卷积神经网络在学习识别猫时,前面的卷积层会先从图像数据中学习到猫的各种边缘等局部模式,这些简单的模式会在后面的卷积层中组合成局部特征(眼睛、鼻子、耳朵等),这些局部对象又会在后面的卷积层中组合成更高级别的特征。正是因为这些特性使得卷积神经网络在处理图像数据时可以高效地利用数据,相比较于全连接网络只需要更少的数据就能学习到具有泛化能力的网络模型。

本次我们将使用卷积神经网络来完成同样的分类任务。

02

CIFAR-10分类


具体步骤与前篇一致,只是将全连接网络替换成卷积神经网络。
  • 加载CIFAR-10数据集并进行预处理:

分别下载训练集和测试集,并进行图像预处理操作,以提升模型的训练效果。
# 数据预处理  
transform=transforms.Compose([transforms.ToTensor(), # 变换为Tensor
                              transforms.Normalize((0.4915,0.4823,0.4468),(0.2470,0.2435,0.2616)) # 数据归一化
                             ])

# 下载并加载CIFAR10训练集和测试集
trainset = datasets.CIFAR10('./data/' , train=True , download=True,transform=transform)
train_loader = DataLoader(trainset , batch_size=64 , shuffle=True)

testset = datasets.CIFAR10('./data/' , train=False , download=True,transform=transform)
test_loader = DataLoader(testset , batch_size=64 , shuffle=True)

  • 构建网络:

不同于之前使用的Sequential模型,本次通过继承 nn.Module 类并实现 forward 方法来定义卷积神经网络模型。该方式是构建自定义神经网络最常用和灵活的方式。
本次构建的神经网络模型结构为卷积层nn.Conv2d+标准化层nn.BatchNorm2d+池化层nn.MaxPool2d+线性层nn.Linear的组合。选择交叉熵损失函数作为损失函数,选择SGD随机梯度下降优化器。
# 构建卷积神经网络模型  
class Net(nn.Module):  
    def __init__(self):  
        super().__init__()  
        self.conv1 = nn.Conv2d(365) # 卷积层  
        self.bn1 = nn.BatchNorm2d(6)  # 标准化层
        self.pool = nn.MaxPool2d(22)  # 池化层
        self.conv2 = nn.Conv2d(6165# 卷积层 
        self.bn2 = nn.BatchNorm2d(16)  标准化
        self.fc1 = nn.Linear(16 * 5 * 5120)  
        self.fc2 = nn.Linear(12084)  
        self.fc3 = nn.Linear(8410)  

    def forward(self, x):  
        x = self.pool(nn.functional.relu(self.bn1(self.conv1(x))))  # 在ReLU之前加入BatchNorm  
        x = self.pool(nn.functional.relu(self.bn2(self.conv2(x))))  # 在ReLU之前加入BatchNorm  
        x = x.view(-116 * 5 * 5)  
        x = nn.functional.relu(self.fc1(x))  # relu激活函数
        x = nn.functional.relu(self.fc2(x))  
        x = self.fc3(x)  
        return x

# 检查是否有可用的GPU,如果有,将网络和数据移动到GPU上
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")  
net = Net().to(device)    # 将网络移到GPU上
net

# 定义损失函数
criterion  = nn.CrossEntropyLoss()

# 定义优化器
optimizer = optim.SGD(net.parameters(), lr=1e-2, momentum=0.9)
  • 训练网络:

使用训练集对模型进行训练,通过前向传播计算预测值,然后计算损失并进行反向传播来更新模型参数。
# 训练网络  
for epoch in range(10):  # 多次遍历整个数据集  
    running_loss = 0.0  
    for i, data in enumerate(train_loader, 0):  
        # 获取输入数据  
        inputs, labels = data[0].to(device), data[1].to(device)  

        # 清零梯度缓存  
        optimizer.zero_grad()  

        # 前向传播,后向传播,优化  
        outputs = net(inputs)  
        loss = criterion(outputs, labels)  
        loss.backward()  
        optimizer.step()  

        # 输出统计信息  
        running_loss += loss.item()  
        if i % 200 == 199:  # 每200个mini-batches输出一次  
            print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 200))  
            running_loss = 0.0  

print('Finished Training')  
训练过程中,记录损失来监控模型的训练效果。
[1,   200] loss: 1.832
[1,   400] loss: 1.511
[1,   600] loss: 1.404
[2,   200] loss: 1.268
......
[9,   600] loss: 0.799
[10,   200] loss: 0.738
[10,   400] loss: 0.768
[10,   600] loss: 0.773
Finished Training
通过输出结果可以看出,卷积神经网络模型的训练损失低于全连接网络的,说明卷积神经网络通过卷积层能够更有效地从输入数据中提取有用的特征。
  • 测试网络:

使用测试集对训练好的模型进行评估,计算模型在未知数据(测试集)上的性能表现,本次选择准确率指标。

# 测试网络  
correct = 0  
total = 0  
with torch.no_grad():  
    for data in test_loader:  
        images, labels = data[0].to(device), data[1].to(device)  
        outputs = net(images)  
        _, predicted = torch.max(outputs.data, 1)  
        total += labels.size(0)  
        correct += (predicted == labels).sum().item()  

print(f'Accuracy of the network on the 10000 test images: {(100 * correct / total)}%' )

输出结果为:

Accuracy of the network on the 10000 test images: 66.07%

可以看到模型在测试集上的预测准确率为66.07%,要高于全连接网络的预测准确率49.46%

  • 保存和加载模型:

在PyTorch中保存模型十分简单,首先使用state_dict()来获取模型的所有状态数据,然后使用torch.save()函数将这些数据保存到一个文件中即可。

# 保存模型
torch.save(net.state_dict(), 'model.pth'

后续需要使用模型时,使用load_state_dict()方法来加载保存的状态数据。这样可以确保模型的架构与保存的参数是匹配的。

# 加载模型
net2 = Net() # 首先实例化模型  
net2.load_state_dict(torch.load('model.pth')) # 然后加载保存的文件

另外,还可以使用torch.save(model, ‘model.pth’)来保存整个模型(包括架构和参数),并使用model = torch.load(‘model.pth’)来加载。需要注意的是,这种方法严重依赖模型定义方式以及文件路径结构容易出现问题,因此不推荐使用。



更多内容可以前往官网查看

https://pytorch.org/


本篇文章来源于微信公众号: 码农设计师

RELATED ARTICLES

欢迎留下您的宝贵建议

Please enter your comment!
Please enter your name here

- Advertisment -

Most Popular

Recent Comments