softmax回归模型,实际是一个分类模型,与线性回归模型有很多不同的地方(与线性回归一样都是一个单层的神经网络)
输入图片的每一个像素值都可以用一个标量表示,我们将图片中的4个像素用 x1,x2,x3,x4表示
假设训练数据集中图像的真实标签为狗、猫或鸡(假设可以用4像素表示出这3种动物),这些标签分别对应离散值y 1 , y 2 , y 3
softmax回归跟线性回归一样将输入特征与权重做线性叠加。与线性回归的一个主要不同在于,softmax回归的输出值个数等于标签里的类别数。因为一共有4种特征和3种输出动物类别,所以权重包含12个标量(带下标的w)、偏差包含3个标量(带下标的b),每个输入都会得到三个输出o1,o2,o3
输出oi当作预测类别i的置信度,将最大的置信度输出作为预测的种类(我们会用一些方法把Oi转换成为概率),假如O1=o.1,O2=o.3,O3=0.6 , 最大,那么预测类别为2,其代表猫。
引入数据集
#sec_fashion_mnist中引入的Fashion-MNIST数据集, 并设置数据迭代器的批量大小为256
import torch
from IPython import display
from d2l import torch as d2l
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)//iter 是迭代器
初始化模型参数
num_inputs = 784#模型输入有784
num_outputs = 10#模型输入有10
W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)#初始一个权重,选一个高斯随机数据为权重
b = torch.zeros(num_outputs, requires_grad=True)#初始化偏差,利用某个数学方法在数据中选择一个作为偏差
定义softmax操作
X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdim=True), X.sum(1, keepdim=True)
def softmax(X):
X_exp = torch.exp(X)#对元素进行指数计算
partition = X_exp.sum(1, keepdim=True)#对每一行进行求和
return X_exp / partition # 这里应用了广播机制
#将输出变成总概率为1
X = torch.normal(0, 1, (2, 5))
X_prob = softmax(X)
X_prob, X_prob.sum(1)
定义模型
def net(X):
return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b
定义损失函数
def cross_entropy(y_hat, y):
return - torch.log(y_hat[range(len(y_hat)), y])
cross_entropy(y_hat, y)
分类精度
#将预测类别与真实y元素进行比较
def accuracy(y_hat, y): #@save
"""计算预测正确的数量"""
if len(y_hat.shape) > 1 and y_hat.shape[1] > 1:
y_hat = y_hat.argmax(axis=1)
cmp = y_hat.type(y.dtype) == y
return float(cmp.type(y.dtype).sum())
accuracy(y_hat, y) / len(y)#预测正确的概率
绘制动画
#在展示训练函数的实现之前,我们[定义一个在动画中绘制数据的实用程序类]Animator
class Animator: #@save
"""在动画中绘制数据"""
def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,
ylim=None, xscale='linear', yscale='linear',
fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,
figsize=(3.5, 2.5)):
# 增量地绘制多条线
if legend is None:
legend = []
d2l.use_svg_display()
self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)
if nrows * ncols == 1:
self.axes = [self.axes, ]
# 使用lambda函数捕获参数
self.config_axes = lambda: d2l.set_axes(
self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
self.X, self.Y, self.fmts = None, None, fmts
def add(self, x, y):
# 向图表中添加多个数据点
if not hasattr(y, "__len__"):
y = [y]
n = len(y)
if not hasattr(x, "__len__"):
x = [x] * n
if not self.X:
self.X = [[] for _ in range(n)]
if not self.Y:
self.Y = [[] for _ in range(n)]
for i, (a, b) in enumerate(zip(x, y)):
if a is not None and b is not None:
self.X[i].append(a)
self.Y[i].append(b)
self.axes[0].cla()
for x, y, fmt in zip(self.X, self.Y, self.fmts):
self.axes[0].plot(x, y, fmt)
self.config_axes()
display.display(self.fig)
display.clear_output(wait=True)
训练
def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater): #@save
"""训练模型(定义见第3章)"""
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):#扫n遍数据
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 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
#小批量随机梯度下降来优化模型的损失函数,设置学习率为0.1
lr = 0.1
def updater(batch_size):
return d2l.sgd([W, b], lr, batch_size)
num_epochs = 10#训练10个迭代周期
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater)#开始训练
预测
#现在训练已经完成,我们的模型已经准备好[对图像进行分类预测]。 给定一系列图像,我们将比较它们的实际标签(文本输出的第一行)和模型预测(文本输出的第二行)
def predict_ch3(net, test_iter, n=6): #@save
"""预测标签(定义见第3章)"""
for X, y in test_iter:
break
trues = d2l.get_fashion_mnist_labels(y)
preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))
titles = [true +'\n' + pred for true, pred in zip(trues, preds)]
d2l.show_images(
X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])
predict_ch3(net, test_iter)
引入数据集
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)
初始化模型参数
PyTorch不会隐式地调整输入的形状。因此,
# 我们在线性层前定义了展平层(flatten),来调整网络输入的形状
net = nn.Sequential(nn.Flatten(), nn.Linear(784, 10))#模型在这里创建出来
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')
优化算法
trainer = torch.optim.SGD(net.parameters(), lr=0.1)#调用优化算法,设置学习率为0.1 ,这与我们在线性回归例子中的相同,这说明了优化器的普适性
训练
num_epochs = 10#训练10圈
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)#调用第三章的那个ch3函数训练