当前位置:   article > 正文

NLP笔记(5)——Pytorch实现手写数字识别_pytorch手写数字识别

pytorch手写数字识别

1、概述

自然语言处理:也称为NLP (Natural Language Processing),是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。

图片

2、准备数据集

2.1数据处理方法

2.1.1 tensor转换

把一个取值范围是[0,255]的PIL.Image或者shape为(H,W,C)的numpy.ndarray,转换成形状为[C,H,W]其中(H,W,C)意思为(高,宽,通道数),黑白图片的通道数只有1,其中每个像素点的取值为[0,255],彩色图片的通道数为(R,G,B),每个通道的每个像素点的取值为[0,255],三个通道的颜色相互叠加,形成了各种颜色

  1. from torchvision import transforms
  2. import numpy as np
  3. data = np.random.randint(0, 255, size=12)
  4. img = data.reshape(2,2,3)
  5. print(img.shape)
  6. img_tensor = transforms.ToTensor()(img) # 转换成tensor
  7. print(img_tensor)
  8. print(img_tensor.shape)

注意:transforms.ToTensor对象中有__call__方法,所以可以对其示例能够传入数据获取结果。

2.1.2 规范化处理

给定均值:mean,shape和图片的通道数相同(指的是每个通道的均值),方差:std,和图片的通道数相同(指的是每个通道的方差),将会把Tensor规范化处理。即:

Normalized_image=(image-mean)/std

  1. from torchvision import transforms
  2. import numpy as np
  3. import torchvision
  4. data = np.random.randint(0, 255, size=12)
  5. img = data.reshape(2,2,3)
  6. img = transforms.ToTensor()(img) # 转换成tensor
  7. img = img.float()
  8. print(img)
  9. print("*"*100)
  10. norm_img = transforms.Normalize((10,10,10), (1,1,1))(img) #进行规范化处理
  11. print(norm_img)

2.1.3 tensor组合

  1. transforms.Compose([
  2. torchvision.transforms.ToTensor(), #先转化为Tensor
  3. torchvision.transforms.Normalize(mean,std) #在进行正则化
  4. ])

2.2数据集加载

准备训练集只需将train等于True,测试集改为False。

  1. import torchvision
  2. #准备数据集,其中0.13070.3081为MNIST数据的均值和标准差,这样操作能够对其进行标准化
  3. #因为MNIST只有一个通道(黑白图片),所以元组中只有一个值
  4. dataset = torchvision.datasets.MNIST('/data', train=True, download=True,
  5. transform=torchvision.transforms.Compose([
  6. torchvision.transforms.ToTensor(),
  7. torchvision.transforms.Normalize(
  8. (0.1307,), (0.3081,))
  9. ]))
  10. #准备数据迭代器
  11. train_dataloader = torch.utils.data.DataLoader(dataset,batch_size=64,shuffle=True)

3、构建模型

3.1激活函数

常用的激活函数为Relu激活函数,他的使用非常简单Relu激活函数由import torch.nn.functional as F提供,F.relu(x)即可对x进行处理:

  1. import torch.nn.functional as F
  2. F.relu(b)

3.2数据形状

原始输入数据为的形状:[batch_size,1,28,28]

进行形状修改:[batch_size,28*28],(全连接层是在进行矩阵的乘法操作)

第一个全连接层的输出形状:[batch_size,28],28是个人设定的,激活函数不会修改数据的形状

第二个全连接层的输出形状:[batch_size,10],因为手写数字有10个类别

构建模型的代码如下:

  1. import torch
  2. from torch import nn
  3. import torch.nn.functional as F
  4. class MnistNet(nn.Module):
  5. def __init__(self):
  6. super(MnistNet,self).__init__()
  7. self.fc1 = nn.Linear(28*28*1,28) #定义Linear的输入和输出的形状
  8. self.fc2 = nn.Linear(28,10) #定义Linear的输入和输出的形状
  9. def forward(self,x):
  10. x = x.view(-1,28*28*1) #对数据形状变形,-1表示该位置根据后面的形状自动调整
  11. x = self.fc1(x) #[batch_size,28]
  12. x = F.relu(x) #[batch_size,28]
  13. x = self.fc2(x) #[batch_size,10]

