上一篇blog详细的讲了softmax的具体实现方法,这些有助于我们逐渐入门深度学习,当然我们强大的Pytorch库中就有现成的方法实现softmax,本章就来展示一下使用方法。
延用上一章的例子,对图片进行分类,使用fashion_mnist库。
import torch
from torch import nn
from d2l import torch as d2l
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
在线性回归简易实现的blog中有讲到过神经网络的Sequential,它表示多层连接,在softamx中只需要单层,并且用全连接实现,
# PyTorch不会隐式地调整输入的形状。因此,
# 我们在线性层前定义了展平层(flatten),来调整网络输入的形状
#flatten将28*28的二维图像展开成了784长度的一维数组
#输入长度784,输出长度10
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))
#将权重初始化,均值0,方差0.01
def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights);
这里用一句代码就可以实现softmax和交叉熵损失函数:
loss = nn.CrossEntropyLoss(reduction='none')
这里使用到了和线性回归一样的优化方法:随机梯度下降
这句话就是对模型中的权重进行梯度下降的优化处理,学习率赋值0.1
trainer = torch.optim.SGD(net.parameters(), lr=0.1
num_epochs = 10
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
train_ch3是上一篇详细实现softmax中写的函数,这里再回忆一下:
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater): #@save
"""训练模型"""
animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3, 0.9],
legend=['train loss', 'train acc', 'test acc'])
for epoch in range(num_epochs):
train_metrics = train_epoch_ch3(net, train_iter, loss, updater)
test_acc = evaluate_accuracy(net, test_iter)
animator.add(epoch + 1, train_metrics + (test_acc,))
train_loss, train_acc = train_metrics
#assert 断言 false 报错
assert train_loss < 0.5, train_loss
assert train_acc <= 1 and train_acc > 0.7, train_acc
assert test_acc <= 1 and test_acc > 0.7, test_acc
本文中的net用的是神经网络实现的模型,等同于上一篇blog中的y=Xw
一次迭代函数回顾:
def train_epoch_ch3(net, train_iter, loss, updater): #@save
"""训练模型一个迭代周期"""
# 将模型设置为训练模式
if isinstance(net, torch.nn.Module):
net.train() #要计算梯度
# 训练损失总和、训练准确度总和、样本数
metric = Accumulator(3)
for X, y in train_iter:
# 计算梯度并更新参数
y_hat = net(X)
l = loss(y_hat, y)
if isinstance(updater, torch.optim.Optimizer):
# 使用PyTorch内置的优化器和损失函数
updater.zero_grad()
l.mean().backward()
updater.step()
else:
# 使用定制的优化器和损失函数
# 我们这里会用到小批量随机梯度下降
l.sum().backward()
updater(X.shape[0])
metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())
# 返回训练损失和训练精度
return metric[0] / metric[2], metric[1] / metric[2]
那么至此,softmax使用框架的实现就完成了
可以看出框架实现softmax回归是真的快,但搞清楚原理同样的重要。对于一些有点规律的分类问题来说使用softmax回归是个不错的选择,就像本文用的MNIST-FASHION数据集,一张衣服的图片,像素点就集中在那么几块区域,他和鞋子的像素点分布肯定是不同的,这种就是比较有特点的分类问题,softmax就很合适,那么碰到这种问题直接套本文的这些代码就会很快。