【深度学习】卷积神经网络-图片分类案例(pytorch实现)

【深度学习】卷积神经网络-图片分类案例(pytorch实现) ladoo 2024-02-01 14:28:38 123

文章目录

前言

前文已经介绍过卷积神经网络的基本概念【深度学习】卷积神经网络-CNN简单理论介绍。下面开始动手实践吧。本文任务描述如下:
从公开数据集CIFAR10中创建训练集、测试集数据,使用Pytorch构建CNN模型对训练集数据进行训练,然后在测试集中测试,查看简单的CNN模型训练效果如何。

CIFAR10公开数据地址:http://www.cs.toronto.edu/~kriz/cifar.html。 CIFAR-10数据集包含 60000 张 32x32 的彩色 10 中类型的数据, 其中50000张训练图片和10000测试图片。下面是每个类别随机10张图片的结果。

下面就根据CNN的原理:【深度学习】卷积神经网络-CNN简单理论介绍设计相关的网络和程序,建议使用jupyter。

1. 数据集

这里结合torchvision包下载相关数据集并进行数据的预处理。代码如下:

import torch
import torchvision
import torchvision.transforms as transforms

# 数据预处理转换器
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
# 构建训练集数据,使用transform处理数据集供模型直接使用
train_set = torchvision.datasets.CIFAR10('./data', train=True, download=True, transform=transform)
# 将数据集转成可迭代的批次处理数据
train_loader = torch.utils.data.DataLoader(train_set, batch_size=4, shuffle=True, num_workers=1)
# 同理构建测试集数据
test_set = torchvision.datasets.CIFAR10('./data', train=False, download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(test_set, batch_size=4, shuffle=True, num_workers=1)
# 数据对应标签
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

注: 如果数据下载较慢,可以在官网下载(cifar-10-python.tar.gz),然后放在data目录下,再将download改为False即可。

另外:transforms.Compose组合两种处理图片的方法,一种是将图片转成模型输入的张量格式数据,另一个则为数据标准化函数。

到此数据应该处理好了。下面我们可以查看一下数据,代码如下:

import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline


def imshow(img):
    """
    展示图片
    img:图片数据
    """
    img = img / 2 + 0.5  # 反标准化
    npimg = img.numpy()  # 将数据转换成numpy格式
    plt.imshow(np.transpose(npimg, (1, 2, 0))) 


# 随机获取部分训练数据
dataiter = iter(train_loader)
images, labels = dataiter.next()
# 显示图像
imshow(torchvision.utils.make_grid(images))
# 打印标签
print(" ".join('%5s' % classes[labels[j]] for j in range(4))) 
# 结果:car  ship truck horse

我这边随机显示的图片如下:

到这里数据已基本上没什么问题了。

注: 这里暂不考究图像预处理的内容,感兴趣的可以深入了解。

2. 构建网络

下面就是构建CNN网络了,根据之前的介绍以及pytorch,代码如下:

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

# 如果有gpu的可使用GPU加速
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

class CNNNet(nn.Module):
    def __init__(self):
        super(CNNNet, self).__init__()
        # 定义第一个卷积层
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=5, stride=1)
        # 定义第一个池化层
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
        # 定义第二个卷积层
        self.conv2 = nn.Conv2d(in_channels=16, out_channels=36, kernel_size=3, stride=1)
        # 定义第二个池化层
        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
        # 定义第一个全连接层
        self.fc1 = nn.Linear(1296, 128)
        # 定义第二个全连接层
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        # 连接各个cnn各个模块
        x = self.pool1(F.relu(self.conv1(x)))
        x = self.pool2(F.relu(self.conv2(x)))
        # print(x.shape)
        x=x.view(-1, 36*6*6)
        x=F.relu(self.fc2(F.relu(self.fc1(x))))
        # 返回运算后的结果
        return x

# 实例化模型
net = CNNNet()
net.to(device)  # 模型设备转移
# 查看模型
print(net)

打印的模型输出结果如下:

