当前位置:   article > 正文

Pytorch深度学习——多分类问题、MNIST训练实例(B站刘二大人P9学习笔记)_minist数据集深度学习pytorch

minist数据集深度学习pytorch

目录

1 Softmax层介绍

2 选择Loss函数

2.1 NLLLoss损失函数

2.2 CrossEntropyLoss损失函数

3 MNIST训练实例代码详解

3.1 准备数据集

3.2 建立模型

3.3 构建损失函数和优化器

3.4 训练+测试

3.5 完整代码+运行结果

4 遇到问题


        本节课以深度学习经典数据集MNIST数据集为例展开,如图所示是MNIST数据集的一张样例图,每个方框中是手写的数字。而我们需要做的事情就是:根据数据集中的数据,利用深度学习,让机器能够自己识别每个方框中的数字。

        数字一共有0~9一共10种类别,利用深度学习来识别十种数字的类别,这就是多分类问题

         之前在糖尿病数据集的学习中,我们遇到的是二分类问题,也就是病人一共只有患病(y=1)和不患病(y=0)两种分类,知道y=1的概率,那y=0的概率就等于1-P(y=1),比较两个概率的大小,很容易就可以区分该病人属于哪一个分类。

         而多分类问题不同,以MNIST数据集为例,需要计算出每个方框属于不同数字的10个概率,这10个概率需要满足:

  1.         P\left ( y=i \right )> 0
  2.        \sum_{i=0}^{9}P(y=i)=1

        因此多分类问题我们通常选用Softmax函数作为神经网络的最后一层。


 1 Softmax层介绍

         Softmax函数公式如下:其中 Z_{i} 表示的是线性层输出的数值;对每层的线性层求指数,之后再计算每层指数值占总层数指数值之和的比例,就是计算出的该层次的概率。

    注意: 

  •          首先先对线性层输出的数值求指数,是为了保证计算出的数值一定是一个大于0的数,保证多分类问题中的条件1:P\left ( y=i \right )> 0
  • 计算每个层次占总层次之和的比例,是为了保证多分类问题中的条件2:\sum_{i=0}^{9}P(y=i)=1

 一个简单的例子如下图所示:

2 选择Loss函数

2.1 NLLLoss损失函数

         NLLLoss损失函数如下图所示:(\widehat{y} 最大的对应的 y 值为1,其余都为0.)

          对应的损失函数代码如下所示:

  1. import numpy as np
  2. y = np.array([1, 0, 0])
  3. z = np.array([0.2, 0.1, -0.1])
  4. y_pred = np.exp(z) / np.exp(z).sum()
  5. loss = (- y * np.log(y_pred)).sum()
  6. print(loss)

2.2 CrossEntropyLoss损失函数

       CrossEntropyLoss损失函数是将Softmax层和NLLLoss损失函数整合在一。CrossEntropyLoss损失函数如下图所示:

        注意:使用CrossEntropyLoss损失函数时,神经网络的最后一层不需要做激活,(也就是不用经过Softmax层的计算),直接输入到CrossEntropyLoss损失函数中就可以,因为CrossEntropyLoss损失函数包含的Sofrmax层。

        对应的损失函数代码如下所示:

  1. import torch
  2. y = torch.LongTensor([0])
  3. z = torch.Tensor([[0.2, 0.1, -0.1]])
  4. criterion = torch.nn.CrossEntropyLoss()
  5. loss = criterion(z, y)
  6. print(loss)

3 MNIST训练实例代码详解

        我们之前学习的案例中,输入x都是一个向量;在MNIST数据集中,我们需要输入的是一个图像,怎样,图像怎么才能输入到模型中进行训练呢?一种方法是我们可以把图像映射成一个矩向量,再输入到模型中进行训练。

        怎样将一个图像映射成一个向量?

        如图所示是MNIST数据集中一个方格的图像,它是由28x28=784个像素组成,其中越深的地方数值越接近0,越亮的地方数值越接近1。

         因此可以将此图像按照对应的像素和数值映射成一个28x28的一个矩阵,如下图所示:


3.1 准备数据集

具体代码如下:

  1. # 准备数据集
  2. batch_size = 64
  3. transform = transforms.Compose([
  4. transforms.ToTensor(),
  5. #均值、标准差
  6. transforms.Normalize((0.1307, ), (0.3081, ))
  7. ])
  8. train_dataset = datasets.MNIST(root='../dataset/mnist/',
  9. train=True,
  10. download=True,
  11. transform=transform)
  12. train_loader = DataLoader(train_dataset,
  13. shuffle=True,
  14. batch_size=batch_size)
  15. test_dataset = datasets.MNIST(root='../dataset/mnist',
  16. train=False,
  17. download=True,
  18. transform=transform)
  19. test_loader = DataLoader(test_dataset,
  20. shuffle=False,
  21. batch_size=batch_size)

 注:

  1. 图像张量:灰度图(黑白图像)就是一个单通道的图像,彩色图像是多通道的图像(分别是R,G,B三个通道),一个通道具有高度——H,宽度——W,通道由——C表示。
  2. transform作用:再pytorch中读取图像时使用的是python的PIL,而由PIL读取的图像一般是由W x H x C组成,而在pytorch中为了进行更高效的图像处理,需要图像由C x W x H这样的顺序组成,因此transform的作用就是将PIL读取的图像顺序转换成C x W x H;像素值从0~255转换成0~1。


3.2 建立模型

        全连接网络中,要求输入的是一个矩阵,因此需要将1x28x28的这个三阶的张量变成一个一阶的向量,因此将图像的每一行的向量横着拼起来变成一串,这样就变成了一个维度为1x784的向量,一共输入N个手写数图,因此,输入矩阵维度为(N,784)。这样就可以设计我们的模型,如下图所示:

 具体代码:

  1. # 设计模型
  2. class Net(torch.nn.Module):
  3. def __init__(self):
  4. super(Net, self).__init__()
  5. self.l1 = torch.nn.Linear(784, 512)
  6. self.l2 = torch.nn.Linear(512, 256)
  7. self.l3 = torch.nn.Linear(256, 128)
  8. self.l4 = torch.nn.Linear(128, 64)
  9. self.l5 = torch.nn.Linear(64, 10)
  10. def forward(self, x):
  11. x = x.view(-1, 784)
  12. x = F.relu(self.l1(x))
  13. x = F.relu(self.l2(x))
  14. x = F.relu(self.l3(x))
  15. x = F.relu(self.l4(x))
  16. return self.l5(x)
  17. model = Net()

3.3 构建损失函数和优化器

  1.   这里我们选择CrossEntropyLoss损失函数;
  2.   因为训练数据集有些大,所以优化器可以加上冲量参数。

  具体代码:

  1. # 构建损失函数和优化器
  2. criterion = torch.nn.CrossEntropyLoss()
  3. optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

3.4 训练+测试

  1. 为了方便,这里我们将一轮训练循环封装成函数;
  2. test函数不需要反向传播,只用计算正向的就可以;
  3. torch.max的返回值有两个,第一个是每一行的最大值是多少,第二个是每一行最大值的下标(索引)是多少;
  4.  torch.no_grad() :不需要计算梯度;
  5. Python 各种下划线都是啥意思_、_xx、xx_、__xx、__xx__、_classname_ - 知乎

