赞
踩
MNIST手写数字识别主要从以下这个部分去讲解:
正文:
# (1)加载必要的库 import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, transforms # (2)定义超参数 BATCH_SIZE = 16 # 每批处理的数据 DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 用GPU还是CPU训练 EPOCHS = 10 # 训练数据集的轮次 # (3)构建pipeline,对图像做处理 pipeline = transforms.Compose([ transforms.ToTensor(), # /将图片转化成tensor transforms.Normalize((0.1307,), (0.3081,)) # 正则化:降低模型的复杂化 ]) # (4)下载、加载数据 from torch.utils.data import DataLoader # 下载数据集 train_set = datasets.MNIST('data', train=True, download=True, transform=pipeline) test_set = datasets.MNIST('data', train=False, download=True, transform=pipeline) # 加载数据 train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True) test_loader = DataLoader(test_set, batch_size=BATCH_SIZE, shuffle=True) # (5) 构建网络模型 class Digit(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(1, 10, 5) # 卷积层 1:灰度图片的通道, 10:输出通道, 5: 卷积核 self.conv2 = nn.Conv2d(10, 20, 3) # 卷积层 10:输入通道,20 :输出通道,3:卷积核大小 self.fc1 = nn.Linear(20 * 10 * 10, 500) # 全连接层 20*10*10:输入通道,500:输出通道 self.fc2 = nn.Linear(500, 10) # 全连接层 500:输入通道,10:输出通道 def forward(self, x): # 前向传播 input_size = x.size(0) # batch_size BATCH_SIZE = 16 # 每批处理的数据 x = self.conv1(x) # 第一个卷积层 输入:batch*1*28*28 , 输出:batch*10*24*24(28-5+1 = 24) x = F.relu(x) # 激活函数 保持shape不变,输出:batch*10*24*24 x = F.max_pool2d(x, 2, 2) # 池化层 最大池化 输入:batch*10*24*24 输出:batch*10*12*12 x = self.conv2(x) # 第二个卷积层 输入:batch*10*12*12 输出:batch*20*10*10(12-3+1=10) x = F.relu(x) # 激活函数 x = x.view(input_size, -1) # 拉平,把二维图片拉成一维度的,-1:自动计算维度:20*20*10 = 2000 x = self.fc1(x) # 全连接层 输入:batch*2000 输出:batch*500 x = F.relu(x) # 激活层,保持shpae不变 x = self.fc2(x) # 全连接层2 输入:batch*500 输出:batch*10 output = F.log_softmax(x, dim=1) # 计算分类就,每个数字的概率值 return output # 把概率值给返回回去 # (6) 定义优化器 model = Digit().to(DEVICE) # 创建一个模型,并把模型放在设备上面去 optimizer = optim.Adam(model.parameters()) # 定义一个优化器,更新模型的参数。优化器有很多种,这只是其中的一个 # (7)定义训练方法 def train_model(model, device, train_loader, optimizer, epoch): # model:模型, device:运行模型的设备(cpu还是gpu), optimizer:优化器,epoch:训练集训练的轮数 EPOCHS = 10 # 训练数据集的轮次 # 模型训练 model.train() for batch_index, (data, target) in enumerate(train_loader): # 部署到DEVICE上去 data, target = data.to(device), target.to(device) # 梯度初始化为0 optimizer.zero_grad() # 训练后的结果 output = model(data) # 计算损失 loss = F.cross_entropy(output, target) # 此处使用的是交叉熵损失,交叉熵损失适用于多分类的情况 # 找到概率值最大的下标 pred = output.max(1, keepdim=True) # pred = output.argmax(dim=1) 1:表示维度,这里是指横轴 # 反向传播 loss.backward() # 参数优化 上一步的反向传播哦,不进行参数更新吗? optimizer.step() if batch_index % 3000 == 0: # 每处理3000张图片打印一次损失函数 print('Train Epoch : {} \t Loss : {:.6}'.format(epoch, loss.item())) # 输出的数字是6位 # (8)定义测试方法 def test_model(model, device, test_loader): # 模型验证 验证什么? model.eval() # 正确率 correct = 0.0 # 测试损失 测试损失?这个是做什么用的? test_loss = 0.0 with torch.no_grad(): # 不会计算梯度,也不会进行反向传播 for data, target in test_loader: # 部署到device上 data, target = data.to(device), target.to(device) # 测试数据 output = model(data) # 计算测试损失 test_loss = F.cross_entropy(output, target).item() # 找到概率值最大的下标 pred = output.max(1, keepdim=True)[1] # 值,索引 # 累计正确的值 correct += pred.eq(target.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) print('Test -- Average loss : {:.4f}, Accuracy : {:.3f}\n'.format(test_loss, 100 * correct / len(test_loader.dataset))) # (9)调用方法(7)(8) for epoch in range(1, EPOCHS + 1): train_model(model, DEVICE, train_loader, optimizer, epoch) test_model(model, DEVICE, test_loader)
1、加载必要的库
2、定义超参数
3、构建pipeline,对图像做处理
4、下载、加载数据
5、构建网络模型
6、定义优化器
7、定义训练方法
8、定义测试方法
9、调用方法(7)(8)
1、加载必要的库
(1)import torch.optim as optim
#导入的是优化器
(2)from torchvision import datasets, transforms
#这个是为了操作MNSIT数据集
# (1)加载必要的库
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
2、定义超参数
(1)参数:模型f(x,y)中的y称为模型的参数,可以通过优化算法进行学习。深度学习中,这些参数可以通过训练集进行自动修改的数
(2)超参数:用来定义模型结构或优化策略
(3)BATCH_SIZE = 16 # 每批处理的数据
# 每次处理图片的数量
(4)EPOCHS = 10 # 训练数据集的轮次
# 对于训练集进行训练的轮次,有些训练集太小,训练一次并不能取得很好的效果,所以需要多次训练。
# (2)定义超参数
BATCH_SIZE = 16 # 每批处理的数据
DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 用GPU还是CPU训练
EPOCHS = 10 # 训练数据集的轮次
3、构建pipeline,对图像做处理 (1)ToTensor() #
将图片从它保存的格式,转化成python能够处理的格式。总的来说,就是MNIST数据集在实际生活中,会被各种行业的人所使用,而大家对于MNIST的使用都不是一样的,但是官网又不可能为所有不同的使用方式,单独保存一种图片的保存格式,所以官方会把图片保存为一种格式,但保存的格式可以在使用时进行修改,并提供了各种修改图片格式的函数,比如下面的ToTensor()便是对图片处理的一种函数。而在数据集中图片的存储格式可能是下面这两中格式。输入模式为(L、LA、P、I、F、RGB、YCbCr、RGBA、CMYK、1)的PIL Image 或 numpy.ndarray (形状为H x W x C)数据范围是[0, 255]
对于上面这两种图片格式,并不是我们想要的,而且这两种图片的格式,在我们的代码中可能是不能够处理的,所以需要对数据集中的图片数据进行ToTensor()处理。
https://www.bilibili.com/read/cv10342533/(该链接对image中的几种输入模式做了详细的解释)
(2)transforms.Normalize((0.1307,), (0.3081,)) # 正则化:降低模型的复杂化 #
Normalize :模型出现过拟合现象时,降低模型的复杂度 疑问:
(1)这儿是对图片进行处理,过拟合是在进行了测试集测试过后与训练集做对比,才能够知道是否有过拟合现象,但这段代码中,好像测试集处理完了,就没进行下一步工作了,那么在这儿的正则化处理有用嘛,还是说这儿的正则化处理是在模型训练的时候,就一直存在损失函数中,在训练集中就一直的防止模型过拟合。
(2)正则化是防止模型吧,因为正则化的时间是在训练过程中,而你如果想要知道模型是否过拟合,必须要经过测试集测试完之后才能够知道。
# (3)构建pipeline,对图片做处理
pipeline = transforms.Compose([
transforms.ToTensor(), # /将图片转化成tensor
transforms.Normalize((0.1307,), (0.3081,)) # 正则化:降低模型的复杂化
])
4、下载、加载数据
(1)from torch.utils.data import DataLoader
# 里面有处理数据的一些方法和函数
(2)from torchvision import datasets, transforms
# torchvision 把一些经典的数据集都保存在datasets中,方便用户自行下载。
(3)train_set = datasets.MNIST('data', train=True, download=True, transform=pipeline)
# datasets后面直接写你需要下载的数据集的名字。
# 'data',:下载下来的数据集,放在此时代码文件所在根目录下的data文件中,如果没有data文件夹,系统会自动的创建一个data文件夹。
# train=True :由于我们所要下载的是一个训练集,所以这儿的train参数我们赋值为True,如果我们下载的是一个测试集,那么这里应该赋值为Flase。
# download=True:‘这个参数是询问你是否下载,确实没有搞懂什么要这样去询问用户,我肯定需要下载闪,但也有其他可能,比如它可能直接在网络上传输数据集的图片信息,不把训练集下载带本地。(这只是本人的一些猜想,这里先记着这么用吧,以后遇到了新的使用方式再去记吧,毕竟现在是一个信息爆炸的时代,不要尝试去搞懂这个的所用用法,很多用法可能你一辈子都用不到。)
#transform=pipeline:这儿使用到了我们前面写的pipeline,这里就更好理解了,在datasets中存储的图片你的格式与我们所需要的格式是不用的,当我们需要使用存储的数据集时,我们需要把图片的格式转化成我们需要的格式,比如:在数据集中图片的存储是彩色图片,但是我们代码处理的图片得是灰色的,这时,我们就需要把图片处理成灰色的,把我们所需图片的要求通过tranform参数,传递给内部函数。
(4)train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True)
# batch_size=BATCH_SIZE:为啥下载完数据,还需要对数据进行加载呢?我的理解下载的数据可能是放在一个容器里面,但是我们最后要把图片送到模型中去训练,但是一次送多少张图片进去呢?这儿就设定了一次送16中图片进去训练。
# shuffle=True:这个是询问你是否把图片打乱,将图片打乱训练可以提高模型的泛化能力,防止过拟合,也可以提高模型准确率。
# (4)下载、加载数据
from torch.utils.data import DataLoader
# 下载数据集
train_set = datasets.MNIST('data', train=True, download=True, transform=pipeline)
test_set = datasets.MNIST('data', train=False, download=True, transform=pipeline)
# 加载数据
train_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True)
test_loader = DataLoader(test_set, batch_size=BATCH_SIZE, shuffle=True)
5、构建网络模型
# (5) 构建网络模型 class Digit(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(1, 10, 5) # 卷积层 1:灰度图片的通道, 10:输出通道, 5: 卷积核 self.conv2 = nn.Conv2d(10, 20, 3) # 卷积层 10:输入通道,20 :输出通道,3:卷积核大小 self.fc1 = nn.Linear(20 * 10 * 10, 500) # 全连接层 20*10*10:输入通道,500:输出通道 self.fc2 = nn.Linear(500, 10) # 全连接层 500:输入通道,10:输出通道 def forward(self, x): # 前向传播 input_size = x.size(0) # batch_size BATCH_SIZE = 16 # 每批处理的数据 x = self.conv1(x) # 第一个卷积层 输入:batch*1*28*28 , 输出:batch*10*24*24(28-5+1 = 24) x = F.relu(x) # 激活函数 保持shape不变,输出:batch*10*24*24 x = F.max_pool2d(x, 2, 2) # 池化层 最大池化 输入:batch*10*24*24 输出:batch*10*12*12 x = self.conv2(x) # 第二个卷积层 输入:batch*10*12*12 输出:batch*20*10*10(12-3+1=10) x = F.relu(x) # 激活函数 x = x.view(input_size, -1) # 拉平,把二维图片拉成一维度的,-1:自动计算维度:20*20*10 = 2000 x = self.fc1(x) # 全连接层 输入:batch*2000 输出:batch*500 x = F.relu(x) # 激活层,保持shpae不变 x = self.fc2(x) # 全连接层2 输入:batch*500 输出:batch*10 output = F.log_softmax(x, dim=1) # 计算分类就,每个数字的概率值 return output # 把概率值给返回回去
6、定义优化器
# (6) 定义优化器
model = Digit().to(DEVICE) # 创建一个模型,并把模型放在设备上面去
optimizer = optim.Adam(model.parameters()) # 定义一个优化器,更新模型的参数。优化器有很多种,这只是其中的一个,有点反向传播改变参数的值的意思
7、定义训练方法
# (7)定义训练方法 def train_model(model, device, train_loader, optimizer, epoch): # model:模型, device:运行模型的设备(cpu还是gpu), optimizer:优化器,epoch:训练集训练的轮数 EPOCHS = 10 # 训练数据集的轮次 # 模型训练 model.train() # 这个代码没有写train方法,那么这个方法应该是继承自父类的 for batch_index, (data, target) in enumerate(train_loader): # 部署到DEVICE上去 data, target = data.to(device), target.to(device) # 梯度初始化为0 optimizer.zero_grad() # 训练后的结果 output = model(data) # 计算损失 loss = F.cross_entropy(output, target) # 此处使用的是交叉熵损失,交叉熵损失适用于多分类的情况 # 找到概率值最大的下标 pred = output.max(1, keepdim=True) # pred = output.argmax(dim=1) 1:表示维度,这里是指横轴 # 反向传播 loss.backward() # 参数优化 上一步的反向传播哦,不进行参数更新吗? optimizer.step() if batch_index % 3000 == 0: # 每处理3000张图片打印一次损失函数 print('Train Epoch : {} \t Loss : {:.6}'.format(epoch, loss.item())) # 输出的数字是6位
8、定义`在这里插入代码片`测试方法
# (8)定义测试方法 def test_model(model, device, test_loader): # 模型验证 验证什么? model.eval() # 正确率 correct = 0.0 # 测试损失 测试损失?这个是做什么用的? test_loss = 0.0 with torch.no_grad(): # 不会计算梯度,也不会进行反向传播 for data, target in test_loader: # 部署到device上 data, target = data.to(device), target.to(device) # 测试数据 output = model(data) # 计算测试损失 test_loss = F.cross_entropy(output, target).item() # 找到概率值最大的下标 pred = output.max(1, keepdim=True)[1] # 值,索引 # 累计正确的值 correct += pred.eq(target.view_as(pred)).sum().item() test_loss /= len(test_loader.dataset) print('Test -- Average loss : {:.4f}, Accuracy : {:.3f}\n'.format(test_loss, 100 * correct / len(test_loader.dataset)))
9、调用方法(7)(8)
# (9)调用方法(7)(8)
for epoch in range(1, EPOCHS + 1):
train_model(model, DEVICE, train_loader, optimizer, epoch)
test_model(model, DEVICE, test_loader)
、
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。