深度学习基础-softmax回归的从零开始实现
1. softmax回归的从零开始实现
动手实现softmax回归。
1.1 获取、读取数据和初始化模型参数
使用Fashion-MNIST数据集,并设置批量大小为256。
跟线性回归中的例子一样,将使用向量表示每个样本。已知每个样本输入是高和宽均为28像素的图像。模型的输入向量的长度是 28 × 28=784:该向量的每个元素对应图像中每个像素。由于图像有10个类别,单层神经网络输出层的输出个数为10,因此softmax回归的权重和偏差参数分别为784 × 10和1 × 10的矩阵。
import torch
import torchvision
import numpy as np
import sys
sys.path.append("..")
import utils as d2l # 导入之前创建的包
batch_size = 256
train_iter,test_iter =d2l.load_data_fashion_mnist(batch_size)
num_inputs = 784
num_outputs = 10
W = torch.tensor(np.random.normal(0,0.01,(num_inputs,num_outputs)),dtype=torch.float)
b = torch.zeros(num_outputs,dtype=torch.float)
# 需要模型参数梯度
W.requires_grad_(requires_grad = True)
b.requires_grad_(requires_grad = True)
注意:load_data_fashion_mnist 函数封装在 utils 包里了,具体代码如下:
def load_data_fashion_mnist(batch_size, resize=None, root='~/Datasets/FashionMNIST'):
"""Download the fashion mnist dataset and then load into memory."""
trans = []
if resize:
trans.append(torchvision.transforms.Resize(size=resize))
trans.append(torchvision.transforms.ToTensor())
transform = torchvision.transforms.Compose(trans)
mnist_train = torchvision.datasets.FashionMNIST(root=root, train=True, download=True, transform=transform)
mnist_test = torchvision.datasets.FashionMNIST(root=root, train=False, download=True, transform=transform)
train_iter = torch.utils.data.DataLoader(mnist_train, batch_size=batch_size, shuffle=True)
test_iter = torch.utils.data.DataLoader(mnist_test, batch_size=batch_size, shuffle=False)
return train_iter, test_iter
1.2 实现softmax运算
在介绍如何定义softmax回归之前,先描述一下对如何对多维Tensor按维度操作。在下面的例子中,给定一个Tensor矩阵X。可以只对其中同一列(dim=0)或同一行(dim=1)的元素求和,并在结果中保留行和列这两个维度(keepdim=True)。
X = torch.tensor([[1,2,3],[4,5,6]])
print(X.sum(dim=0,keepdim=True))
print(X.sum(dim=1,keepdim=True))
输出结果:
tensor([[5, 7, 9]])
tensor([[ 6],
[15]])
下面就可以定义softmax运算了。在下面的函数中,矩阵X的行数是样本数,列数是输出个数。为了表达样本预测各个输出的概率,softmax运算会先通过exp函数对每个元素做指数运算,再对exp矩阵同行元素求和,最后令矩阵每行各元素与该行元素之和相除。这样一来,最终得到的矩阵每行元素和为1且非负。因此,该矩阵每行都是合法的概率分布。softmax运算的输出矩阵中的任意一行元素代表了一个样本在各个输出类别上的预测概率。
def softmax(X):
X_exp = X.exp()
partition = X_exp.sum(dim=1,keepdim=True)
return X_exp / partition
可以看到,对于随机输入,将每个元素变成了非负数,且每一行和为1。
X = torch.rand((2,5))
X_prob = softmax(X)
print(X_prob,X_prob.sum(dim=1))
输出结果:
tensor([[0.2165, 0.1488, 0.1669, 0.2806, 0.1873],
[0.1725, 0.1486, 0.2334, 0.1578, 0.2877]]) tensor([1.0000, 1.0000])
1.3 定义模型
有了softmax运算,可以定义前面描述的softmax回归模型了。这里通过view函数将每张原始图像改成长度为num_inputs的向量。
def net(X):
return softmax(torch.mm(X.view((-1,num_inputs)),W) + b)
1.4 定义损失函数
前面介绍了softmax 回归使用的交叉熵损失函数。为了得到标签的预测概率,我们可以使用gather函数。在下面的例子中,变量y_hat是2个样本在3个类别的预测概率,变量y是这2个样本的标签类别。通过使用gather函数,得到了2个样本的标签的预测概率。与前面(softmax回归)数学表述中标签类别离散值从1开始逐一递增不同,在代码中,标签类别的离散值是从0开始逐一递增的。
y_hat = torch.tensor([[0.1,0.3,0.6],[0.3,0.2,0.5]])
y = torch.LongTensor([0,2])
y_hat.gather(1,y.view(-1,1))
print(y_hat.gather(1,y.view(-1,1)))
# 实现之前的(softmax回归)中介绍的交叉熵损失函数
# def cross_entropy(y_hat, y):
# return - torch.log(y_hat.gather(1, y.view(-1, 1)))
输出结果:
tensor([[0.1000],
[0.5000]])
1.5 计算分类准确率
给定一个类别的预测概率分布y_hat,把预测概率最大的类别作为输出类别。如果它与真实类别y一致,说明这次预测是正确的。分类准确率即正确预测数量与总预测数量之比。
为了演示准确率的计算,下面定义准确率accuracy函数。其中y_hat.argmax(dim=1)返回矩阵y_hat每行中最大元素的索引,且返回结果与变量y形状相同。相等条件判断式(y_hat.argmax(dim=1) == y)是一个类型为ByteTensor的Tensor,我们用float()将其转换为值为0(相等为假)或1(相等为真)的浮点型Tensor。
def accuracy(y_hat,y):
return (y_hat.argmax(dim=1) == y).float.mean().item()
继续使用在演示gather函数时定义的变量y_hat和y,并将它们分别作为预测概率分布和标签。可以看到,第一个样本预测类别为2(该行最大元素0.6在本行的索引为2),与真实标签0不一致;第二个样本预测类别为2(该行最大元素0.5在本行的索引为2),与真实标签2一致。因此,这两个样本上的分类准确率为0.5。
print(accuracy(y_hat,y))
输出结果:
0.5
类似地,可以评价模型net在数据集data_iter上的准确率。
# 该函数已保存在utils包中方便以后使用。该函数将被逐步改进:完整实现将在“图像增广”
def evaluate_accuracy(data_iter, net):
acc_sum, n = 0.0, 0
for X, y in data_iter:
acc_sum += (net(X).argmax(dim=1) == y).float().sum().item()
n += y.shape[0]
return acc_sum / n
#因为随机初始化了模型net,所以这个随机模型的准确率应该接近于类别个数10的倒数即0.1。
print(evaluate_accuracy(test_iter,net))
输出结果:
0.0566
1.6 训练模型
训练softmax回归的实现跟前面(线性回归的从零开始实现)介绍的线性回归中的实现非常相似。同样使用小批量随机梯度下降来优化模型的损失函数。在训练模型时,迭代周期数num_epochs和学习率lr都是可以调的超参数。改变它们的值可能会得到分类更准确的模型。
# 该函数保存在utils包中方便以后使用
num_epochs ,lr = 5,0.1
def train_ch3(net,train_iter,test_iter,loss,num_epochs,batch_size,
params=None,lr=None,optimizer=None):
for epoch in range(num_epochs):
train_l_sum,train_acc_sum,n = 0.0,0.0,0
for X,y in train_iter:
y_hat = net(X)
l = loss(y_hat,y).sum()
#梯度清零
if optimizer is not None:
optimizer.zero_grad()
elif params is not None and params[0].grad is not None:
for param in params:
param.grad.data.zero_()
l.backward()
if optimizer is None:
d2l.sgd(params,lr,batch_size)
else:
optimizer.step()
train_l_sum +=l.item()
train_acc_sum +=(y_hat.argmax(dim=1) == y).sum().item()
n +=y.shape[0]
test_acc = evaluate_accuracy(test_iter,net)
print('epoch %d,loss %.4f,train acc %.3f,test acc %.3f'
%(epoch + 1,train_l_sum /n,train_acc_sum/n,test_acc))
train_ch3(net,train_iter,test_iter,cross_entropy,num_epochs,batch_size,[W,b],lr)
输出结果:
epoch 1,loss 0.7867,train acc 0.749,test acc 0.790
epoch 2,loss 0.5713,train acc 0.813,test acc 0.813
epoch 3,loss 0.5256,train acc 0.826,test acc 0.820
epoch 4,loss 0.5024,train acc 0.832,test acc 0.822
epoch 5,loss 0.4858,train acc 0.836,test acc 0.824
1.7 预测
训练完成后,现在就可以演示如何对图像进行分类了。给定一系列图像(第三行图像输出),比较一下它们的真实标签(第一行文本输出)和模型预测结果(第二行文本输出)。
X,y = iter(test_iter).next()
true_labels = d2l.get_fashion_mnist_labels(y.numpy())
pred_labels = d2l.get_fashion_mnist_labels(net(X).argmax(dim=1).numpy())
titles = [true + '\n' + pred for true,pred in zip(true_labels,pred_labels)]
d2l.show_fashion_mnist(X[0:9],titles[0:9])
输出结果:
- 分享
- 举报
-
浏览量:4887次2021-08-05 09:21:07
-
浏览量:5021次2021-08-05 09:20:49
-
浏览量:674次2023-12-18 18:23:15
-
浏览量:600次2023-06-12 14:35:02
-
浏览量:3573次2020-07-27 15:19:53
-
浏览量:2826次2020-08-10 09:28:54
-
浏览量:5562次2021-06-15 11:49:53
-
浏览量:4895次2021-06-21 11:50:25
-
浏览量:5034次2021-07-26 11:25:51
-
浏览量:3313次2022-08-16 19:28:15
-
浏览量:2065次2022-03-10 09:00:43
-
浏览量:2363次2023-06-12 14:34:18
-
浏览量:3702次2020-08-18 19:54:58
-
浏览量:728次2023-02-14 17:22:21
-
浏览量:869次2023-02-15 17:26:26
-
浏览量:6151次2021-06-07 11:48:50
-
浏览量:15827次2021-05-11 15:08:39
-
浏览量:430次2023-08-28 09:56:42
-
浏览量:5627次2021-02-20 17:09:58
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
Ocean
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明