05Softmax
回归基础版
主要内容
- 初始化模型参数:定义输入和输出的维度,初始化权重
W
和偏置b
。 - 定义
Softmax
函数:实现Softmax
函数,将输入的每个元素转换为概率。 - 定义模型:实现
Softmax
回归模型,将每个图像展平为向量并计算输出。 - 定义损失函数:实现交叉熵损失函数。
- 定义分类精度计算函数:计算预测正确的数量。
- 定义累加器类:用于对多个变量进行累加。
- 定义精度评估函数:计算模型在指定数据集上的精度。
- 定义训练一个迭代周期的函数:训练模型一个迭代周期,并计算训练损失和准确度。
- 定义动画绘制实用程序类:用于在动画中绘制训练过程中的损失和准确度。
- 定义训练函数:训练模型多个迭代周期,并在每个周期后绘制训练损失和准确度。
- 定义参数更新函数:使用小批量随机梯度下降优化模型的损失函数。
- 定义预测函数:对测试数据进行预测,并显示前 6 个样本的图像及其真实和预测标签。
import torch
import numpy as np
from IPython import display
import PIL as plt
from d2l import torch as d2l
#设置数据迭代器的批量大小为256
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
#初始化模型参数
#原始数据集中的每个样本都是28*28
#由于softmax回归,输入是一个向量。
#将展平每个图像,把它们看作长度为784的向量。
num_inputs = 784
#因为我们的数据集有10个类别,所以网络输出维度为10
num_outputs = 10
W = torch.normal(0,0.01,size=(num_inputs,num_outputs),requires_grad=True)
b = torch.zeros(num_outputs,requires_grad=True)
#回顾:给定一个矩阵X,我们可以对所有元素求和
# X = torch.tensor([[1.0,2.0,3.0],[4.0,5.0,6.0]])
# #keepdim 表示是否需要保持输出的维度与输入一样
# print(X.shape)
# print(X.sum(0, keepdim = True))
# print(X.sum(1, keepdim = True))
"""
torch.Size([2, 3])
tensor([[5., 7., 9.]])
tensor([[ 6.],
[15.]])
"""
# 定义softmax函数
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)
# print(X)
# print(X_prob)
# print(X_prob.sum(1,keepdim=True))
"""
tensor([[-1.8393, 1.1537, -0.3047, 0.2240, -0.9293],
[-0.6396, 0.4152, -0.3158, -0.1546, -0.1579]])
tensor([[0.0278, 0.5550, 0.1291, 0.2190, 0.0691],
[0.1177, 0.3379, 0.1627, 0.1912, 0.1905]])
tensor([[1.0000],
[1.0000]])
"""
#定义模型-实现softmax回归模型
def net(X):
#w.shape[0]为784
#使用reshape函数将每张原始图像展平为向量,然后进行矩阵乘法并加上偏置
#X变成256 * 784的矩阵
return softmax(torch.matmul(X.reshape((-1,W.shape[0])), W) + b)
#定义损失函数
#回顾:交叉熵采用真实标签的预测概率的负对数似然
#y_hat[[0,1],y]中的[0,1]指的是第一行和第二行的索引,
#后面的y等价于[0,2]。那么可以这么理解y_hat[0,0]和y_hat[1,2]
y = torch.tensor([0,2])
y_hat = torch.tensor([[0.1,0.2,0.6],[0.3,0.2,0.5]])
# print(y_hat[[0,1]])
# print(y_hat[[0,1],y])
#实现交叉熵损失函数
def cross_entropy(y_hat, y):
#y_hat[range(len(y_hat)),y]得到真实标量的预测值
#len(y_hat)是2
#range(len(y_hat))是range(0,2)
#range(0,2)是[0,1]
return -torch.log(y_hat[range(len(y_hat