CNNNet(
  (conv1): Conv2d(3, 16, kernel_size=(5, 5), stride=(1, 1))
  (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (conv2): Conv2d(16, 36, kernel_size=(3, 3), stride=(1, 1))
  (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  (fc1): Linear(in_features=1296, out_features=128, bias=True)
  (fc2): Linear(in_features=128, out_features=10, bias=True)
)

针对模型中一些层的参数介绍如下:

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1,bias=True, padding_model=‘zeros’) 其中主要参数释义:

  • in_channels(int):输入图片的通道数目,彩色图片的通道数为3(RGB)
  • out_channels(int): 卷积产生的通道数
  • kernel_size(int or tuple):卷积核的尺寸,单个值则认为卷积核长宽相同
  • stride(int or tuple):卷积步长
  • padding(int or tuple, optional):输入的每一条边填充0的圈数,参数可选,默认为0
  • bias(bool, optional):如果bias=True,添加偏置。

这里需要补充一下多维数据中卷积是如何计算的

对于一张三通道的图片,每个通道对应一个卷积核,最后计算得到三个结果矩阵,三个结果矩阵对应值相加到最后的结果,即为一个输出通道。输出形状的计算可参考前文。

torch.nn.MaxPool2d(kernel_size,stride=None,padding=0,diltion=1,return_indices=False,ceil_mode=False) 其中主要参数如下:

  • kernel_size:池化窗口的大小[height, weight],如果一个数,则两者相等
  • stride:窗口在每个维度上滑动的步长,一般为[stride_h, stride_w],如果两者相等,则可为一个数字

输出形状的计算可参考前文。

3. 选择优化器和损失函数

由于是分类问题,以及做个简单的模型实现,选择交叉熵损失函数以及带动量的随机梯度下降算法,如下:

## 选择优化器
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

4. 模型训练

模型训练10轮,使用train_loader构建的mini-batch迭代器进行mini-batch的数据训练,每2000个mini-batch打印一次。代码如下:

## 训练模型
for epoch in range(10):
    running_loss = 0.0
    # 迭代,批次训练
    for i, data in enumerate(train_loader, 0):
        # 获取训练数据
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)
        # 权重参数梯度清零
        optimizer.zero_grad()

        # 正向传播
        outputs = net(inputs)
        # 计算损失值
        loss = criterion(outputs, labels)
        # 反向传播
        loss.backward()
        # 参数更新
        optimizer.step()
        # 损失值累加
        running_loss += loss.item()
        # 每2000个mini-batch显示一次损失值
        if i % 2000 == 1999:
            print('[%d, %d] loss:%.3f' % (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0
print('Finished Training')

对应的训练过程如下图:

5. 模型测试

模型训练结束之后,就可以进行模型的测试了。模型使用时,不需要进去相关梯度计算,则需要使用torch.no_grad()方法。

correct = 0    # 预测正确数目
total = 0     # 测试样本总数
with torch.no_grad():
    for data in test_loader:
        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))
# Accuracy of the network on the 10000 test images: 68 %

最后得到的结果是:这个简单的CNN模型对10分类的数据正确率达到68%,总体还是可以的。我们可以看看各个类别预测的正确率,使用代码如下:

## 各类别的准确率
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in test_loader:
        images, labels = data
        images, labels = images.to(device), labels.to(device)
        outputs = net(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1

for i in range(10):
    print('Accuracy of %5s: %2d %%' %(classes[i], 100 * class_correct[i] /class_total[i]))

结果如下:

Accuracy of plane: 74 %
Accuracy of   car: 83 %
Accuracy of  bird: 56 %
Accuracy of   cat: 41 %
Accuracy of  deer: 65 %
Accuracy of   dog: 61 %
Accuracy of  frog: 75 %
Accuracy of horse: 73 %
Accuracy of  ship: 78 %
Accuracy of truck: 71 %

6. 总结

总体来说,CNN是一个简单而高效的神经网络算法,当前也有很多基于经典CNN改进的卷积神经网络,感兴趣的可以深入学习,后面我们可以看看CNN是如何今学期文本分类的,也就是textcnn模型。

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
ladoo
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
ladoo
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区