具体代码:

  1. # 定义训练函数
  2. def train(epoch):
  3. running_loss = 0.0
  4. for batch_idx, data in enumerate(train_loader, 0):
  5. inputs, target = data
  6. optimizer.zero_grad()
  7. # 前馈+反馈+更新
  8. outputs = model(inputs)
  9. loss = criterion(outputs, target)
  10. loss.backward()
  11. optimizer.step()
  12. running_loss += loss.item()
  13. # 每300次迭代输出一次
  14. if batch_idx % 300 == 299:
  15. print('[%d,%5d] loss:%.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
  16. running_loss = 0.0
  17. # 定义测试函数
  18. def test():
  19. correct = 0
  20. total = 0
  21. with torch.no_grad():
  22. for data in test_loader:
  23. images, labels = data
  24. outputs = model(images)
  25. # 沿着第一维度找最大值的下标
  26. _, predicted = torch.max(outputs.data, dim=1)
  27. total += labels.size(0)
  28. correct += (predicted == labels).sum().item()
  29. print('Accuracy on test set:%d %%' % (100 * correct / total))
  30. # 实例化训练和测试
  31. if __name__ == '__main__':
  32. # 训练10轮
  33. for epoch in range(10):
  34. train(epoch)
  35. test()

3.5 完整代码+运行结果

完整代码:

  1. import torch
  2. from torchvision import transforms
  3. from torchvision import datasets
  4. from torch.utils.data import DataLoader
  5. import torch.nn.functional as F
  6. import torch.optim as optim
  7. # 准备数据集
  8. batch_size = 64
  9. transform = transforms.Compose([
  10. transforms.ToTensor(),
  11. transforms.Normalize((0.1307, ), (0.3081, ))
  12. ])
  13. train_dataset = datasets.MNIST(root='../dataset/mnist/',
  14. train=True,
  15. download=True,
  16. transform=transform)
  17. train_loader = DataLoader(train_dataset,
  18. shuffle=True,
  19. batch_size=batch_size)
  20. test_dataset = datasets.MNIST(root='../dataset/mnist',
  21. train=False,
  22. download=True,
  23. transform=transform)
  24. test_loader = DataLoader(test_dataset,
  25. shuffle=False,
  26. batch_size=batch_size)
  27. # 设计模型
  28. class Net(torch.nn.Module):
  29. def __init__(self):
  30. super(Net, self).__init__()
  31. self.l1 = torch.nn.Linear(784, 512)
  32. self.l2 = torch.nn.Linear(512, 256)
  33. self.l3 = torch.nn.Linear(256, 128)
  34. self.l4 = torch.nn.Linear(128, 64)
  35. self.l5 = torch.nn.Linear(64, 10)
  36. def forward(self, x):
  37. x = x.view(-1, 784)
  38. x = F.relu(self.l1(x))
  39. x = F.relu(self.l2(x))
  40. x = F.relu(self.l3(x))
  41. x = F.relu(self.l4(x))
  42. return self.l5(x)
  43. model = Net()
  44. # 构建损失函数和优化器
  45. criterion = torch.nn.CrossEntropyLoss()
  46. optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
  47. # 定义训练函数
  48. def train(epoch):
  49. running_loss = 0.0
  50. for batch_idx, data in enumerate(train_loader, 0):
  51. inputs, target = data
  52. optimizer.zero_grad()
  53. # 前馈+反馈+更新
  54. outputs = model(inputs)
  55. loss = criterion(outputs, target)
  56. loss.backward()
  57. optimizer.step()
  58. running_loss += loss.item()
  59. if batch_idx % 300 == 299:
  60. print('[%d,%5d] loss:%.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
  61. running_loss = 0.0
  62. # 定义测试函数
  63. def test():
  64. correct = 0
  65. total = 0
  66. with torch.no_grad():
  67. for data in test_loader:
  68. images, labels = data
  69. outputs = model(images)
  70. _, predicted = torch.max(outputs.data, dim=1)
  71. total += labels.size(0)
  72. correct += (predicted == labels).sum().item()
  73. print('Accuracy on test set:%d %%' % (100 * correct / total))
  74. # 实例化训练和测试
  75. if __name__ == '__main__':
  76. for epoch in range(10):
  77. train(epoch)
  78. test()

运行截图如下:

4 遇到问题

运行时遇到警告:The given NumPy array is not writeable,and PyTorch does not support non-writeable tensor,如图:

 按照路径找到mnist.py文件:

 点开修改:删除copy+False,就没有报错,程序可以继续运行了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/928257
推荐阅读
相关标签
  

闽ICP备14008679号