3.3损失函数

softmax和sigmoid的区别在于我们需要去计算样本属于每个类别的概率,需要计算多次,而sigmoid只需要计算一次。softmax的公式如下:

图片

图片

 在pytorch中有两种方法实现交叉熵损失:

  1. # 调用pytorch
  2. criterion = nn.CrossEntropyLoss()
  3. loss = criterion(input,target)
  4. # 对输出值计算softmax和取对数
  5. output = F.log_softmax(x,dim=-1)
  6. loss = F.nll_loss(output,target)

4、模型训练

训练的流程:实例化模型,设置模型为训练模式→实例化优化器类,实例化损失函数→获取,遍历dataloader→梯度置为0→进行向前计算→计算损失→反向传播→更新参数

  1. mnist_net = MnistNet()
  2. optimizer = optim.Adam(mnist_net.parameters(),lr= 0.001)
  3. def train(epoch):
  4. mode = True
  5. mnist_net.train(mode=mode) #模型设置为训练模型
  6. train_dataloader = get_dataloader(train=mode) #获取训练数据集
  7. for idx,(data,target) in enumerate(train_dataloader):
  8. optimizer.zero_grad() #梯度置为0
  9. output = mnist_net(data) #进行向前计算
  10. loss = F.nll_loss(output,target) #带权损失
  11. loss.backward() #进行反向传播,计算梯度
  12. optimizer.step() #参数更新
  13. if idx % 10 == 0:
  14. print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
  15. epoch, idx * len(data), len(train_dataloader.dataset),
  16. 100. * idx / len(train_dataloader), loss.item()))

5、模型保存和加载

  1. # 模型保存
  2. torch.save(mnist_net.state_dict(),"model/mnist_net.pt") #保存模型参数
  3. torch.save(optimizer.state_dict(), 'results/mnist_optimizer.pt') #保存优化器参数
  4. # 模型加载
  5. mnist_net.load_state_dict(torch.load("model/mnist_net.pt"))
  6. optimizer.load_state_dict(torch.load("results/mnist_optimizer.pt"))

6、模型的评估

评估的过程和训练的过程相似,但是不需要计算梯度。需要收集损失和准确率,用来计算平均损失和平均准确率,损失的计算和训练时候损失的计算方法相同。

准确率的计算:

   - 模型的输出为[batch_size,10]的形状

   - 其中最大值的位置就是其预测的目标值(预测值进行过sotfmax后为概率,sotfmax中分母都是相同的,分子越大,概率越大)

   - 最大值的位置获取的方法可以使用`torch.max`,返回最大值和最大值的位置

   - 返回最大值的位置后,和真实值(`[batch_size]`)进行对比,相同表示预测成功

  1. def test():
  2. test_loss = 0
  3. correct = 0
  4. mnist_net.eval() #设置模型为评估模式
  5. test_dataloader = get_dataloader(train=False) #获取评估数据集
  6. with torch.no_grad(): #不计算其梯度
  7. for data, target in test_dataloader:
  8. output = mnist_net(data)
  9. test_loss += F.nll_loss(output, target, reduction='sum').item()
  10. pred = output.data.max(1, keepdim=True)[1] #获取最大值的位置,[batch_size,1]
  11. correct += pred.eq(target.data.view_as(pred)).sum() #预测准备样本数累加
  12. test_loss /= len(test_dataloader.dataset) #计算平均损失
  13. print('\nTest set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.2f}%)\n'.format(
  14. test_loss, correct, len(test_dataloader.dataset),
  15. 100. * correct / len(test_dataloader.dataset)))

