东方耀AI技术分享

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 3309|回复: 2
打印 上一主题 下一主题

[PyTorch] 04、pytorch训练一个cifar10的分类器

[复制链接]

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
跳转到指定楼层
楼主
发表于 2020-4-9 17:18:57 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
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像素

  1. # -*- coding: utf-8 -*-
  2. __author__ = u'东方耀 微信:dfy_88888'
  3. __date__ = '2020/4/9 下午5:20'
  4. __product__ = 'PyCharm'
  5. __filename__ = 'dfy02'


  6. # 训练一个图像分类器
  7. # 依次按照下列顺序进行:
  8. #
  9. # 1、使用torchvision加载和归一化CIFAR10训练集和测试集
  10. # 2、定义一个卷积神经网络
  11. # 3、定义损失函数
  12. # 4、在训练集上训练网络
  13. # 5、在测试集上测试网络


  14. # 1、读取和归一化 CIFAR10
  15. # 使用torchvision可以非常容易地加载CIFAR10。
  16. import torch
  17. import torchvision
  18. import torchvision.transforms as transforms
  19. # torchvision的输出是[0,1]的PILImage图像,我们把它转换为归一化范围为[-1, 1]的张量。

  20. transform = transforms.Compose(
  21.     [transforms.ToTensor(),
  22.      transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))])

  23. trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
  24.                                         download=True, transform=transform)
  25. trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
  26.                                           shuffle=True, num_workers=2)
  27. # 下载数据 https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
  28. testset = torchvision.datasets.CIFAR10(root='./data', train=False,
  29.                                        download=True, transform=transform)
  30. testloader = torch.utils.data.DataLoader(testset, batch_size=4,
  31.                                          shuffle=False, num_workers=2)

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

  34. import matplotlib.pyplot as plt
  35. import numpy as np

  36. # 展示图像的函数


  37. def imshow(img):
  38.     # [-1, 1] to [0,1]
  39.     img = img / 2 + 0.5     # unnormalize
  40.     npimg = img.numpy()
  41.     # CHW ---> HWC
  42.     plt.imshow(np.transpose(npimg, (1, 2, 0)))


  43. # 获取随机数据
  44. dataiter = iter(trainloader)  # 迭代器
  45. images, labels = dataiter.next()
  46. # [4, 3, 32, 32]
  47. print(images.size())
  48. # [4,]
  49. print('标签数据:', labels.size(), labels.numpy())

  50. # 展示图像
  51. imshow(torchvision.utils.make_grid(images))
  52. # 显示图像标签
  53. print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

  54. # plt.show()

  55. # 2、定义一个卷积神经网络
  56. import torch.nn as nn
  57. import torch.nn.functional as F


  58. class Net(nn.Module):
  59.     def __init__(self):
  60.         super(Net, self).__init__()
  61.         # 二维卷积 5*5*3*6
  62.         self.conv1 = nn.Conv2d(3, 6, 5)
  63.         self.pool = nn.MaxPool2d(2, 2)
  64.         self.conv2 = nn.Conv2d(6, 16, 5)
  65.         self.fc1 = nn.Linear(16 * 5 * 5, 120)
  66.         self.fc2 = nn.Linear(120, 84)
  67.         self.fc3 = nn.Linear(84, 10)

  68.     def forward(self, x):
  69.         # 输入的x的size = [4, 3, 32, 32]
  70.         x = self.pool(F.relu(self.conv1(x)))
  71.         x = self.pool(F.relu(self.conv2(x)))
  72.         x = x.view(-1, 16 * 5 * 5)
  73.         x = F.relu(self.fc1(x))
  74.         x = F.relu(self.fc2(x))
  75.         x = self.fc3(x)
  76.         # x = F.softmax(x, dim=1)
  77.         return x


  78. net = Net()
  79. print('net的结构:', net)
  80. params = list(net.parameters())
  81. print(len(params))
  82. print("conv1's .weight size=", params[0].size())
  83. for i in range(len(params)):
  84.     print('layer-%d的权重size=' % i, params[i].size())

  85. # 3、定义损失函数和优化器
  86. # 我们使用交叉熵作为损失函数,使用带动量的随机梯度下降。
  87. import torch.optim as optim

  88. criterion = nn.CrossEntropyLoss()
  89. optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

  90. # 4、训练网路
  91. # 我们只需在数据迭代器上循环,将数据输入给网络,并优化。
  92. for epoch in range(2):  # 多批次循环

  93.     running_loss = 0.0
  94.     print('开始第%d轮的训练!' % epoch)
  95.     for i, data in enumerate(trainloader, 0):
  96.         # 获取输入
  97.         inputs, labels = data
  98.         # torch.Size([4, 3, 32, 32])
  99.         # print('inputs.size=', inputs.size())

  100.         # 梯度置0
  101.         optimizer.zero_grad()

  102.         # 正向传播,反向传播,优化
  103.         outputs = net(inputs)
  104.         loss = criterion(outputs, labels)
  105.         # 反向传播 计算梯度
  106.         loss.backward()
  107.         # 优化器更新网络参数
  108.         optimizer.step()

  109.         # 打印状态信息
  110.         # 如果你有只有一个元素的张量,使用.item()来得到Python数据类型的数值
  111.         running_loss += loss.item()
  112.         if i % 2000 == 1999:    # 每2000批次打印一次
  113.             print('[第%d轮, %5d] loss: %.4f' %
  114.                   (epoch, i + 1, running_loss / 2000))
  115.             running_loss = 0.0

  116. print('Finished Training')

  117. # 5、在测试集上测试网络
  118. # 我们在整个训练集上进行了2轮训练,但是我们需要检查网络是否从数据集中学习到有用的东西。
  119. # 通过预测神经网络输出的类别标签与实际情况标签进行对比来进行检测。
  120. # 如果预测正确,我们把该样本添加到正确预测列表。

  121. # 第一步,显示测试集中的图片并熟悉图片内容
  122. dataiter = iter(testloader)
  123. images, labels = dataiter.next()

  124. # 显示图片
  125. imshow(torchvision.utils.make_grid(images))
  126. print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

  127. # 让我们看看神经网络认为以上图片是什么。
  128. outputs = net(images)
  129. # 4*10
  130. # outputs.data
  131. _, predicted = torch.max(outputs, 1)

  132. print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
  133.                               for j in range(4)))

  134. # 接下来让看看网络在整个测试集上的结果如何。
  135. correct = 0
  136. total = 0
  137. with torch.no_grad():
  138.     for data in testloader:
  139.         images, labels = data
  140.         outputs = net(images)
  141.         _, predicted = torch.max(outputs.data, 1)
  142.         total += labels.size(0)
  143.         correct += (predicted == labels).sum().item()

  144. # Accuracy of the network on the 10000 test images: 54 %
  145. print('Accuracy of the network on the 10000 test images: %d %%' % (
  146.     100 * correct / total))

  147. # 结果看起来不错,至少比随机选择要好,随机选择的正确率为10%。 似乎网络学习到了一些东西。
  148. #
  149. # 在识别哪一个类的时候好,哪一个不好呢?
  150. class_correct = list(0. for i in range(10))
  151. class_total = list(0. for i in range(10))
  152. with torch.no_grad():
  153.     for data in testloader:
  154.         images, labels = data
  155.         outputs = net(images)
  156.         _, predicted = torch.max(outputs, 1)
  157.         c = (predicted == labels).squeeze()
  158.         for i in range(4):
  159.             label = labels[i]
  160.             class_correct[label] += c[i].item()
  161.             class_total[label] += 1


  162. for i in range(10):
  163.     print('Accuracy of %5s : %2d %%' % (
  164.         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 秒

  1. # -*- coding: utf-8 -*-
  2. __author__ = u'东方耀 微信:dfy_88888'
  3. __date__ = '2020/4/9 下午5:20'
  4. __product__ = 'PyCharm'
  5. __filename__ = 'dfy02'


  6. # 训练一个图像分类器
  7. # 依次按照下列顺序进行:
  8. #
  9. # 1、使用torchvision加载和归一化CIFAR10训练集和测试集
  10. # 2、定义一个卷积神经网络
  11. # 3、定义损失函数
  12. # 4、在训练集上训练网络
  13. # 5、在测试集上测试网络


  14. # 1、读取和归一化 CIFAR10
  15. # 使用torchvision可以非常容易地加载CIFAR10。
  16. import torch
  17. import torchvision
  18. import torchvision.transforms as transforms
  19. # torchvision的输出是[0,1]的PILImage图像,我们把它转换为归一化范围为[-1, 1]的张量。

  20. transform = transforms.Compose(
  21.     [transforms.ToTensor(),
  22.      transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))])

  23. trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
  24.                                         download=True, transform=transform)
  25. trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
  26.                                           shuffle=True, num_workers=2)
  27. # 下载数据 https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
  28. testset = torchvision.datasets.CIFAR10(root='./data', train=False,
  29.                                        download=True, transform=transform)
  30. testloader = torch.utils.data.DataLoader(testset, batch_size=4,
  31.                                          shuffle=False, num_workers=2)

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

  34. import matplotlib.pyplot as plt
  35. import numpy as np

  36. # 展示图像的函数


  37. def imshow(img):
  38.     # [-1, 1] to [0,1]
  39.     img = img / 2 + 0.5     # unnormalize
  40.     npimg = img.numpy()
  41.     # CHW ---> HWC
  42.     plt.imshow(np.transpose(npimg, (1, 2, 0)))


  43. # 获取随机数据
  44. dataiter = iter(trainloader)  # 迭代器
  45. images, labels = dataiter.next()
  46. # [4, 3, 32, 32]
  47. print(images.size())
  48. # [4,]
  49. print('标签数据:', labels.size(), labels.numpy())

  50. # 展示图像
  51. imshow(torchvision.utils.make_grid(images))
  52. # 显示图像标签
  53. print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

  54. # plt.show()

  55. # 2、定义一个卷积神经网络
  56. import torch.nn as nn
  57. import torch.nn.functional as F


  58. class Net(nn.Module):
  59.     def __init__(self):
  60.         super(Net, self).__init__()
  61.         # 二维卷积 5*5*3*6
  62.         self.conv1 = nn.Conv2d(3, 6, 5)
  63.         self.pool = nn.MaxPool2d(2, 2)
  64.         self.conv2 = nn.Conv2d(6, 16, 5)
  65.         self.fc1 = nn.Linear(16 * 5 * 5, 120)
  66.         self.fc2 = nn.Linear(120, 84)
  67.         self.fc3 = nn.Linear(84, 10)

  68.     def forward(self, x):
  69.         # 输入的x的size = [4, 3, 32, 32]
  70.         x = self.pool(F.relu(self.conv1(x)))
  71.         x = self.pool(F.relu(self.conv2(x)))
  72.         x = x.view(-1, 16 * 5 * 5)
  73.         x = F.relu(self.fc1(x))
  74.         x = F.relu(self.fc2(x))
  75.         x = self.fc3(x)
  76.         # x = F.softmax(x, dim=1)
  77.         return x


  78. net = Net()
  79. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
  80. print(device)
  81. net.to(device)
  82. print('net的结构:', net)
  83. params = list(net.parameters())
  84. print(len(params))
  85. print("conv1's .weight size=", params[0].size())
  86. for i in range(len(params)):
  87.     print('layer-%d的权重size=' % i, params[i].size())

  88. # 3、定义损失函数和优化器
  89. # 我们使用交叉熵作为损失函数,使用带动量的随机梯度下降。
  90. import torch.optim as optim

  91. criterion = nn.CrossEntropyLoss()
  92. optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

  93. import time
  94. start_time = time.time()
  95. # 4、训练网路
  96. # 我们只需在数据迭代器上循环,将数据输入给网络,并优化。
  97. for epoch in range(2):  # 多批次循环

  98.     running_loss = 0.0
  99.     print('开始第%d轮的训练!' % epoch)
  100.     for i, data in enumerate(trainloader, 0):
  101.         # 获取输入
  102.         inputs, labels = data
  103.         # torch.Size([4, 3, 32, 32])
  104.         # print('inputs.size=', inputs.size())
  105.         # 记住:inputs 和 targets 也要转换
  106.         inputs, labels = inputs.to(device), labels.to(device)

  107.         # 梯度置0
  108.         optimizer.zero_grad()

  109.         # 正向传播,反向传播,优化
  110.         outputs = net(inputs)
  111.         loss = criterion(outputs, labels)
  112.         # 反向传播 计算梯度
  113.         loss.backward()
  114.         # 优化器更新网络参数
  115.         optimizer.step()

  116.         # 打印状态信息
  117.         # 如果你有只有一个元素的张量,使用.item()来得到Python数据类型的数值
  118.         running_loss += loss.item()
  119.         if i % 2000 == 1999:    # 每2000批次打印一次
  120.             print('[第%d轮, %5d] loss: %.4f' %
  121.                   (epoch, i + 1, running_loss / 2000))
  122.             running_loss = 0.0

  123. # cpu上训练的耗时: 106.1030011177063 秒
  124. # gpu上的耗时:65.4867947101593 秒
  125. print('Finished Training, 共耗时:', time.time() - start_time)

  126. # 5、在测试集上测试网络
  127. # 我们在整个训练集上进行了2轮训练,但是我们需要检查网络是否从数据集中学习到有用的东西。
  128. # 通过预测神经网络输出的类别标签与实际情况标签进行对比来进行检测。
  129. # 如果预测正确,我们把该样本添加到正确预测列表。

  130. # 第一步,显示测试集中的图片并熟悉图片内容
  131. dataiter = iter(testloader)
  132. images, labels = dataiter.next()

  133. # 显示图片
  134. imshow(torchvision.utils.make_grid(images))
  135. print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

  136. # 让我们看看神经网络认为以上图片是什么。
  137. # RuntimeError: Input type (torch.FloatTensor)
  138. # and weight type (torch.cuda.FloatTensor) should be the same
  139. images = images.to(device)
  140. outputs = net(images)
  141. # 4*10
  142. # outputs.data
  143. _, predicted = torch.max(outputs, 1)

  144. print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
  145.                               for j in range(4)))

  146. # 接下来让看看网络在整个测试集上的结果如何。
  147. correct = 0
  148. total = 0
  149. with torch.no_grad():
  150.     for data in testloader:
  151.         images, labels = data
  152.         images, labels = images.to(device), labels.to(device)
  153.         outputs = net(images)
  154.         _, predicted = torch.max(outputs.data, 1)
  155.         total += labels.size(0)
  156.         correct += (predicted == labels).sum().item()

  157. # Accuracy of the network on the 10000 test images: 54 %
  158. print('Accuracy of the network on the 10000 test images: %d %%' % (
  159.     100 * correct / total))

  160. # 结果看起来不错,至少比随机选择要好,随机选择的正确率为10%。 似乎网络学习到了一些东西。
  161. #
  162. # 在识别哪一个类的时候好,哪一个不好呢?
  163. class_correct = list(0. for i in range(10))
  164. class_total = list(0. for i in range(10))
  165. with torch.no_grad():
  166.     for data in testloader:
  167.         images, labels = data
  168.         images, labels = images.to(device), labels.to(device)
  169.         outputs = net(images)
  170.         _, predicted = torch.max(outputs, 1)
  171.         c = (predicted == labels).squeeze()
  172.         for i in range(4):
  173.             label = labels[i]
  174.             class_correct[label] += c[i].item()
  175.             class_total[label] += 1


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



