3.1手写数字图片数据集
MNIST数据集
:0~9共10个数字,每种数字有7000张图片.共70000张,其中60000张作为训练集,10000张图片作为测试集.每张图片大小为28*28.灰度图片
import torch
from torch import nn
from torch.nn import functional # 导入网络层函数子库
from torch import optim # 导入优化器
import torchvision # 导入视觉库
from matplotlib import pyplot as plt
from utils import plot_image, plot_curve, one_hot
import torch.utils.data
import matplotlib as mpl
mpl.use('TkAgg')
def plot_image(img, label, name):
fig = plt.figure()
for i in range(6):
plt.subplot(2, 3, i + 1)
plt.tight_layout()
plt.imshow(img[i][0]*0.3081+0.1307, cmap='gray', interpolation='none')
plt.title("{}: {}".format(name, label[i].item()))
plt.xticks([])
plt.yticks([])
plt.show()
batch_size = 512 # 批大小
# 训练数据集
train_data = torchvision.datasets.MNIST('mnist-data', train=True, download=True,
transform=torchvision.transforms.Compose(
# 图片的预处理步骤: 1. 转化为张量 2.标准化
[torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize((0.5,), (0.5,))
]))
# 测试数据集
test_data = torchvision.datasets.MNIST('mnist-data', train=False, download=True,
transform=torchvision.transforms.Compose(
[torchvision.transforms.ToTensor(),
# torchvision.transforms.Normalize((0.5,), (0.5,))
]))
# 创建Dataloader对象,为方便批量形式训练,随机打乱顺序
train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, shuffle=True)
# 加载一个批数据
x, y = next(iter(train_loader)) # torch.Size([512, 1, 28, 28]) torch.Size([512]) tensor(-1.) tensor(1.)
print(x.shape, y.shape, x.min(), x.max())
plot_image(x, y, 'Image')
坑1:长按Ctrl无法进入DataLoader类中:
添加:import torch.utils.data
坑2:matplotlib在报错:vars()参数必须有__dict__属性
import matplotlib as mpl
mpl.use('TkAgg')
3.2模型构建
- 数字之间存在天然的大小比较关系, 数字编码并不能适合分类网络的输出
- .一般采用独热编码(One-hot),但是其非常稀疏(Sparse),相对于数字编码来说占用较多的存储空间,因此一般在存储时还是采用数字编码方式,仅在计算时转化为One-hot编码.
torch.scatter()
#A.scatter_(dim, index, B) # 基本用法, tensor A 被就地scatter到 tensor B
https://www.cnblogs.com/simpleminds/p/16291635.html
## 在torch里面,view函数相当于numpy的reshape
def one_hot(label,depth=0): # depth表示类别数目
out = torch.zeros(label.size(0),depth) # 4*10列
idx = torch.LongTensor(label).view(-1,1) # [0;1;2;3]
out.scatter_(dim=1,index=idx,value=1)
return out
y = torch.tensor([0,1,2,3])
y = one_hot(y,depth=10)
print(y)
3.3误差计算
- 分类问题一般使用
交叉熵
- 本次使用MSE
3.4真的解决了吗?
3.6表达能力
3.7优化方法
这时就是深度学习框架发明的意义所在,借助于自动求导(Autograd)技术,深度学习框
架在计算神经网络每层的输出以及损失函数的过程中,会内部构建神经网络的计算图模
型,并自动完成误差对任意参数𝜃的偏导数𝜕ℒ
𝜕𝜃的计算,用户只需要搭建出网络结构,送入数
据,梯度将自动完成计算和更新,使用起来非常便捷高效,甚至连梯度下降算法也不需要
用户手动编写,交给 PyTorch 提供的优化器 optim 即可
3.8手写数字图片识别体验
# 利用Sequential容器封装3个网络层,前网络的输出默认作为下一层的输入
model = nn.Sequential(
#1. 创建第一层,输入784,输出256
nn.Linear(28*28,256),
nn.ReLU(), # 激活函数
#2.创建第二层,输入256,输出128
nn.Linear(256,128),
nn.ReLU(), # 激活函数
# 3.创建第三层,输入128,输出10
nn.Linear(128,10)
)
# 创建优化器,并传递需要优化的参数列表
# 设置学习率
optimizer = optim.SGD(model.parameters(),lr=0.01, momentum=0.9)
train_loss = []
for epoch in range(5): # 训练5轮 所有训练数据迭代一遍叫做一个Epoch
for batch_idx,(x,y) in enumerate(train_loader): # 按批迭代数据
# x = [b,1,28,28],y:[512]
# 打平操作
x = x.view(x.size(0),28*28)
# 送入网络模型 => [b,10]
out = model(x)
y_onehot = one_hot(y)
#计算loss
loss = F.mse_loss(out,y_onehot)
# 在计算参数的梯度之前,通常需要清零梯度信息
optimizer.zero_grad()
# 计算模型中所有参数的梯度信息,这些梯度信息自动保存在每个张量的grad成员变量中
loss.backward() # 方向传播,计算所有参数的梯度
# w`= w - lr * grad
optimizer.step() # 根据梯度下降算法更新参数
train_loss.append(loss.item())
if batch_idx % 10==0:
print(epoch, batch_idx, loss.item())
plot_curve(train_loss)