pytorch学习——卷积神经网络应用在CIFAR10数据集

本文是参照官方教程https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py
pytorch中提供了一个名为torchvision,其中包含了一些常用的数据集。

  • 定义转换操作
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(
        mean=(0.5, 0.5, 0.5),
        std=(0.5, 0.5, 0.5))])

transforms.Compose()用于将多个转换组合在一起。

  • 加载数据
trainset = torchvision.datasets.CIFAR10(root='./data',
                                        train=True,
                                        download=True,
                                        transform=transform)
# root 用于指定数据集在下载之后的存放路径
# transform 用于指定导入数据集需要对数据进行那种变化操作
# train是指定在数据集下载完成后需要载入那部分数据,
# 如果设置为True 则说明载入的是该数据集的训练集部分
# 如果设置为FALSE 则说明载入的是该数据集的测试集部分

trainloader = torch.utils.data.DataLoader(trainset,
                                          batch_size=4,
                                          shuffle=True,
                                          num_workers=0)
# 下面对数据进行装载,我们可以将数据的载入理解为对图片的处理,
# 在处理完成后,我们就需要将这些图片打包好送给我们的模型进行训练 了  而装载就是这个打包的过程
# dataset 参数用于指定我们载入的数据集名称
# batch_size参数设置了每个包中的图片数据个数
# shuffle决定是否会在装载的过程会将数据随机打乱顺序并进打包
# num_workers要使用多少子进程来加载数据。0表示数据将在主进程中加载。(默认值:0)

testset = torchvision.datasets.CIFAR10(root='./data',
                                       train=False,
                                       download=True,
                                       transform=transform)

testloader = torch.utils.data.DataLoader(testset,
                                         batch_size=4,
                                         shuffle=False,
                                         num_workers=0)

  • 构建卷积神经网络模型
#构建模型
class CNN(torch.nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = torch.nn.Sequential(
            torch.nn.Conv2d(3, 6, 5),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2, stride=2)
            # kernel_size表示池化窗口大小2*2
            # stride表示池化窗口移动步长
        )
        self.conv2 = torch.nn.Sequential(
            torch.nn.Conv2d(6, 16, 5),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.fc1 = torch.nn.Sequential(
            torch.nn.Linear(16 * 5 * 5, 120),
            torch.nn.ReLU()
        )
        self.fc2 = torch.nn.Sequential(
            torch.nn.Linear(120, 84),
            torch.nn.ReLU()
        )
        self.fc3 = torch.nn.Sequential(
            torch.nn.Linear(84, 10)
            # 注意此处无激活函数
        )

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(-1, 16 * 5 * 5)
        # 对参数实现扁平化,否则全连接层的实际输
        # 出的参数维度和其定义输入的维度不匹配,程序报错
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x

- 训练前的准备

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
cnn = CNN()
cnn.to(device)
#或者直接cnn=cnn.cuda(),(前提是你的电脑装了cuda)训练中的代码要做出变化

learning_rate = 0.001
epoch_n = 2
loss_fc = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(params=cnn.parameters(), lr=learning_rate, momentum=0.9)

这里强烈建议安装CUDA,速度提升的不是一点。。。
在调用cuda时,可以使用以上方法,也可以使用例如:

cnn=cnn.cuda()

也可以应用另外一种方法:

cnn = torch.cuda(cnn)

但是前提是计算机中安装过了,否则可以用torch.cuda.is_available()判断一下。

  • 训练模型
# 训练
for epoch in range(epoch_n):
    running_loss = 0.0  # 累积损失
    for i, data in enumerate(trainloader, 0):

        #input, label=data
        #input=input.cude()
        #label=label.cuda()
        input, label = data[0].to(device), data[1].to(device)

        output = cnn(input)
        loss = loss_fc(output, label)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        running_loss += loss.item()

        if i % 2000 == 1999:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0  # 2000次归零一次

print('Finished Training')
  • 测试
    由于是分类任务,这里计算了整个测试集的准确率和10类样本分别的准确率。
# 整体准确率
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data[0].to(device), data[1].to(device)
        outputs = cnn(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))
# 各个类的准确率
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 testloader:
        # images, labels = data
        images, labels = data[0].to(device), data[1].to(device)
        outputs = cnn(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):  # range里面是4,是因为batch_size=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]))

整体的代码结构

import torch
import torch.nn
import torch.optim
import torch.utils.data
import torchvision

