pytorch 实现图片分类(CIFAR-10)

步骤

官方教程:https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#loading-and-normalizing-cifar10
步骤:
A、Load and normalizing the CIFAR10 training and test datasets using torchvision
B、Define a Convolution Neural Network
C、Define a loss function
D、Train the network on the training data
E、Test the network on the test data

数据集介绍

在这里插入图片描述
CIFAR-10包含10个类别,50,000个训练图像,彩色图像大小:32x32,10,000个测试图像。CIFAR-100与CIFAR-10类似,包含100个类,每类有600张图片,其中500张用于训练,100张用于测试;这100个类分组成20个超类。图像类别均有明确标注。
详细见官方文档说明:http://www.cs.toronto.edu/~kriz/cifar.html

代码

总共有三个py文件,文件名分别为:dataset(数据预处理和加载)、model(网络模型搭建)、train(训练模型并测试)

数据预处理和加载

PyTorch框架中有一个非常重要且好用的包:torchvision,该包可以用来对数据进行预处理,也可以用来进行数据增强的操作。其主要由3个子包组成,分别是:torchvision.datasetstorchvision.modelstorchvision.transforms

  • torchvision.datasets模块中保存了常用的深度学习数据集,例如cifar10、Imagenet、Mnist等。可以直接使用该模块下载指定的数据集。
  • torchvision.transforms模块用于对datasets模快下载的数据进行预处理操作。
  • torchvision.models模块保存了一些经典的网络模型。

在这里插入图片描述
root:表示存放下载的数据集存放的位置
train:如果为True,则从training.pt创建数据集,否则从test.pt创建数据集。
transform:接受PIL图像并对数据进行预处理
download:如果为True,就从网上下载,如果已经有下载好的数据就不会重复下载了
target_transform:接受目标并对其进行转换的函数/转换。

from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import numpy as np

# transforms模块中的Compose( )可以把多个变换组合在一起,需要写成列表的形式
# 将PIL图片或者numpy.ndarray(HxWxC) (范围在0-255) 转成torch.FloatTensor (CxHxW) (范围为0.0-1.0)
# 归一化,RGB三个通道上的均值(0.5,0.5,0.5),三个通道的标准差(0.5, 0.5, 0.5)
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

# 下载数据集,并将其保存在当前文件夹下的CIFAR文件夹中,并对其进行transform变换
trainset = datasets.CIFAR10(root='./CIFAR', train=True, download=True, transform=transform)
testset = datasets.CIFAR10(root='./CIFAR', train=False, download=True, transform=transform)

# 打印出数据和标签的维度, 标签是list,需要将其转换成numpy数组才能查看其维度
print("train:", trainset.data.shape)
print("train_label:", np.array(trainset.targets).shape)
print("test:", testset.data.shape)
print("test_label:", np.array(testset.targets).shape)

# 数据加载,
trainloader = DataLoader(trainset, batch_size=32,shuffle=True, num_workers=2)
testloader = DataLoader(testset, batch_size=32, shuffle=False, num_workers=2)

# 类别信息也是需要我们给定的
classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')


if __name__ == '__main__':
    print("训练集长度", len(trainset))
    print("测试集集长度", len(testset))
    # 每训练完一个epoch,需要训练多少个批次
    print("训练集的总批次数", len(trainloader))
    print("测试集的总批次数", len(testloader))

from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import numpy as np

# transforms模块中的Compose( )可以把多个变换组合在一起,需要写成列表的形式
# 将PIL图片或者numpy.ndarray(HxWxC) (范围在0-255) 转成torch.FloatTensor (CxHxW) (范围为0.0-1.0)
# 归一化,RGB三个通道上的均值(0.5,0.5,0.5),三个通道的标准差(0.5, 0.5, 0.5)
transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

# 下载数据集,并将其保存在当前文件夹下的CIFAR文件夹中,并对其进行transform变换
trainset = datasets.CIFAR10(root='./CIFAR', train=True, download=True, transform=transform)
testset = datasets.CIFAR10(root='./CIFAR', train=False, download=True, transform=transform)

# 打印出数据和标签的维度, 标签是list,需要将其转换成numpy数组才能查看其维度
print("train:", trainset.data.shape)
print("train_label:", np.array(trainset.targets).shape)
print("test:", testset.data.shape)
print("test_label:", np.array(testset.targets).shape)

# 数据加载,
trainloader = DataLoader(trainset, batch_size=32,shuffle=True, num_workers=2)
testloader = DataLoader(testset, batch_size=32, shuffle=False, num_workers=2)

