PyTorch 框架实现逻辑回归:从数据预处理到模型训练全流程

系列文章目录

01-PyTorch新手必看:张量是什么?5 分钟教你快速创建张量!
02-张量运算真简单!PyTorch 数值计算操作完全指南
03-Numpy 还是 PyTorch?张量与 Numpy 的神奇转换技巧
04-揭秘数据处理神器:PyTorch 张量拼接与拆分实用技巧
05-深度学习从索引开始:PyTorch 张量索引与切片最全解析
06-张量形状任意改!PyTorch reshape、transpose 操作超详细教程
07-深入解读 PyTorch 张量运算:6 大核心函数全面解析,代码示例一步到位!
08-自动微分到底有多强?PyTorch 自动求导机制深度解析
09-从零手写线性回归模型:PyTorch 实现深度学习入门教程
10-PyTorch 框架实现线性回归:从数据预处理到模型训练全流程

11-PyTorch 框架实现逻辑回归:从数据预处理到模型训练全流程


文章目录

  • 系列文章目录
  • 前言
  • 一、逻辑回应基础概念
    • [1.1 逻辑回应的数学表达](#1.1 逻辑回应的数学表达)
      • [1.1.1 交叉疵损失函数](#1.1.1 交叉疵损失函数)
    • [1.2 逻辑回应的应用场景](#1.2 逻辑回应的应用场景)
  • [二、使用 PyTorch 实现逻辑回应](#二、使用 PyTorch 实现逻辑回应)
    • [2.1 数据准备](#2.1 数据准备)
      • [2.1.1 注意事项](#2.1.1 注意事项)
    • [2.2 模型构建](#2.2 模型构建)
      • [2.2.1 关键代码解析](#2.2.1 关键代码解析)
    • [2.3 模型训练](#2.3 模型训练)
      • [2.3.1 注意事项](#2.3.1 注意事项)
    • [2.4 模型测试](#2.4 模型测试)
      • [2.4.1 可视化分类结果](#2.4.1 可视化分类结果)
    • [2.5 示例输出](#2.5 示例输出)
  • 三、常见问题与优化
    • [3.1 常见问题](#3.1 常见问题)
      • [3.1.1 训练不收敛](#3.1.1 训练不收敛)
      • [3.1.2 模型过拟合](#3.1.2 模型过拟合)
      • [3.1.3 测试精度较低](#3.1.3 测试精度较低)
    • [3.2 优化技巧](#3.2 优化技巧)
      • [3.2.1 学习率调整](#3.2.1 学习率调整)
      • [3.2.2 正则化](#3.2.2 正则化)
      • [3.2.3 批量训练](#3.2.3 批量训练)
      • [3.2.4 使用更复杂的特征](#3.2.4 使用更复杂的特征)
      • [3.2.5 增加模型复杂度](#3.2.5 增加模型复杂度)
  • 四、总结
    • [4.1 完整代码](#4.1 完整代码)
    • [4.2 优化后代码](#4.2 优化后代码)
      • [4.2.1 完整代码](#4.2.1 完整代码)
      • [4.2.2 示例输出](#4.2.2 示例输出)

前言

逻辑回应是机器学习中一种经典的监督学习算法,常用于解决分类问题。在深度学习领域,PyTorch 作为一个高效且灵活的框架,为逻辑回应的实现提供了强大的支持。本篇文章将系统介绍如何使用 PyTorch 实现逻辑回应,逐步从基础概念到代码实现,并结合实际应用场景,为初学者和进阶读者提供完整的学习路径。

适用读者

  • 想了解 PyTorch 基础操作的初学者。
  • 希望掌握逻辑回应实现与应用的进阶学习者。
  • 寻找分类任务实践指导的开发者。

文章结构

  1. 逻辑回应基础概念与理论解析。
  2. 使用 PyTorch 实现逻辑回应的完整步骤。
  3. 实际案例分析及代码示例。
  4. 常见问题与优化技巧。

一、逻辑回应基础概念

逻辑回应是一种用于二分类问题的线性模型,其核心思想是利用 sigmoid 函数将线性回应的输出映射到 (0,1) 区间,从而得到类别概率。

1.1 逻辑回应的数学表达

逻辑回应的目标是建立输入特征 X X X 与输出类别 Y Y Y 之间的关系:

P ( Y = 1 ∣ X ) = σ ( W X + b ) P(Y=1|X) = \sigma(WX + b) P(Y=1∣X)=σ(WX+b)

其中:

  • σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1+e^{-z}} σ(z)=1+e−z1 是 sigmoid 激活函数。
  • W W W 是权重矩阵, b b b 是偏缘项。
  • 输出 P ( Y = 1 ∣ X ) P(Y=1|X) P(Y=1∣X) 表示预测为类别 1 的概率。

通过最小化交叉疵损失(Cross-Entropy Loss),优化 W W W 和 b b b 的值,最终得到分类模型。

1.1.1 交叉疵损失函数

对于二分类问题,交叉疵损失函数的公式为:

L = − 1 N ∑ i = 1 N [ y i log ⁡ ( y ^ i ) + ( 1 − y i ) log ⁡ ( 1 − y ^ i ) ] L = -\frac{1}{N} \sum_{i=1}^N \left[ y_i \log(\hat{y}_i) + (1-y_i)\log(1-\hat{y}_i) \right] L=−N1i=1∑N[yilog(y^i)+(1−yi)log(1−y^i)]

其中:

  • y i y_i yi 是真实标签, y ^ i \hat{y}_i y^i 是模型预测概率。
  • N N N 是样本数量。

通过梯度下降法优化上述损失函数,即可训练逻辑回应模型。

1.2 逻辑回应的应用场景

逻辑回应广泛应用于以下领域:

  • 医学诊断:如病症预测(是否患病)。
  • 金融风控:如信用评分(用户是否违约)。
  • 自然进行处理:如文本分类(垃圾邮件检测)。

二、使用 PyTorch 实现逻辑回应

接下来,将通过 PyTorch 框架实现一个完整的逻辑回应模型,包括数据准备、模型构建、训练与测试。

2.1 数据准备

我们以一个简单的二分类问题为例,使用 PyTorch 内置的 make_classification 方法生成数据集。

python 复制代码
import torch
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 生成数据集
# 修正后的生成数据集代码
X, y = make_classification(
    n_samples=1000,         # 样本数
    n_features=2,           # 总特征数
    n_informative=2,        # 有效特征数(与 n_features 相等)
    n_redundant=0,          # 冗余特征数(设置为 0)
    n_repeated=0,           # 重复特征数(设置为 0)
    n_classes=2,            # 分类类别数
    random_state=42         # 随机种子
)


# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 数据标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 转换为 PyTorch 张量
X_train = torch.tensor(X_train, dtype=torch.float32)  # 转换训练集为 PyTorch 张量
y_train = torch.tensor(y_train, dtype=torch.float32).unsqueeze(1)  # 保证标签维度为 [N, 1]
X_test = torch.tensor(X_test, dtype=torch.float32)  # 转换测试集为 PyTorch 张量
y_test = torch.tensor(y_test, dtype=torch.float32).unsqueeze(1)  # 保证测试集标签维度为 [N, 1]

2.1.1 注意事项

  • 数据标准化是逻辑回归的关键步骤,可加速模型收敛。
  • 确保标签维度一致,例如 y_train 的 shape 应为 [N, 1]

2.2 模型构建

在 PyTorch 中,我们可以通过 torch.nn.Module 自定义逻辑回归模型。

python 复制代码
import torch.nn as nn

class LogisticRegression(nn.Module):
    def __init__(self, input_dim):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_dim, 1)  # 定义线性层,用于实现线性变换 WX + b
        self.sigmoid = nn.Sigmoid()  # 定义 Sigmoid 激活函数

    def forward(self, x):
        return self.sigmoid(self.linear(x))  # 前向传播过程,线性变换后通过 Sigmoid 激活

# 初始化模型
input_dim = X_train.shape[1]  # 获取输入特征的维度
model = LogisticRegression(input_dim)  # 实例化逻辑回归模型

2.2.1 关键代码解析

  • nn.Linear 实现线性变换 W X + b WX + b WX+b。
  • nn.Sigmoid 将线性输出映射到概率范围。

2.3 模型训练

逻辑回归的训练过程包括定义损失函数、优化器,并循环迭代更新参数。

python 复制代码
# 定义损失函数和优化器
criterion = nn.BCELoss()  # 使用二分类交叉熵损失函数
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)  # 使用随机梯度下降优化器,学习率为 0.01

# 训练模型
epochs = 100  # 训练轮次
for epoch in range(epochs):
    # 前向传播
    outputs = model(X_train)  # 获取模型对训练集的预测结果
    loss = criterion(outputs, y_train)  # 计算损失函数值

    # 反向传播
    optimizer.zero_grad()  # 清除梯度缓存,避免梯度累积
    loss.backward()  # 计算梯度
    optimizer.step()  # 更新模型参数

    # 打印训练信息
    if (epoch+1) % 10 == 0:  # 每 10 个 epoch 打印一次损失
        print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')

2.3.1 注意事项

  • 使用 optimizer.zero_grad() 清除梯度,避免累积。
  • 交叉熵损失函数需要模型输出为概率值,因此需要 Sigmoid 激活。

2.4 模型测试

最后,我们评估模型的分类性能。

python 复制代码
# 模型评估
y_pred = model(X_test)  # 获取模型对测试集的预测概率
y_pred_class = (y_pred >= 0.5).float()  # 将概率值转换为二分类标签(0 或 1)

accuracy = (y_pred_class == y_test).sum() / y_test.shape[0]  # 计算分类准确率
print(f'Accuracy: {accuracy:.4f}')  # 打印准确率

2.4.1 可视化分类结果

我们可以通过绘制分类边界直观展示模型效果。

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

# 绘制分类边界
def plot_decision_boundary(X, y, model):
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1  # 确定横轴范围
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1  # 确定纵轴范围
    
    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),  # 生成网格点
                         np.arange(y_min, y_max, 0.01))
    
    grid = np.c_[xx.ravel(), yy.ravel()]  # 将网格点展开成二维数组
    grid_tensor = torch.tensor(grid, dtype=torch.float32)  # 转换为 PyTorch 张量
    probs = model(grid_tensor).detach().numpy().reshape(xx.shape)  # 获取模型预测概率,并重塑为网格形状
    
    plt.contourf(xx, yy, probs, alpha=0.8, cmap=plt.cm.Spectral)  # 绘制概率等高线
    plt.scatter(X[:, 0], X[:, 1], c=y, edgecolor='k', cmap=plt.cm.Spectral)  # 绘制样本点
    plt.show()  # 显示图像

plot_decision_boundary(X_test.numpy(), y_test.numpy().flatten(), model)  # 调用绘图函数

2.5 示例输出

lua 复制代码
Epoch [20/200], Loss: 0.5399
Epoch [40/200], Loss: 0.5289
Epoch [60/200], Loss: 0.5187
Epoch [80/200], Loss: 0.5094
Epoch [100/200], Loss: 0.5009
Epoch [120/200], Loss: 0.4930
Epoch [140/200], Loss: 0.4857
Epoch [160/200], Loss: 0.4789
Epoch [180/200], Loss: 0.4726
Epoch [200/200], Loss: 0.4668
Accuracy: 0.8700

这幅图展示了逻辑回归模型在二分类任务中的分类结果及分类边界:

  1. 分类边界

    • 背景色代表了模型对数据点分类的概率分布。
    • 边界区域颜色的过渡体现了模型预测为某一类别的概率变化。颜色越深,模型对该类别的分类信心越高。
    • 分类边界(颜色变化最显著的区域)是模型划分两类数据的核心区域,对应于逻辑回归模型中的决策边界。
  2. 数据分布

    • 红色和蓝色的散点分别表示两个类别的样本数据。
    • 大多数样本在其对应类别的区域中分布良好,说明模型的分类能力较强。
    • 边界附近的点可能具有一定的不确定性,模型对这些点的分类可能不够准确。
  3. 分类效果

    • 模型成功地将两个类别的样本通过一条近似线性的边界进行分割,符合逻辑回归模型的线性分类特性。
    • 对于分布较为复杂的数据(如蓝点延伸到红色区域),模型的表现受限于逻辑回归的线性假设。

三、常见问题与优化

在使用 PyTorch 实现逻辑回归的过程中,可能会遇到一些问题,如模型不收敛、过拟合或性能不足。以下将详细分析常见问题的原因,并提供优化建议和实用技巧。

3.1 常见问题

3.1.1 训练不收敛

  • 问题现象:模型的损失值在训练过程中没有明显下降。
  • 可能原因
    1. 学习率过大或过小,导致梯度更新无法有效优化损失函数。
    2. 数据没有经过标准化,导致特征值范围不一致,模型难以学习到有效的参数。
    3. 模型初始化权重不合理,可能会导致梯度爆炸或梯度消失。
  • 解决方案
    1. 调整学习率(建议尝试不同量级的学习率,例如 0.1, 0.01, 0.001)。
    2. 在训练前对数据进行标准化处理,如使用 StandardScaler 将数据缩放到零均值和单位方差。
    3. 使用 PyTorch 默认的权重初始化方式,或显式指定权重初始化(例如 Xavier 初始化)。

3.1.2 模型过拟合

  • 问题现象:在训练集上表现良好,但在测试集上的性能明显下降。
  • 可能原因
    1. 训练集样本不足或数据分布单一。
    2. 模型复杂度过高,拟合了数据中的噪声。
  • 解决方案
    1. 使用更多的训练数据,或通过数据增强(Data Augmentation)来扩充数据集。
    2. 加入正则化项,例如 L2 正则化,可以通过优化器中的 weight_decay 参数实现。
    3. 使用交叉验证评估模型的泛化能力,避免过度依赖单一测试集。

3.1.3 测试精度较低

  • 问题现象:训练过程正常,但模型在测试集上的分类精度不足。
  • 可能原因
    1. 训练数据与测试数据分布差异较大(即数据集偏移问题)。
    2. 特征选择不足或数据特征中存在噪声。
    3. 逻辑回归模型的能力不足以拟合复杂数据分布。
  • 解决方案
    1. 检查训练集与测试集的数据分布,确保两者的特征范围一致。
    2. 尝试使用特征工程(如特征筛选、特征组合)提取更有效的特征。
    3. 如果问题较复杂,可以尝试更强大的模型(如神经网络)代替逻辑回归。

3.2 优化技巧

为了进一步提升逻辑回归模型的性能,可以采用以下优化方法:

3.2.1 学习率调整

学习率是优化模型的关键参数。可以尝试以下方法:

  1. 学习率衰减 :随着训练的进行逐步减小学习率,提高模型的收敛性能。例如:

    python 复制代码
    scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)

    上述代码表示每 10 个 epoch 将学习率衰减为原来的 0.1 倍。

  2. 动态调整 :使用 ReduceLROnPlateau 动态调整学习率,当损失不再下降时降低学习率。

    python 复制代码
    scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=5, factor=0.1)

3.2.2 正则化

在逻辑回归中,L2 正则化(即权重衰减)是最常见的防止过拟合的手段。可以在定义优化器时设置 weight_decay 参数,例如:

python 复制代码
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, weight_decay=0.01)  # 添加 L2 正则化

正则化可以限制模型参数的大小,避免过拟合。


3.2.3 批量训练

通过批量训练(Mini-batch Training),可以在保持训练效率的同时减小训练波动,尤其适用于大规模数据集。

python 复制代码
from torch.utils.data import DataLoader, TensorDataset

# 创建数据集和 DataLoader
dataset = TensorDataset(X_train, y_train)
data_loader = DataLoader(dataset, batch_size=32, shuffle=True)  # 每次训练 32 个样本

# 批量训练
for epoch in range(epochs):
    for batch_X, batch_y in data_loader:
        outputs = model(batch_X)
        loss = criterion(outputs, batch_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

批量训练有助于平滑损失下降曲线,提高训练效率。


3.2.4 使用更复杂的特征

逻辑回归本质是线性模型,对于非线性问题的拟合能力有限。因此,可以尝试以下方法增强模型的表达能力:

  1. 特征多项式扩展 :引入二次或更高次特征,例如:

    python 复制代码
    from sklearn.preprocessing import PolynomialFeatures
    poly = PolynomialFeatures(degree=2)
    X_train_poly = poly.fit_transform(X_train)
  2. 组合特征:通过构造新特征来捕捉变量间的非线性关系。


3.2.5 增加模型复杂度

如果逻辑回归无法胜任任务,可以尝试使用简单的神经网络,例如多层感知机(MLP):

python 复制代码
class MLP(nn.Module):
    def __init__(self, input_dim):
        super(MLP, self).__init__()
        self.fc1 = nn.Linear(input_dim, 32)  # 第一层
        self.relu = nn.ReLU()  # 激活函数
        self.fc2 = nn.Linear(32, 1)  # 输出层
        self.sigmoid = nn.Sigmoid()  # 输出概率

    def forward(self, x):
        x = self.relu(self.fc1(x))
        x = self.sigmoid(self.fc2(x))
        return x

四、总结

本文通过使用 PyTorch 实现逻辑回归模型,完成了以下内容:

  • 构建数据集并设计数据加载器 :通过 make_classification 生成二分类数据集,并使用 DataLoader 实现小批量训练;
  • 使用 nn.Linear 定义逻辑回归假设函数 :通过 nn.Linear 实现逻辑回归模型的核心线性变换;
  • 使用 nn.BCELoss 设计二分类交叉熵损失函数:确保分类问题的损失函数适用于概率输出;
  • 使用 optim.SGD 并结合正则化优化模型 :通过随机梯度下降(SGD)优化器结合 L2 正则化(weight_decay)防止过拟合;
  • 动态调整学习率并提升模型收敛效率:引入学习率衰减策略,随着训练的进行逐步降低学习率;
  • 训练模型并可视化分类边界:输出训练过程中的损失变化,最终绘制模型的分类边界以直观展示分类效果。

4.1 完整代码

python 复制代码
import torch
import torch.nn as nn
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import numpy as np

# 设置 Matplotlib 显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# ====================
# 2.1 数据准备
# ====================

# 生成数据集
X, y = make_classification(
    n_samples=1000,         # 样本数
    n_features=2,           # 总特征数
    n_informative=2,        # 有效特征数
    n_redundant=0,          # 冗余特征数
    n_repeated=0,           # 重复特征数
    n_classes=2,            # 分类类别数
    random_state=42         # 随机种子
)

# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 数据标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 转换为 PyTorch 张量
X_train = torch.tensor(X_train, dtype=torch.float32)  # 转换训练集为 PyTorch 张量
y_train = torch.tensor(y_train, dtype=torch.float32).unsqueeze(1)  # 保证标签维度为 [N, 1]
X_test = torch.tensor(X_test, dtype=torch.float32)  # 转换测试集为 PyTorch 张量
y_test = torch.tensor(y_test, dtype=torch.float32).unsqueeze(1)  # 保证测试集标签维度为 [N, 1]

# ====================
# 2.2 模型构建
# ====================

class LogisticRegression(nn.Module):
    def __init__(self, input_dim):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_dim, 1)  # 定义线性层,用于实现线性变换 WX + b
        self.sigmoid = nn.Sigmoid()  # 定义 Sigmoid 激活函数

    def forward(self, x):
        return self.sigmoid(self.linear(x))  # 前向传播过程,线性变换后通过 Sigmoid 激活

# 初始化模型
input_dim = X_train.shape[1]  # 获取输入特征的维度
model = LogisticRegression(input_dim)  # 实例化逻辑回归模型

# ====================
# 2.3 模型训练
# ====================

# 定义损失函数和优化器
criterion = nn.BCELoss()  # 使用二分类交叉熵损失函数
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)  # 使用随机梯度下降优化器,学习率为 0.01

# 训练模型
epochs = 300  # 训练轮次
for epoch in range(epochs):
    # 前向传播
    outputs = model(X_train)  # 获取模型对训练集的预测结果
    loss = criterion(outputs, y_train)  # 计算损失函数值

    # 反向传播
    optimizer.zero_grad()  # 清除梯度缓存,避免梯度累积
    loss.backward()  # 计算梯度
    optimizer.step()  # 更新模型参数

    # 打印训练信息
    if (epoch+1) % 60 == 0:  # 每 10 个 epoch 打印一次损失
        print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')

# ====================
# 2.4 模型测试
# ====================

# 模型评估
y_pred = model(X_test)  # 获取模型对测试集的预测概率
y_pred_class = (y_pred >= 0.5).float()  # 将概率值转换为二分类标签(0 或 1)

accuracy = (y_pred_class == y_test).sum() / y_test.shape[0]  # 计算分类准确率
print(f'Accuracy: {accuracy:.4f}')  # 打印准确率

# ====================
# 2.4.1 可视化分类结果
# ====================

# 绘制分类边界
def plot_decision_boundary(X, y, model):
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1  # 确定横轴范围
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1  # 确定纵轴范围
    
    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),  # 生成网格点
                         np.arange(y_min, y_max, 0.01))
    
    grid = np.c_[xx.ravel(), yy.ravel()]  # 将网格点展开成二维数组
    grid_tensor = torch.tensor(grid, dtype=torch.float32)  # 转换为 PyTorch 张量
    probs = model(grid_tensor).detach().numpy().reshape(xx.shape)  # 获取模型预测概率,并重塑为网格形状
    
    plt.contourf(xx, yy, probs, alpha=0.8, cmap=plt.cm.Spectral)  # 绘制概率等高线
    plt.scatter(X[:, 0], X[:, 1], c=y, edgecolor='k', cmap=plt.cm.Spectral)  # 绘制样本点
    plt.xlabel("特征 1")  # 设置 X 轴标签
    plt.ylabel("特征 2")  # 设置 Y 轴标签
    plt.title("逻辑回归分类边界")  # 设置标题
    plt.show()  # 显示图像

plot_decision_boundary(X_test.numpy(), y_test.numpy().flatten(), model)  # 调用绘图函数

4.2 优化后代码

  • 批量训练:使用 DataLoader 实现小批量训练,提高训练效率。
  • 动态学习率:设置学习率衰减策略(每 50 个 epoch 学习率减半)。
  • 正则化:在优化器中加入 L2 正则化(weight_decay 参数)。
  • 训练日志优化:每 20 个 epoch 输出损失和当前学习率,便于跟踪训练进度。

4.2.1 完整代码

python 复制代码
import torch
import torch.nn as nn
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from torch.utils.data import DataLoader, TensorDataset
import matplotlib.pyplot as plt
import numpy as np

# 设置 Matplotlib 显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

# ====================
# 2.1 数据准备
# ====================

# 生成数据集
X, y = make_classification(
    n_samples=1000,         # 样本数
    n_features=2,           # 总特征数
    n_informative=2,        # 有效特征数
    n_redundant=0,          # 冗余特征数
    n_repeated=0,           # 重复特征数
    n_classes=2,            # 分类类别数
    random_state=42         # 随机种子
)

# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 数据标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 转换为 PyTorch 张量
X_train = torch.tensor(X_train, dtype=torch.float32)  # 转换训练集为 PyTorch 张量
y_train = torch.tensor(y_train, dtype=torch.float32).unsqueeze(1)  # 保证标签维度为 [N, 1]
X_test = torch.tensor(X_test, dtype=torch.float32)  # 转换测试集为 PyTorch 张量
y_test = torch.tensor(y_test, dtype=torch.float32).unsqueeze(1)  # 保证测试集标签维度为 [N, 1]

# 创建 DataLoader
train_dataset = TensorDataset(X_train, y_train)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)  # 批量大小为 32

# ====================
# 2.2 模型构建
# ====================

class LogisticRegression(nn.Module):
    def __init__(self, input_dim):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_dim, 1)  # 定义线性层,用于实现线性变换 WX + b
        self.sigmoid = nn.Sigmoid()  # 定义 Sigmoid 激活函数

    def forward(self, x):
        return self.sigmoid(self.linear(x))  # 前向传播过程,线性变换后通过 Sigmoid 激活

# 初始化模型
input_dim = X_train.shape[1]  # 获取输入特征的维度
model = LogisticRegression(input_dim)  # 实例化逻辑回归模型

# ====================
# 2.3 模型训练
# ====================

# 定义损失函数和优化器
criterion = nn.BCELoss()  # 使用二分类交叉熵损失函数
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, weight_decay=0.01)  # 加入 L2 正则化(weight_decay)

# 动态学习率调整
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.5)  # 每 50 个 epoch 学习率减半

# 训练模型
epochs = 200  # 训练轮次
for epoch in range(epochs):
    model.train()  # 设置模型为训练模式
    for batch_X, batch_y in train_loader:
        # 前向传播
        outputs = model(batch_X)  # 获取模型对训练集的预测结果
        loss = criterion(outputs, batch_y)  # 计算损失函数值

        # 反向传播
        optimizer.zero_grad()  # 清除梯度缓存,避免梯度累积
        loss.backward()  # 计算梯度
        optimizer.step()  # 更新模型参数

    scheduler.step()  # 更新学习率

    # 打印训练信息
    if (epoch + 1) % 20 == 0:  # 每 20 个 epoch 打印一次损失
        print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}, Learning Rate: {scheduler.get_last_lr()[0]:.6f}')

# ====================
# 2.4 模型测试
# ====================

# 模型评估
model.eval()  # 设置模型为评估模式
with torch.no_grad():
    y_pred = model(X_test)  # 获取模型对测试集的预测概率
    y_pred_class = (y_pred >= 0.5).float()  # 将概率值转换为二分类标签(0 或 1)

accuracy = (y_pred_class == y_test).sum() / y_test.shape[0]  # 计算分类准确率
print(f'Accuracy: {accuracy:.4f}')  # 打印准确率

# ====================
# 2.4.1 可视化分类结果
# ====================

# 绘制分类边界
def plot_decision_boundary(X, y, model):
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1  # 确定横轴范围
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1  # 确定纵轴范围
    
    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.01),  # 生成网格点
                         np.arange(y_min, y_max, 0.01))
    
    grid = np.c_[xx.ravel(), yy.ravel()]  # 将网格点展开成二维数组
    grid_tensor = torch.tensor(grid, dtype=torch.float32)  # 转换为 PyTorch 张量
    probs = model(grid_tensor).detach().numpy().reshape(xx.shape)  # 获取模型预测概率,并重塑为网格形状
    
    plt.contourf(xx, yy, probs, alpha=0.8, cmap=plt.cm.Spectral)  # 绘制概率等高线
    plt.scatter(X[:, 0], X[:, 1], c=y, edgecolor='k', cmap=plt.cm.Spectral)  # 绘制样本点
    plt.xlabel("特征 1")  # 设置 X 轴标签
    plt.ylabel("特征 2")  # 设置 Y 轴标签
    plt.title("逻辑回归分类边界")  # 设置标题
    plt.show()  # 显示图像

plot_decision_boundary(X_test.numpy(), y_test.numpy().flatten(), model)  # 调用绘图函数

4.2.2 示例输出

lua 复制代码
Epoch [20/200], Loss: 0.4166, Learning Rate: 0.100000
Epoch [40/200], Loss: 0.4401, Learning Rate: 0.100000
Epoch [60/200], Loss: 0.4131, Learning Rate: 0.050000
Epoch [80/200], Loss: 0.3316, Learning Rate: 0.050000
Epoch [100/200], Loss: 0.3692, Learning Rate: 0.025000
Epoch [120/200], Loss: 0.2930, Learning Rate: 0.025000
Epoch [140/200], Loss: 0.3391, Learning Rate: 0.025000
Epoch [160/200], Loss: 0.3489, Learning Rate: 0.012500
Epoch [180/200], Loss: 0.4923, Learning Rate: 0.012500
Epoch [200/200], Loss: 0.3672, Learning Rate: 0.006250
Accuracy: 0.8800
相关推荐
ramsey171 小时前
python_excel列表单元格字符合并、填充、复制操作
python
Ven%2 小时前
如何让后台运行llamafactory-cli webui 即使关掉了ssh远程连接 也在运行
运维·人工智能·chrome·python·ssh·aigc
Jeo_dmy2 小时前
(七)人工智能进阶之人脸识别:从刷脸支付到智能安防的奥秘,小白都可以入手的MTCNN+Arcface网络
人工智能·计算机视觉·人脸识别·猪脸识别
睡觉狂魔er4 小时前
自动驾驶控制与规划——Project 5: Lattice Planner
人工智能·机器学习·自动驾驶
xm一点不soso4 小时前
ROS2+OpenCV综合应用--11. AprilTag标签码跟随
人工智能·opencv·计算机视觉
caron45 小时前
Python--正则表达式
python·正则表达式
云卓SKYDROID5 小时前
无人机+Ai应用场景!
人工智能·无人机·科普·高科技·云卓科技
是十一月末5 小时前
机器学习之过采样和下采样调整不均衡样本的逻辑回归模型
人工智能·python·算法·机器学习·逻辑回归
小禾家的5 小时前
.NET AI 开发人员库 --AI Dev Gallery简单示例--问答机器人
人工智能·c#·.net
生信碱移5 小时前
万字长文:机器学习的数学基础(易读)
大数据·人工智能·深度学习·线性代数·算法·数学建模·数据分析