今天我们来聊聊如何使用PyTorch实现一个简单的逻辑回归模型,解决二分类问题。逻辑回归虽然名字里有"回归"二字,但实际上它是解决分类问题的利器,特别适合处理只有两种可能结果的场景,比如判断邮件是否为垃圾邮件、预测学生考试是否通过等。
这个项目我们会用PyTorch从头构建一个逻辑回归模型,训练它来学习一个简单的分类任务。通过这个实践,你不仅能掌握逻辑回归的核心原理,还能学到PyTorch的基本使用流程,包括数据准备、模型定义、训练过程和结果可视化等关键环节。
在开始之前,我们需要先处理一个常见的技术问题。当你在某些环境下同时使用NumPy和PyTorch时,可能会遇到OpenMP库冲突的问题。这个问题会导致程序崩溃,解决方法很简单:
python复制import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
这行代码告诉系统允许OpenMP库的重复加载,避免了冲突。虽然这不是必须的步骤,但在某些开发环境中(特别是macOS)可能会遇到这个问题,提前设置可以避免后续的麻烦。
接下来,我们需要导入项目所需的Python库:
python复制import torch
import numpy as np
import torch.nn.functional as F
import matplotlib.pyplot as plt
torch:PyTorch深度学习框架的核心numpy:科学计算基础库torch.nn.functional:包含各种神经网络函数(如激活函数)matplotlib.pyplot:用于数据可视化我们使用一个简单的数据集来演示逻辑回归:
python复制x_data = torch.tensor([[1.0], [2.0], [3.0]])
y_data = torch.tensor([[0.0], [0.0], [1.0]])
这里:
x_data是输入特征,表示学习时间(小时)y_data是标签,0表示未通过考试,1表示通过考试这个数据集虽然简单,但足以展示逻辑回归的工作原理。在实际应用中,你通常会处理更大规模、更复杂的数据集。
在PyTorch中,我们通过继承torch.nn.Module类来定义自己的模型:
python复制class LogisticRegressionModel(torch.nn.Module):
def __init__(self):
super(LogisticRegressionModel, self).__init__()
self.linear = torch.nn.Linear(1, 1)
def forward(self, x):
y_pred = F.sigmoid(self.linear(x))
return y_pred
关键点解析:
__init__方法中定义了模型的层结构。这里我们使用一个线性层torch.nn.Linear(1, 1),表示输入和输出都是1维的。forward方法定义了数据如何通过网络。线性层的输出通过sigmoid函数转换为概率值(0到1之间)。创建模型实例非常简单:
python复制model = LogisticRegressionModel()
这个模型现在包含了可训练的参数(权重和偏置),PyTorch会自动管理这些参数。
对于二分类问题,二元交叉熵损失(BCELoss)是最常用的选择:
python复制criterion = torch.nn.BCELoss(size_average=False)
size_average=False表示我们不希望对损失求平均,而是直接使用总和。这在某些情况下能提供更稳定的训练。
我们使用随机梯度下降(SGD)作为优化算法:
python复制optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
model.parameters()告诉优化器需要更新哪些参数lr=0.01设置学习率,这是一个需要根据具体问题调整的超参数训练过程通常包含以下几个步骤:
python复制for epoch in range(1000):
# 前向传播
y_pred = model(x_data)
# 计算损失
loss = criterion(y_pred, y_data)
print(epoch, loss.item())
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
每个epoch的流程:
我们在每个epoch打印损失值,这有助于观察训练过程是否正常。理想情况下,损失应该随着训练逐渐下降。
为了可视化模型的预测结果,我们生成一组测试数据:
python复制x = np.linspace(0, 10, 200)
x_t = torch.Tensor(x).view((200, 1))
y_t = model(x_t)
y = y_t.data.numpy()
python复制plt.plot(x, y)
plt.plot([0, 10], [0.5, 0.5], c='r')
plt.xlabel('Hours')
plt.ylabel('Probability of pass')
plt.grid()
plt.show()
这张图展示了模型对不同学习时间的通过概率预测。红色水平线表示0.5的决策边界,高于这条线的预测会被分类为"通过"。
sigmoid函数将线性输出映射到(0,1)区间,这正好对应概率的取值范围。其数学形式为:
σ(z) = 1 / (1 + e^{-z})
这个函数的特性:
二元交叉熵损失衡量了预测概率分布与真实分布之间的差异。对于单个样本:
L = -[y*log(p) + (1-y)*log(1-p)]
其中:
这个损失函数对错误预测(如预测p接近0而y=1)会给予很大的惩罚。
当输入值很大或很小时,sigmoid函数的梯度会变得非常小(因为曲线变得平缓),这会导致训练困难。解决方案:
学习率太大可能导致震荡或不收敛,太小则训练缓慢。建议:
虽然这个简单例子不需要,但在实际应用中,对输入特征进行标准化(均值0,方差1)通常能提高训练效果:
python复制from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
x_data = scaler.fit_transform(x_data)
除了损失函数,我们还应该关注:
这个基础模型可以进一步优化:
在实际项目中应用逻辑回归时:
逻辑回归虽然简单,但在很多实际问题中表现优异,特别是当数据量不大或特征与目标之间存在近似线性关系时。掌握好这个基础模型,能为学习更复杂的深度学习模型打下坚实基础。