# 类别信息也是需要我们给定的
classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')


if __name__ == '__main__':
    print("训练集长度", len(trainset))
    print("测试集集长度", len(testset))
    # 每训练完一个epoch,需要训练多少个批次
    print("训练集的总批次数", len(trainloader))
    print("测试集的总批次数", len(testloader))

# 结果
Files already downloaded and verified
Files already downloaded and verified
train: (50000, 32, 32, 3)
train_label: (50000,)
test: (10000, 32, 32, 3)
test_label: (10000,)
训练集长度 50000
测试集集长度 10000
训练集的总批次数 1563
测试集的总批次数 313

网络模型搭建

model.py

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


class Net(nn.Module):  # 我们定义网络时一般是继承的torch.nn.Module创建新的子类
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=6, kernel_size=5)  # 卷积层,默认padding=0,stride=1
        self.pool = nn.MaxPool2d(kernel_size=2, stride=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):  # 前向传播,反向传播涉及到torch.autograd模块
        x = self.pool(F.relu(self.conv1(x)))  # F是torch.nn.functional的别名,这里调用了relu函数 F.relu()
        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

if __name__ == '__main__':
    model = Net()
    print(model)

    input = torch.randn(1,3,32,32)
    output = model(input)
    print("input", input.shape)
    print("output", output.shape)

在这里插入图片描述

训练并测试

import torch
from torch.autograd import Variable

# 导入
from dataset import trainloader,testloader,trainset,testset
from model import Net

# 定义超参数
learning_rate = 1e-3
momentum = 0.9
num_epoches = 20
batch_size = 32

model = Net()
#判断是否有GPU, 如果使用GPU就将模型放到GPU中进行训练
use_gpu = torch.cuda.is_available()
if use_gpu:
    model.cuda()
print(model)

# 交叉熵损失函数
criterion = torch.nn.CrossEntropyLoss()
# SGD梯度下降方法
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum)

# 训练
for epoch in range(num_epoches):
    print("*"*10)
    print("epoch{}".format(epoch+1))
    train_loss = 0.0
    train_acc =0.0
    for i,data in enumerate(trainloader,0): # enumerate是python的内置函数,既获得索引也获得数据
    #for image, label in trainloader:
        image, label = data # data包含数据和标签信息
        # 将数据转换成Variable
        if use_gpu:
            image = Variable(image).cuda()
            label = Variable(label).cuda()
        else:
            image = Variable(image)
            label = Variable(label)

        # 要把梯度重新归零,因为反向传播过程中梯度会累加上一次循环的梯度
        optimizer.zero_grad()

        output = model(image)
        loss = criterion(output, label)
        train_loss += loss.item()*label.size(0) # 此处是什么意思?
        # train_loss += loss.item() 也可以
        _, pred = torch.max(output,1) # 返回每行的最大值的索引值,也就是预测出的可能性最大的类别的相应的标签
        train_correct = (pred == label).sum()
        train_acc += train_correct.item()

        loss.backward() # 反向传播
        optimizer.step() # 梯度更新
        
    # 每训练完一个周期打印一次平均损失和平均精度
    print('Finish {} epoch, Loss: {:.6f}, Acc: {:.6f}'.format(
        epoch + 1, train_loss / (len(trainset)), train_acc / (len(trainset))
    ))

# 测试
model.eval()
eval_loss = 0.0
eval_acc = 0.0
for image, label in testloader:
    if use_gpu:
        image = Variable(image).cuda()
        label = Variable(label).cuda()
    else:
        image = Variable(image)
        label = Variable(label)

    output = model(image)
    loss = criterion(output, label)
    eval_loss += loss.item()*label.size(0) # 此处是什么意思?
    _, predicted = torch.max(output, 1)
    eval_correct = (predicted == label).sum()
    eval_acc += eval_correct.item()
print("Test Loss: {:.6f}, Acc: {:.6f}".format(
    eval_loss/len(testset), eval_acc/len(testset)
))

在这里插入图片描述

参考文献

Pytorch打怪路(一)pytorch进行CIFAR-10分类(1)CIFAR-10数据加载和处理
Pytorch打怪路(一)pytorch进行CIFAR-10分类(2)定义卷积神经网络
Pytorch打怪路(一)pytorch进行CIFAR-10分类(3)定义损失函数和优化器
Pytorch打怪路(一)pytorch进行CIFAR-10分类(4)训练
Pytorch打怪路(一)pytorch进行CIFAR-10分类(5)测试

  • 2
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值