持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情
1.环境配置要求及常见问题
pytorch 1.12.1
numpy 1.21.5
d2l包0.17.5
在我们运行的时候我们会出现这样几种情况:
1.# No module named ‘tqdm‘
这种报错解决的办法是在我们所运行的环境下输入命令:conda install tqdm 或者pip install tqdm
2. No module named 'torchtext'
这种问题同上,缺什么下载什么。conda install torchtext
3.d2lzh_pytorch包没有的话可以在百度上搜索下载,然后放在运行环境的lib文件中。
2.代码实现
2.1导入环境
import torch
import torchvision
import numpy as np
import sys
sys.path.append("E:/anaconda/envs/pytorch/Lib/d2lzh_pytorch")
import d2lzh_pytorch as d2l
2.2 获取和读取数据
这里我们使用Fashion-MINIST数据集,并设置批量大小为256.
batch_size=256
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size)
2.3 初始化模型参数
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)#初始化置0
这里我们将模型的参数梯度设置成True,如果不设置成True就会默认为False.
W.requires_grad_(requires_grad=True)
b.requires_grad_(requires_grad=True)
这里的样本都是高和宽28像素的图像。所以输入向量的长度是28*28=784.图像我们是将它们区分为数字0,1,2,3,4,5,6,7,8,9共计十种。所以单层神经网络输出层的输出个数为10。
2.4 实现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))
2.5 定义模型
def net(X):
return softmax(torch.mm(X.view((-1,num_inputs)),W)+b)
这里是通过view函数将每张原始图像改成长度为num_inputs的向量。
2.6 损失函数
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))
这里我们为了得到标签的预测概率,我们可以使用gather函数。通过使用gather函数,我们可以得到两个样本的标签的预测概率。
def cross_entropy(y_hat,y):
return - torch.log(y_hat.gather(1,y.view(-1,1)))
这里是实现交叉熵损失函数。
2.7 计算分类准确率
def accuracy(y_hat,y):
return (y_hat.argmax(dim=1)==y).float().mean().item()
print(accuracy(y_hat,y))
这里的y_hat.argmax(dim=1)返回矩阵y_hat每行中最大元素的索引,且返回结果与变量y形状相同。
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.
2.8 训练模型
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_1_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_1_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_1_sum/n,train_acc_sum/n,test_acc))
train_ch3(net,train_iter,test_iter,cross_entropy,num_epochs,batch_size,[W,b],lr)
这里训练softmax回归模型的实现跟上一节的线性回归的训练很接近。也是使用小批量随机梯度下降来优化模型的损失函数。
2.9 预测
模型到底好不好用,实践出真知。
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])
其中第一行是它的真实标签,第二行是模型预测结果。