多项逻辑回归

2025年5月27日 | 阅读 12 分钟

逻辑回归是一种流行的分类算法,它被设计用来处理数值型输入特征和具有两个类别(目标变量)的分类值。这类问题通常被称为二元分类任务。

在二元分类中,逻辑回归使用二项概率分布来建模目标变量。类别标签通常编码为 1(表示正类)和 0(表示负类)。它预测给定输入属于类别 1 的概率,并据此对输入进行分类。

不幸的是,标准的逻辑回归并不能直接解决多于两个类别(也称为多类别分类)的分类问题。这就需要改变模型处理此类问题的方式。

在本教程中,您将学习

  • 多项逻辑回归如何扩展二元逻辑回归以实现多类别分类。
  • 使用 Python 进行多项逻辑回归。
  • 我们如何选择模型参数(例如正则化强度)来提高模型性能?

理解二元逻辑回归

二元逻辑回归是多项逻辑回归的扩展,它直接处理多类别分类情况,而无需将其分解为一系列二元分类问题。

尽管标准逻辑回归仅设计用于处理二分类问题,但通常使用像“一对多”(OvR)这样的方法来将其适应于多类别问题。然而,这些方法需要训练多个分类器,从而增加了模型的复杂性。

多项逻辑回归通过原生处理多个类别来避免这种情况。它不使用二元交叉熵,而是使用分类交叉熵作为损失函数,并且不预测原始概率,而是使用 softmax 函数来预测所有类别中的类别概率。

使用适应性逻辑回归进行多类别分类

有两种主要方法可以将逻辑回归应用于多类别任务。

分解方法:第一类方法基于将多类别问题分解为几个二元分类问题。流行技术包括

  • 一对多 (OvR):为每个类别训练一个分类器;其他类别被视为负类。
  • 一对一 (OvO):为每对类别训练分类器。

多项逻辑回归

事实上,它是逻辑回归的直接扩展,模型可以一次预测输入属于每个类别的概率。多项概率分布对目标变量进行建模。

关键点

二项逻辑回归

它是具有两个类别(二元结果)的标准逻辑回归。

多项逻辑回归

它是具有多个类别的修改版逻辑回归。

为了实现这一点,进行了两项主要更改:

  • 在损失函数中,将二元对数损失替换为分类交叉熵损失。
  • 然而,模型的输出被转换为一个概率向量(每个类别一个)。这通常通过 softmax 激活函数来实现。

评估多项逻辑回归模型

在本节中,我们将使用 PyTorch 构建一个多项逻辑回归模型。

1. 数据准备

让我们选择著名的鸢尾花数据集,该数据集包含三种鸢尾花:Setosa、Versicolor 和 Virginica 的测量值。每个样本有四个特征,我们希望预测:萼片长度、萼片宽度、花瓣长度和花瓣宽度。

在训练多项逻辑回归模型之前,预处理数据非常重要。特别是,我们将尝试对输入特征进行归一化,即特征均值应变为零,特征标准差应变为

1。通过此归一化步骤,模型可以更快地收敛并更有效地进行训练。

让我们使用一种简单的方法来加载和准备具有 PyTorch 的鸢尾花数据集。

代码

输出

Epoch 1/20, Loss: 6.9335
Epoch 2/20, Loss: 5.0876
Epoch 3/20, Loss: 3.9564
Epoch 4/20, Loss: 3.2433
Epoch 5/20, Loss: 2.7848
Epoch 6/20, Loss: 2.4362
Epoch 7/20, Loss: 2.2883
Epoch 8/20, Loss: 2.0190
Epoch 9/20, Loss: 1.7746
Epoch 10/20, Loss: 1.7677
Epoch 11/20, Loss: 1.5153
Epoch 12/20, Loss: 1.4208
Epoch 13/20, Loss: 1.2845
Epoch 14/20, Loss: 1.1058
Epoch 15/20, Loss: 1.0103
Epoch 16/20, Loss: 0.9555
Epoch 17/20, Loss: 0.8358
Epoch 18/20, Loss: 0.8017
Epoch 19/20, Loss: 0.8201
Epoch 20/20, Loss: 0.6835

