3.6--softmax回归的从零开始实现

前言

本节介绍softmax和交叉熵损失函数的从零开始实现。


一、导入相关的库

import torch
import torchvision
import numpy as np
import sys
sys.path.append("..") # 为了导入上层目录的d2lzh_pytorch
import d2lzh_pytorch as d2l

print(torch.__version__)
print(torchvision.__version__)

2.3.1+cpu
0.14.1+cu117

二、数据和模型参数

1.读取数据

使用上一节提供的方法

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

2.初始化模型参数

定义权重和偏差

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) 

sum函数求和实例

# sum函数求和实例
X = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(X.size())
print(X.sum(dim=0, keepdim=True))
print(X.sum(dim=1, keepdim=True))

三、实现softmax运算

# X.exp()是对tensor中每个变量操作
def softmax(X):
	X_exp = X.exp()
	partition = X_exp.sum(dim=1, keepdim=True)
	# 这里应用了广播机制
	return X_exp/partition

四、定义模型

# 返回256×10的张量
def net(X):
    return softmax(torch.mm(X.view((-1, num_inputs)), W) + b)

五、定义损失函数

gather()参数dim=1表示,矩阵中数的值是列值,矩阵中数所处位置的行值是行值。dim=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))

tensor([[0.1000],
[0.5000]])

# 交叉熵损失函数
# 先选出y_hat对应样本标签处的值,然后求对数就是交叉熵损失函数的值
def cross_entropy(y_hat, y):
    return - torch.log(y_hat.gather(1, y.view(-1, 1)))

六、计算分类准确率

本函数已保存在d2lzh_pytorch包中方便以后使用

def evaluate_accuracy(data_iter, net):
    acc_sum, n = 0.0, 0
    for X, y in data_iter:
        # net(X)使样本经过模型和softmax,argmax(dim=1)输出样本最大值的索引,然后判断是否与真实标签相等
        acc_sum += (net(X).argmax(dim=1) == y).float().sum().item() # argmax(dim=1)表示第二个维度中最大值的下标
        n += y.shape[0]
    return acc_sum / n

测试

print(evaluate_accuracy(test_iter, net))

0.0477

七、训练模型

num_epochs, lr = 5, 0.1

# 本函数已保存在d2lzh_pytorch包中方便以后使用
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)
            # sum()的原因是后面要根据标量反向传播
            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_()
            # 反向传播原因可以看这篇文章https://blog.csdn.net/weixin_45021364/article/details/105194187
            l.backward()
            # 优化器修改模型参数,修改params.data梯队不会对其计算
            if optimizer is None:
                d2l.sgd(params, lr, batch_size)
            else:
                optimizer.step()  # “softmax回归的简洁实现”一节将用到
            
            # train_l_sum为交叉熵损失函数的和
            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.7857, train acc 0.747, test acc 0.790
epoch 2, loss 0.5713, train acc 0.813, test acc 0.812
epoch 3, loss 0.5252, train acc 0.826, test acc 0.820
epoch 4, loss 0.5016, train acc 0.831, test acc 0.824
epoch 5, loss 0.4858, train acc 0.837, test acc 0.825

八、预测

X, y = next( iter(test_iter))
# 真实样本标签
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)]
# 显示前9张图
d2l.show_fashion_mnist(X[0:9], titles[0:9])

在这里插入图片描述


总结

从这节中学到了
1.softmax对模型预测结果的处理,softmax使预测概率为正数,并且概率在范围[0,1]。
2.交叉熵损失函数为softmax处理结果中,把样本真实标签对应位置的预测概率求对数再取反就是对应样本的损失函数。
3.准确率是样本预测正确总数除样本总数。
4.模型每次迭代训练过程为:正向传播、计算损失函数、反向传播(梯度清零)、优化器修改模型参数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值