复制代码






cifar10.png (231.78 KB, 下载次数: 122)

cifar10.png
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
沙发
 楼主| 发表于 2020-4-9 19:06:26 | 只看该作者
cifar-10-python.tar.gz的下载(官网非常慢, 我给出百度盘):链接: https://pan.baidu.com/s/1W_F31q3olZO61O-p1F6ACA  密码: jn34
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

1365

主题

1856

帖子

1万

积分

管理员

Rank: 10Rank: 10Rank: 10

积分
14435
QQ
板凳
 楼主| 发表于 2020-4-10 09:56:54 | 只看该作者
设备间转换
一般情况下可以使用.cuda方法将tensor移动到gpu,这步操作需要cuda设备支持
  1. cpu_a=torch.rand(4, 3)
  2. cpu_a.type()
  3. gpu_a=cpu_a.cuda()
  4. gpu_a.type()
  5. 使用.cpu方法将tensor移动到cpu
  6. cpu_b=gpu_a.cpu()
  7. cpu_b.type()
复制代码


如果我们有多GPU的情况,可以使用to方法来确定使用那个设备
让天下人人学会人工智能!人工智能的前景一片大好!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|人工智能工程师的摇篮 ( 湘ICP备2020019608号-1 )

GMT+8, 2024-4-29 15:50 , Processed in 0.216607 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表