|
pytorch训练一个cifar10的分类器
上一讲中已经看到如何去定义一个神经网络,计算损失值和更新网络的权重。 你现在可能在想下一步。
关于数据?
一般情况下处理图像、文本、音频和视频数据时,可以使用标准的Python包来加载数据到一个numpy数组中。 然后把这个数组转换成 torch.*Tensor。
图像可以使用 Pillow, OpenCV
音频可以使用 scipy, librosa
文本可以使用原始Python和Cython来加载,或者使用 NLTK或 SpaCy 处理
特别的,对于图像任务,我们创建了一个包 torchvision,它包含了处理一些基本图像数据集的方法。这些数据集包括 Imagenet, CIFAR10, MNIST 等。除了数据加载以外,torchvision 还包含了图像转换器, torchvision.datasets 和 torch.utils.data.DataLoader。
torchvision包不仅提供了巨大的便利,也避免了代码的重复。
在这个教程中,我们使用CIFAR10数据集,它有如下10个类别 :‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。CIFAR-10的图像都是 3x32x32大小的,即,3颜色通道,32x32像素
- # -*- coding: utf-8 -*-
- __author__ = u'东方耀 微信:dfy_88888'
- __date__ = '2020/4/9 下午5:20'
- __product__ = 'PyCharm'
- __filename__ = 'dfy02'
- # 训练一个图像分类器
- # 依次按照下列顺序进行:
- #
- # 1、使用torchvision加载和归一化CIFAR10训练集和测试集
- # 2、定义一个卷积神经网络
- # 3、定义损失函数
- # 4、在训练集上训练网络
- # 5、在测试集上测试网络
- # 1、读取和归一化 CIFAR10
- # 使用torchvision可以非常容易地加载CIFAR10。
- import torch
- import torchvision
- import torchvision.transforms as transforms
- # torchvision的输出是[0,1]的PILImage图像,我们把它转换为归一化范围为[-1, 1]的张量。
- transform = transforms.Compose(
- [transforms.ToTensor(),
- transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))])
- trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
- download=True, transform=transform)
- trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
- shuffle=True, num_workers=2)
- # 下载数据 https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
- 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=2)
- classes = ('plane', 'car', 'bird', 'cat',
- 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
- import matplotlib.pyplot as plt
- import numpy as np
- # 展示图像的函数
- def imshow(img):
- # [-1, 1] to [0,1]
- img = img / 2 + 0.5 # unnormalize
- npimg = img.numpy()
- # CHW ---> HWC
- plt.imshow(np.transpose(npimg, (1, 2, 0)))
- # 获取随机数据
- dataiter = iter(trainloader) # 迭代器
- images, labels = dataiter.next()
- # [4, 3, 32, 32]
- print(images.size())
- # [4,]
- print('标签数据:', labels.size(), labels.numpy())
- # 展示图像
- imshow(torchvision.utils.make_grid(images))
- # 显示图像标签
- print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
- # plt.show()
- # 2、定义一个卷积神经网络
- import torch.nn as nn
- import torch.nn.functional as F
- class Net(nn.Module):
- def __init__(self):
- super(Net, self).__init__()
- # 二维卷积 5*5*3*6
- self.conv1 = nn.Conv2d(3, 6, 5)
- self.pool = nn.MaxPool2d(2, 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):
- # 输入的x的size = [4, 3, 32, 32]
- x = self.pool(F.relu(self.conv1(x)))
- 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)
- # x = F.softmax(x, dim=1)
- return x
- net = Net()
- print('net的结构:', net)
- params = list(net.parameters())
- print(len(params))
- print("conv1's .weight size=", params[0].size())
- for i in range(len(params)):
- print('layer-%d的权重size=' % i, params[i].size())
- # 3、定义损失函数和优化器
- # 我们使用交叉熵作为损失函数,使用带动量的随机梯度下降。
- import torch.optim as optim
- criterion = nn.CrossEntropyLoss()
- optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
- # 4、训练网路
- # 我们只需在数据迭代器上循环,将数据输入给网络,并优化。
- for epoch in range(2): # 多批次循环
- running_loss = 0.0
- print('开始第%d轮的训练!' % epoch)
- for i, data in enumerate(trainloader, 0):
- # 获取输入
- inputs, labels = data
- # torch.Size([4, 3, 32, 32])
- # print('inputs.size=', inputs.size())
- # 梯度置0
- optimizer.zero_grad()
- # 正向传播,反向传播,优化
- outputs = net(inputs)
- loss = criterion(outputs, labels)
- # 反向传播 计算梯度
- loss.backward()
- # 优化器更新网络参数
- optimizer.step()
- # 打印状态信息
- # 如果你有只有一个元素的张量,使用.item()来得到Python数据类型的数值
- running_loss += loss.item()
- if i % 2000 == 1999: # 每2000批次打印一次
- print('[第%d轮, %5d] loss: %.4f' %
- (epoch, i + 1, running_loss / 2000))
- running_loss = 0.0
- print('Finished Training')
- # 5、在测试集上测试网络
- # 我们在整个训练集上进行了2轮训练,但是我们需要检查网络是否从数据集中学习到有用的东西。
- # 通过预测神经网络输出的类别标签与实际情况标签进行对比来进行检测。
- # 如果预测正确,我们把该样本添加到正确预测列表。
- # 第一步,显示测试集中的图片并熟悉图片内容
- dataiter = iter(testloader)
- images, labels = dataiter.next()
- # 显示图片
- imshow(torchvision.utils.make_grid(images))
- print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
- # 让我们看看神经网络认为以上图片是什么。
- outputs = net(images)
- # 4*10
- # outputs.data
- _, predicted = torch.max(outputs, 1)
- print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
- for j in range(4)))
- # 接下来让看看网络在整个测试集上的结果如何。
- correct = 0
- total = 0
- with torch.no_grad():
- for data in testloader:
- images, labels = data
- outputs = net(images)
- _, predicted = torch.max(outputs.data, 1)
- total += labels.size(0)
- correct += (predicted == labels).sum().item()
- # Accuracy of the network on the 10000 test images: 54 %
- print('Accuracy of the network on the 10000 test images: %d %%' % (
- 100 * correct / total))
- # 结果看起来不错,至少比随机选择要好,随机选择的正确率为10%。 似乎网络学习到了一些东西。
- #
- # 在识别哪一个类的时候好,哪一个不好呢?
- 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
- 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]))
复制代码
我们如何在GPU上运行神经网络呢?
在GPU上训练
把一个神经网络移动到GPU上训练就像把一个Tensor转换GPU上一样简单。
并且这个操作会递归遍历有所模块,并将其参数和缓冲区转换为CUDA张量。
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)
这些方法将递归遍历所有模块并将模块的参数和缓冲区 转换成CUDA张量:
net.to(device)
记住:inputs 和 targets 也要转换。
inputs, labels = inputs.to(device), labels.to(device)
为什么我们没注意到GPU的速度提升很多?那是因为网络非常的小。
# cpu上训练的耗时: 106.1030011177063 秒
# gpu上的耗时:65.4867947101593 秒
- # -*- coding: utf-8 -*-
- __author__ = u'东方耀 微信:dfy_88888'
- __date__ = '2020/4/9 下午5:20'
- __product__ = 'PyCharm'
- __filename__ = 'dfy02'
- # 训练一个图像分类器
- # 依次按照下列顺序进行:
- #
- # 1、使用torchvision加载和归一化CIFAR10训练集和测试集
- # 2、定义一个卷积神经网络
- # 3、定义损失函数
- # 4、在训练集上训练网络
- # 5、在测试集上测试网络
- # 1、读取和归一化 CIFAR10
- # 使用torchvision可以非常容易地加载CIFAR10。
- import torch
- import torchvision
- import torchvision.transforms as transforms
- # torchvision的输出是[0,1]的PILImage图像,我们把它转换为归一化范围为[-1, 1]的张量。
- transform = transforms.Compose(
- [transforms.ToTensor(),
- transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))])
- trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
- download=True, transform=transform)
- trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
- shuffle=True, num_workers=2)
- # 下载数据 https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
- 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=2)
- classes = ('plane', 'car', 'bird', 'cat',
- 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
- import matplotlib.pyplot as plt
- import numpy as np
- # 展示图像的函数
- def imshow(img):
- # [-1, 1] to [0,1]
- img = img / 2 + 0.5 # unnormalize
- npimg = img.numpy()
- # CHW ---> HWC
- plt.imshow(np.transpose(npimg, (1, 2, 0)))
- # 获取随机数据
- dataiter = iter(trainloader) # 迭代器
- images, labels = dataiter.next()
- # [4, 3, 32, 32]
- print(images.size())
- # [4,]
- print('标签数据:', labels.size(), labels.numpy())
- # 展示图像
- imshow(torchvision.utils.make_grid(images))
- # 显示图像标签
- print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
- # plt.show()
- # 2、定义一个卷积神经网络
- import torch.nn as nn
- import torch.nn.functional as F
- class Net(nn.Module):
- def __init__(self):
- super(Net, self).__init__()
- # 二维卷积 5*5*3*6
- self.conv1 = nn.Conv2d(3, 6, 5)
- self.pool = nn.MaxPool2d(2, 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):
- # 输入的x的size = [4, 3, 32, 32]
- x = self.pool(F.relu(self.conv1(x)))
- 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)
- # x = F.softmax(x, dim=1)
- return x
- net = Net()
- device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
- print(device)
- net.to(device)
- print('net的结构:', net)
- params = list(net.parameters())
- print(len(params))
- print("conv1's .weight size=", params[0].size())
- for i in range(len(params)):
- print('layer-%d的权重size=' % i, params[i].size())
- # 3、定义损失函数和优化器
- # 我们使用交叉熵作为损失函数,使用带动量的随机梯度下降。
- import torch.optim as optim
- criterion = nn.CrossEntropyLoss()
- optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
- import time
- start_time = time.time()
- # 4、训练网路
- # 我们只需在数据迭代器上循环,将数据输入给网络,并优化。
- for epoch in range(2): # 多批次循环
- running_loss = 0.0
- print('开始第%d轮的训练!' % epoch)
- for i, data in enumerate(trainloader, 0):
- # 获取输入
- inputs, labels = data
- # torch.Size([4, 3, 32, 32])
- # print('inputs.size=', inputs.size())
- # 记住:inputs 和 targets 也要转换
- inputs, labels = inputs.to(device), labels.to(device)
- # 梯度置0
- optimizer.zero_grad()
- # 正向传播,反向传播,优化
- outputs = net(inputs)
- loss = criterion(outputs, labels)
- # 反向传播 计算梯度
- loss.backward()
- # 优化器更新网络参数
- optimizer.step()
- # 打印状态信息
- # 如果你有只有一个元素的张量,使用.item()来得到Python数据类型的数值
- running_loss += loss.item()
- if i % 2000 == 1999: # 每2000批次打印一次
- print('[第%d轮, %5d] loss: %.4f' %
- (epoch, i + 1, running_loss / 2000))
- running_loss = 0.0
- # cpu上训练的耗时: 106.1030011177063 秒
- # gpu上的耗时:65.4867947101593 秒
- print('Finished Training, 共耗时:', time.time() - start_time)
- # 5、在测试集上测试网络
- # 我们在整个训练集上进行了2轮训练,但是我们需要检查网络是否从数据集中学习到有用的东西。
- # 通过预测神经网络输出的类别标签与实际情况标签进行对比来进行检测。
- # 如果预测正确,我们把该样本添加到正确预测列表。
- # 第一步,显示测试集中的图片并熟悉图片内容
- dataiter = iter(testloader)
- images, labels = dataiter.next()
- # 显示图片
- imshow(torchvision.utils.make_grid(images))
- print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
- # 让我们看看神经网络认为以上图片是什么。
- # RuntimeError: Input type (torch.FloatTensor)
- # and weight type (torch.cuda.FloatTensor) should be the same
- images = images.to(device)
- outputs = net(images)
- # 4*10
- # outputs.data
- _, predicted = torch.max(outputs, 1)
- print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
- for j in range(4)))
- # 接下来让看看网络在整个测试集上的结果如何。
- correct = 0
- total = 0
- with torch.no_grad():
- for data in testloader:
- 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()
- # Accuracy of the network on the 10000 test images: 54 %
- print('Accuracy of the network on the 10000 test images: %d %%' % (
- 100 * correct / total))
- # 结果看起来不错,至少比随机选择要好,随机选择的正确率为10%。 似乎网络学习到了一些东西。
- #
- # 在识别哪一个类的时候好,哪一个不好呢?
- 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 = 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]))
复制代码
|
|