from torch.autograd import Variable
from torchvision import datasets
from torchvision import transforms

#数据处理
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(
        mean=(0.5, 0.5, 0.5),
        std=(0.5, 0.5, 0.5))])
# transforms.Compose用于将多个转换组合在一起

trainset = torchvision.datasets.CIFAR10(root='./data',
                                        train=True,
                                        download=True,
                                        transform=transform)
# root 用于指定数据集在下载之后的存放路径
# transform 用于指定导入数据集需要对数据进行那种变化操作
# train是指定在数据集下载完成后需要载入那部分数据,
# 如果设置为True 则说明载入的是该数据集的训练集部分
# 如果设置为FALSE 则说明载入的是该数据集的测试集部分

trainloader = torch.utils.data.DataLoader(trainset,
                                          batch_size=4,
                                          shuffle=True,
                                          num_workers=0)
# 下面对数据进行装载,我们可以将数据的载入理解为对图片的处理,
# 在处理完成后,我们就需要将这些图片打包好送给我们的模型进行训练 了  而装载就是这个打包的过程
# dataset 参数用于指定我们载入的数据集名称
# batch_size参数设置了每个包中的图片数据个数
# shuffle决定是否会在装载的过程会将数据随机打乱顺序并进打包
# num_workers要使用多少子进程来加载数据。0表示数据将在主进程中加载。(默认值:0)

testset = torchvision.datasets.CIFAR10(root='./data',
                                       train=False,
                                       download=True,
                                       transform=transform)

testloader = torch.utils.data.DataLoader(testset,
                                         batch_size=4,
                                         shuffle=False,
                                         num_workers=0)

classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

#构建模型
class CNN(torch.nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = torch.nn.Sequential(
            torch.nn.Conv2d(3, 6, 5),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2, stride=2)
            # kernel_size表示池化窗口大小2*2
            # stride表示池化窗口移动步长
        )
        self.conv2 = torch.nn.Sequential(
            torch.nn.Conv2d(6, 16, 5),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.fc1 = torch.nn.Sequential(
            torch.nn.Linear(16 * 5 * 5, 120),
            torch.nn.ReLU()
        )
        self.fc2 = torch.nn.Sequential(
            torch.nn.Linear(120, 84),
            torch.nn.ReLU()
        )
        self.fc3 = torch.nn.Sequential(
            torch.nn.Linear(84, 10)
            # 注意此处无激活函数
        )

    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        x = x.view(-1, 16 * 5 * 5)
        # 对参数实现扁平化,否则全连接层的实际输
        # 出的参数维度和其定义输入的维度不匹配,程序报错
        x = self.fc1(x)
        x = self.fc2(x)
        x = self.fc3(x)
        return x

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
cnn = CNN()
cnn.to(device)
#或者直接cnn=cnn.cuda(),(前提是你的电脑装了cuda)训练中的代码要做出变化

learning_rate = 0.001
epoch_n = 2
loss_fc = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(params=cnn.parameters(), lr=learning_rate, momentum=0.9)

# 训练
for epoch in range(epoch_n):
    running_loss = 0.0  # 累积损失
    for i, data in enumerate(trainloader, 0):

        #input, label=data
        #input=input.cude()
        #label=label.cuda()
        input, label = data[0].to(device), data[1].to(device)

        output = cnn(input)
        loss = loss_fc(output, label)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        running_loss += loss.item()

        if i % 2000 == 1999:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0  # 2000次归零一次

print('Finished Training')

# 整体准确率
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data[0].to(device), data[1].to(device)
        outputs = cnn(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))

# 各个类的准确率
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 testloader:
        # images, labels = data
        images, labels = data[0].to(device), data[1].to(device)
        outputs = cnn(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):  # range里面是4,是因为batch_size=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]))

以上便是官方教程中关于CIFAR10的代码,教程有些问题,如果完全按照教程写,则会出现BrokenPipeError: [Errno 32] Broken pipe的错误提示,这是因为windows中多进程的问题,解决方法是将torch.utils.data.DataLoader()中的num_workers赋值为0(原教程中为2)
如下所以:

trainloader = torch.utils.data.DataLoader(trainset,
                                          batch_size=4,
                                          shuffle=True,
                                          num_workers=0)

测试集和训练集都要更改。

以上便是的在学习官方教程中的过程,如有错误请直接评论或联系qq:1932859223,谢谢!!!

你可能感兴趣的:(pytorch学习)