1. 项目概述
今天我们来聊聊PyTorch框架下实现Logistic Regression解决二分类问题的完整流程。作为深度学习入门系列的第5篇,这次我们将从理论到代码实现,手把手带你完成一个完整的二分类项目。
Logistic Regression虽然名字里带"回归",但它实际上是解决分类问题的经典算法。在二分类场景中,它通过sigmoid函数将线性回归的输出映射到(0,1)区间,可以理解为样本属于正类的概率。相比简单的线性回归,Logistic Regression更适合处理分类任务。
提示:即使你之前学过机器学习中的Logistic Regression,PyTorch的实现方式也有其独特之处,特别是在自动求导和GPU加速方面。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心原理与模型设计
2.1 Logistic Regression数学原理
Logistic Regression的核心是sigmoid函数:
σ(z) = 1 / (1 + e^(-z))
其中z = w^T x + b,w是权重向量,b是偏置项。这个函数将任意实数映射到(0,1)区间,输出可以解释为样本属于正类的概率。
损失函数采用交叉熵损失(Binary Cross Entropy):
L(y, ŷ) = -[y log(ŷ) + (1-y)log(1-ŷ)]
这个损失函数在y=1时,-log(ŷ)惩罚低概率预测;在y=0时,-log(1-ŷ)惩罚高概率预测。
2.2 PyTorch实现要点
在PyTorch中实现Logistic Regression需要注意几个关键点:
- 数据准备:需要将数据转换为PyTorch张量
- 模型定义:继承nn.Module类
- 损失函数:使用BCELoss
- 优化器:通常选择SGD或Adam
- 训练循环:前向传播、计算损失、反向传播、参数更新
3. 完整实现步骤
3.1 环境准备与数据加载
首先确保安装了PyTorch:
bash复制pip install torch torchvision
我们使用一个简单的二分类数据集进行演示:
python复制import torch
import torch.nn as nn
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
# 生成模拟数据
X, y = make_classification(n_samples=1000, n_features=10, 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)
# 转换为PyTorch张量
X_train = torch.FloatTensor(X_train)
y_train = torch.FloatTensor(y_train).reshape(-1, 1)
X_test = torch.FloatTensor(X_test)
y_test = torch.FloatTensor(y_test).reshape(-1, 1)
3.2 模型定义
定义Logistic Regression模型:
python复制class LogisticRegression(nn.Module):
def __init__(self, input_dim):
super(LogisticRegression, self).__init__()
self.linear = nn.Linear(input_dim, 1)
def forward(self, x):
return torch.sigmoid(self.linear(x))
3.3 训练过程
完整的训练代码如下:
python复制# 初始化模型
model = LogisticRegression(X_train.shape[1])
# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
# 训练循环
epochs = 1000
for epoch in range(epochs):
# 前向传播
outputs = model(X_train)
loss = criterion(outputs, y_train)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch+1) % 100 == 0:
print(f'Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}')
3.4 模型评估
训练完成后评估模型性能:
python复制with torch.no_grad():
y_pred = model(X_test)
y_pred_class = y_pred.round()
accuracy = (y_pred_class == y_test).float().mean()
print(f'Test Accuracy: {accuracy.item()*100:.2f}%')
4. 关键问题与优化技巧
4.1 常见问题排查
-
梯度消失问题:如果学习率设置不当,可能导致训练停滞。可以尝试调整学习率或使用自适应优化器如Adam。
-
数据不平衡:如果正负样本比例悬殊,可以考虑:
- 使用class_weight参数
- 采用过采样/欠采样技术
- 使用Focal Loss替代BCELoss
-
数值不稳定:sigmoid函数在极端值时可能导致数值问题,可以:
- 在BCELoss中使用logits参数
- 添加小的epsilon防止log(0)
4.2 性能优化技巧
- 批量训练:使用DataLoader实现批量训练,提升训练效率:
python复制from torch.utils.data import TensorDataset, DataLoader
dataset = TensorDataset(X_train, y_train)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
- GPU加速:如果有GPU设备,可以将模型和数据转移到GPU:
python复制device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
X_train, y_train = X_train.to(device), y_train.to(device)
- 学习率调度:使用学习率调度器动态调整学习率:
python复制scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=100, gamma=0.1)
5. 进阶扩展
5.1 添加正则化
为了防止过拟合,可以添加L2正则化:
python复制optimizer = torch.optim.SGD(model.parameters(), lr=0.01, weight_decay=0.01)
5.2 自定义损失函数
如果需要实现特殊的需求,可以自定义损失函数:
python复制def custom_loss(output, target):
bce_loss = nn.BCELoss()(output, target)
# 添加自定义正则化项
l2_reg = torch.tensor(0.)
for param in model.parameters():
l2_reg += torch.norm(param)
return bce_loss + 0.01 * l2_reg
5.3 模型保存与加载
训练好的模型可以保存供后续使用:
python复制# 保存
torch.save(model.state_dict(), 'logistic_regression.pth')
# 加载
model = LogisticRegression(X_train.shape[1])
model.load_state_dict(torch.load('logistic_regression.pth'))
model.eval()
在实际项目中,我发现合理的数据预处理和特征工程往往比模型本身的选择更重要。对于Logistic Regression这种线性模型,确保特征间没有高度相关性、进行适当的标准化处理,能显著提升模型性能。另外,学习率的选择也很关键,太大容易震荡,太小收敛慢,建议先用小批量数据测试不同学习率的效果。