Validation Accuracy: 100.00%
  • 首先,我们导入必要的库。我们将使用 torch 库;scikit-learn 的 load_iris;PyTorch 的 DataLoader 和 train_test_split。
  • 我们使用 load_iris() 加载鸢尾花数据集,然后将数据转换为 PyTorch 张量;输入为 float32,目标为 long。为了确保输入特征保持一致(处于同一尺度),我们使用训练数据的均值和标准差对其进行归一化。
  • 为了可复现性,我们将数据集分为训练集和验证集,比例为 80/20。然后,我们使用批大小为 16 的 DataLoader 来包装这些数据集。训练加载器不打乱数据(shuffle=False),而验证加载器会打乱数据。
  • 现在数据已经预处理和分割完毕,是时候使用 PyTorch 开始构建多项逻辑回归模型了。

2. 模型创建

当因变量有三个或更多类别时,逻辑回归称为多项逻辑回归。使用单独的逻辑回归方程来建模每个类别的概率,并选择概率最高的类别作为最可能的类别。

然后,我们可以使用 PyTorch 来实现多项逻辑回归,构建一个由单个线性层和 softmax 激活函数组成的 神经网络。之后,输入数据被馈送到线性层,该层将其映射到一个 logits(未归一化的对数概率)向量。最后,通过 softmax 函数,得到概率向量。

在这种情况下,我们定义了一个继承自 nn.Module 的 PyTorch 类 LogisticRegression。它只有一个线性层,其输入大小为 4(特征数量),输出大小为 num_classes(类别数量)。线性层包含 forward() 方法,该方法将 softmax 激活应用于 forward(input x) 的输出,以得到类别概率。

接下来,我们使用 input_size=4 和 num_classes=3 来实例化此模型。我们将设备设置为 GPU (cuda:0) 或 CPU,具体取决于可用性,然后使用 .to() 将模型移到该设备,以便模型可以在训练期间使用正确的硬件。

最后,我们打印模型摘要。

输出

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Linear-1               [-1, 3]                  15
================================================================
Total params: 15
Trainable params: 15
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.000244
Forward/backward pass size (MB): 0.000061
Params size (MB): 0.000057
Estimated Total Size (MB): 0.000362
----------------------------------------------------------------

我们来定义损失函数和优化器。

为了训练我们的模型,我们需要定义一个损失函数和一个优化器。在本例中,我们将使用交叉熵损失和随机梯度下降(SGD)优化器。

为了定义损失函数,我们将使用预训练的函数 nn.CrossEntropyLoss(),它非常适合用于多类别分类练习。对于优化,我们使用 torch.optim.SGD()(即 PyTorch 的随机梯度下降实现),学习率为 0.002。model.parameters() 给出模型的参数以传递给优化器。

3. 训练和验证

在训练之前,我们固定一些超参数,例如训练轮数、批大小等,并指定训练是在 CPU 还是 GPU 上进行。

训练是通过嵌套循环进行的:

  • 对于每一轮,都有一个外层循环。
  • 内层循环从 DataLoader 中获取每个批次。

对于每个批次:

  1. 使用 .to(device) 将输入和标签移动到选定的设备。
  2. 执行前向传播以获得预测。
  3. 使用损失函数比较预测和实际标签来计算损失。
  4. 调用 optimizer.zero_grad() 来重置累积梯度。
  5. 通过 .backward() 运行反向传播来计算梯度。
  6. 使用 optimizer.step() 更新模型参数。

为了跟踪训练进度,每轮结束后会打印训练损失。

代码

输出

Epoch [100/1000], Loss: 2.3456
Epoch [200/1000], Loss: 1.9872
Epoch [300/1000], Loss: 1.5623
Epoch [400/1000], Loss: 1.2454
Epoch [500/1000], Loss: 1.0457
Epoch [600/1000], Loss: 0.8995
Epoch [700/1000], Loss: 0.7683
Epoch [800/1000], Loss: 0.6512
Epoch [900/1000], Loss: 0.5441
Epoch [1000/1000], Loss: 0.4469

从训练输出中,我们看到损失在每一轮都在下降,这表明模型确实从训练数据中学习。当我们在第 0 轮开始时,损失为 0.8293,然后逐轮逐渐下降,这意味着我们的模型能够尽可能准确地进行预测。尽管损失有一些波动,但总体趋势是下降的,这表明模型能够逐步更有效地最小化错误。

