1. Softmax回归简介
在机器学习中,分类问题常常要求我们将输入数据分配到不同的类别。例如,假设我们有一组图像数据,每个图像可能是一个数字(0到9中的一个)。我们希望创建一个模型,使得它可以根据输入的图像预测它所代表的数字。
Softmax回归就是 用来解决这类多类别分类问题 的一种模型。它通过将每个类别的得分转化为概率,帮助我们确定输入属于哪个类别。
在之前的文章中,我们已经学习了线性回归的实现。在本文中,我们将使用类似的方法来实现Softmax回归,但是输出的结果会有一些不同,因为我们需要处理多个类别的情况。
2. 初始化模型参数
在实现Softmax回归时,我们的模型包含一个输出层,它是一个全连接层(fully connected layer)。这个层将每个输入的特征映射到多个输出类别。
在PyTorch中,我们可以通过 nn.Linear 来定义全连接层。对于Softmax回归模型,我们将输入特征的维度(例如28x28像素的图像,我们的输入特征维度为784)映射到10个输出类别。这里我们还需要初始化模型的权重。
from torch import nn
import d2l
# 设置批量大小
batch_size = 256
# 加载训练和测试数据
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
in_features = 28 * 28 # 输入特征数(展平成一维)
out_features = 10 # 输出特征数
# 使用框架定义模型
net = nn.Sequential(nn.Flatten(), nn.Linear(in_features, out_features))
# 初始化模型权重参数
def init_weights(m):
if isinstance(m, nn.Linear):
nn.init.normal_(m.weight, std=0.01)
# 模型应用参数
net.apply(init_weights)
在这段代码中,我们定义了一个简单的神经网络,其中包含了一个Flatten层,将28x28的图像展平为784个输入特征,然后通过一个线性层输出10个类别的得分。
nn.Flatten是PyTorch中的一个层,用于将多维输入张量展平为一维张量。在处理图像数据时,图像通常是二维的(例如28x28像素),而全连接层(如nn.Linear)的输入需要是一维的。因此,我们使用nn.Flatten
将图像的二维数据展平为一维数据,以便将其输入到全连接层。
3. 重新审视Softmax的实现
Softmax回归的核心在于 使用Softmax函数将每个类别的得分转化为概率。Softmax函数的公式如下:
其中,是模型的输出向量,是输出向量中的第个元素,是所有元素的指数和。
然而,计算Softmax时可能遇到数值稳定性的问题。具体来说,计算指数时,某些元素的值可能非常大,导致数值溢出(overflow)或下溢(underflow)。为了解决这个问题,我们通常会在计算Softmax之前,从所有输出中减去最大值,这样做不会影响Softmax的结果,但可以避免溢出问题。
数学上,改进后的Softmax公式为:
这样做的好处是,我们避免了数值溢出的风险,同时保持了Softmax的准确性。
为了进一步提高计算的稳定性,我们将Softmax和交叉熵损失结合在一起,直接计算未规范化的得分和它们的对数。这样就避免了在反向传播中可能出现的数值不稳定问题。
在PyTorch中,我们可以使用nn.CrossEntropyLoss来实现这一点:
loss = nn.CrossEntropyLoss(reduction='none')
这个函数内部已经对Softmax和交叉熵损失进行了优化,并且能够处理数值稳定性的问题。
nn.CrossEntropyLoss中的reduction参数用于指定如何对损失值进行处理,具体有三个选项:
-
none:不进行任何处理,返回每个样本的损失值。返回的结果是一个包含每个样本损失的张量。 -
mean(默认值):对所有样本的损失值求平均,返回一个标量,表示所有样本的平均损失。 -
sum:对所有样本的损失值求和,返回一个标量,表示所有样本的总损失。
4. 优化算法
为了训练我们的模型,我们需要使用优化算法来更新模型的参数。我们使用小批量随机梯度下降(SGD)作为优化算法。其主要思想是:每次计算模型的梯度后,沿着梯度的反方向调整模型的参数。
在这里,我们设置学习率为0.1,使用PyTorch的torch.optim.SGD来创建优化器。
lr = 0.1 # 学习率
# 使用小批量随机梯度下降(SGD)作为优化算法
trainer = torch.optim.SGD(net.parameters(), lr=lr)
5. 训练模型
现在我们已经完成了模型的定义、损失函数和优化算法的选择,接下来就是训练模型。我们可以调用之前定义的训练函数来进行训练。
if __name__ == '__main__':
num_epochs = 10
metric = d2l.Accumulator(3)
animator = d2l.Animator(xlabel='轮数', xlim=[1, num_epochs], ylim=[0, 1],
legend=['train loss', 'train acc', 'test acc'])
# 训练模型
d2l.train_softmax(net, train_iter, test_iter, loss,
num_epochs, trainer, batch_size, animator)
# 可视化优化过程
animator.show()
在这段代码中,我们设置了训练的轮数为10,并开始训练模型。训练过程中,模型会通过多次迭代逐步优化参数,从而提高预测的准确性。
6. 总结
本文我们学习了如何用PyTorch实现Softmax回归。Softmax回归的核心思想是将每个类别的得分转化为概率,并通过交叉熵损失函数进行优化。我们还学习了如何处理Softmax中的数值稳定性问题,以及如何使用PyTorch来简洁地实现Softmax回归。