7、完整代码

  1. from torch import optim
  2. from tqdm import tqdm
  3. import numpy as np
  4. import torch
  5. from torch.utils.data import DataLoader
  6. from torchvision.datasets import MNIST
  7. import torchvision
  8. import torch.nn as nn
  9. import torch.nn.functional as F
  10. import os
  11. train_batch_size = 128
  12. test_batch_size = 1000
  13. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
  14. def mnist_dataset(train): #准备minist的dataset
  15. func = torchvision.transforms.Compose([
  16. torchvision.transforms.ToTensor(),
  17. torchvision.transforms.Normalize(
  18. mean=(0.1307,),
  19. std=(0.3081,)
  20. )]
  21. )
  22. # 1. 准备Mnist数据集
  23. return MNIST(root="./data", train=train, download=True, transform=func)
  24. def get_dataloader(train=True):
  25. mnist = mnist_dataset(train)
  26. return DataLoader(mnist,batch_size=train_batch_size,shuffle=True)
  27. class MnistModel(nn.Module):
  28. def __init__(self):
  29. super(MnistModel,self).__init__()
  30. self.fc1 = nn.Linear(1*28*28,100)
  31. self.fc2 = nn.Linear(100,10)
  32. def forward(self, image):
  33. image_viwed = image.view(-1,1*28*28) #[batch_size,1*28*28]
  34. fc1_out = self.fc1(image_viwed) #[batch_size,100]
  35. fc1_out_relu = F.relu(fc1_out) #[batch_siz3,100]
  36. out = self.fc2(fc1_out_relu) #[batch_size,10]
  37. return F.log_softmax(out,dim=-1)
  38. #1. 实例化模型,优化器,损失函数
  39. model = MnistModel().to(device)
  40. optimizer = optim.Adam(model.parameters(),lr=1e-3)
  41. #2. 进行循环,进行训练
  42. def train(epoch):
  43. train_dataloader = get_dataloader(train=True)
  44. bar = tqdm(enumerate(train_dataloader),total=len(train_dataloader))
  45. total_loss = []
  46. for idx,(input,target) in bar:
  47. input = input.to(device)
  48. target = target.to(device)
  49. #梯度置为0
  50. optimizer.zero_grad()
  51. #计算得到预测值
  52. output = model(input)
  53. #得到损失
  54. loss = F.nll_loss(output,target)
  55. #反向传播,计算损失
  56. loss.backward()
  57. total_loss.append(loss.item())
  58. #参数的更新
  59. optimizer.step()
  60. #打印数据
  61. if idx%10 ==0 :
  62. bar.set_description("epcoh:{} idx:{},loss:{:.6f}".format(epoch,idx,np.mean(total_loss)))
  63. torch.save(model.state_dict(),"model.pkl")
  64. torch.save(optimizer.state_dict(),"optimizer.pkl")
  65. def eval():
  66. # 1. 实例化模型,优化器,损失函数
  67. model = MnistModel().to(device)
  68. if os.path.exists("model.pkl"):
  69. model.load_state_dict(torch.load("model.pkl"))
  70. test_dataloader = get_dataloader(train=False)
  71. total_loss = []
  72. total_acc = []
  73. with torch.no_grad():
  74. for input,target in test_dataloader: #2. 进行循环,进行训练
  75. input = input.to(device)
  76. target = target.to(device)
  77. #计算得到预测值
  78. output = model(input)
  79. #得到损失
  80. loss = F.nll_loss(output,target)
  81. #反向传播,计算损失
  82. total_loss.append(loss.item())
  83. #计算准确率
  84. ###计算预测值
  85. pred = output.max(dim=-1)[-1]
  86. total_acc.append(pred.eq(target).float().mean().item())
  87. print("test loss:{},test acc:{}".format(np.mean(total_loss),np.mean(total_acc)))
  88. if __name__ == '__main__':
  89. for i in range(10):
  90. train(i)
  91. eval()

图片

最后:

如果你想要进一步了解更多的相关知识,可以关注下面公众号联系~会不定期发布相关设计内容包括但不限于如下内容:信号处理、通信仿真、算法设计、matlab appdesigner,gui设计、simulink仿真......希望能帮到你!

5a8015ddde1e41418a38e958eb12ecbd.png

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号