深度学习softmax回归(基于pytorch)

1,374 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

1.环境配置要求及常见问题

pytorch 1.12.1

image.png
numpy 1.21.5

image.png
d2l包0.17.5

image.png

在我们运行的时候我们会出现这样几种情况:

1.# No module named ‘tqdm‘

这种报错解决的办法是在我们所运行的环境下输入命令:conda install tqdm 或者pip install tqdm

image.png

2. No module named 'torchtext'

这种问题同上,缺什么下载什么。conda install torchtext

image.png

3.d2lzh_pytorch包没有的话可以在百度上搜索下载,然后放在运行环境的lib文件中。

2.代码实现

2.1导入环境

image.png

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.

image.png

batch_size=256
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size)

2.3 初始化模型参数

image.png

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运算

image.png

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 定义模型

image.png

def net(X):
    return softmax(torch.mm(X.view((-1,num_inputs)),W)+b)

这里是通过view函数将每张原始图像改成长度为num_inputs的向量。

2.6 损失函数

image.png

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函数,我们可以得到两个样本的标签的预测概率。

image.png

def cross_entropy(y_hat,y):
    return - torch.log(y_hat.gather(1,y.view(-1,1)))

这里是实现交叉熵损失函数。

2.7 计算分类准确率

image.png

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形状相同。

image.png

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 训练模型

image.png

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 预测

模型到底好不好用,实践出真知。

image.png

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])

其中第一行是它的真实标签,第二行是模型预测结果。