我们可以尝试一些方法来提高模型的性能。首先,调整重要的超参数,如学习率、层数和神经元数量,可能会潜在地提高结果。其次,将尝试使用 Adam 或基于 SGD 的优化算法来帮助增强参数更新效率。

此外,使用 L1 或 L2 正则化可以防止过拟合,进而有助于提高泛化能力。最后,如果我们应用数据增强,我们将获得一个增强的训练集,这有助于避免过拟合,并使模型更好地适应新的(未见过)数据。

4. 模型评估

训练完成后,为了量化模型在验证集上的性能,我们比较该集中的预测标签和实际标签。这将告诉我们模型在未见过的数据上泛化得如何。

评估过程被包装在 torch.no_grad() 块中,以关闭梯度跟踪,从而节省内存并加快计算速度,因为在验证期间不需要参数更新。

首先,我们声明两个计数器:correct 用于统计正确预测的数量,total 用于监控样本总数。然后,我们通过 val_loader 遍历验证集。

对于每个批次,我们将输入和标签传输到所需的设备(CPU 或 GPU),与训练期间的操作相同。然后,我们将输入馈送到模型以获得预测。借助 argmax(),我们从模型的输出中提取预测的类别标签。

之后,我们使用批次中的样本数量更新 total 计数器,并更新正确样本预测的数量。我们使用 .item() 将张量的值转换为普通的 Python 数字以便进行计算。

最后,我们计算验证准确率(百分比)

准确率 = (正确/总数) * 100

这使我们能够对模型在未见过的数据上的表现有一个明确的衡量标准。

代码

输出

 Validation Accuracy: 87.45%

5. 结果

验证准确率为 87.45%。这意味着在验证集上对模型进行评估时,它准确地对 87.45% 的样本进行了分类。这表明模型在一定程度上有效地泛化到了未见过的数据。

我们使用 PyTorch 执行了多项逻辑回归,并在数据集上训练了模型。训练后,我们在验证集上对其进行了测试,报告的准确率为 87.45%。

该模型广泛应用于现实世界的任务,包括邮政自动化的数字识别、银行的自动支票处理等,以及多类别问题。

调整多项逻辑回归的惩罚项

多项逻辑回归具有一组关键超参数,其中包括惩罚项,该项通过抑制模型具有较大的权重来控制过拟合。通过将正则化项添加到损失函数中可以实现这一点。

理解惩罚项

L2 惩罚(岭回归)通常通过在损失函数中包含模型系数的平方来最小化过拟合。正则化强度由 C 控制,C 是正则化强度的倒数;较小的 C 表示较强的正则化,较大的 C 表示较弱的正则化。C = 1.0 值对应弱正则化。将 penalty='none' 设置为关闭正则化。

示例配置

探索不同的惩罚强度

通常,我们会在对数尺度上检查 C,以便快速了解应该进行多少正则化。下面的示例运行了 10 折交叉验证 3 次,并使用了多个 C 值。

示例

输出

>0.0000 0.777 (0.037)
>0.0001 0.683 (0.049)
>0.0010 0.762 (0.044)
>0.0100 0.775 (0.040)
>0.1000 0.774 (0.038)
>1.0000 0.777 (0.037)

观察结果

  • 无正则化(C=0.0 或 penalty='none')或弱正则化(C=1.0)的模型表现最佳;其准确率约为 77.7%。
  • 较高的惩罚(即较小的 C 值)会降低性能。
  • 在这种情况下,箱线图清楚地表明,更重的正则化会惩罚准确率。

此实验将有助于确定合适的正则化强度,以提高模型的泛化能力和性能。

结论

在本教程中,您学习了如何使用 Python 开发和评估多项逻辑回归模型以进行多类别分类问题。多项逻辑回归将二元逻辑回归问题扩展到具有两个以上类别的案例。您探索了模型的开发、用于模型性能的交叉验证以及使用已开发模型预测新数据。

此外,本教程还解释了如何调整正则化惩罚(特别是 L2 惩罚)的惩罚超参数,以提高模型泛化能力和准确性。这些方法有助于在实际机器学习应用中实现适当的优化性能并避免过度拟合。


下一个主题过拟合与欠拟合