1. 逻辑回归与PyTorch基础解析

逻辑回归是机器学习中最基础但极其重要的分类算法,尽管名字中带有"回归"二字,但它实际上解决的是二分类问题。在PyTorch框架中实现逻辑回归,不仅能理解深度学习的底层机制,也是掌握更复杂神经网络的基础。

注意:虽然逻辑回归模型结构简单,但它包含了深度学习的所有关键要素 - 前向传播、激活函数、损失计算和参数更新。理解这些对后续学习至关重要。

1.1 逻辑回归的数学本质

逻辑回归的核心是将线性回归的输出通过sigmoid函数映射到(0,1)区间,表示样本属于正类的概率。其数学表达式为:

$$ P(y=1|x) = \sigma(w^Tx + b) = \frac{1}{1+e^{-(w^Tx + b)}} $$

其中$\sigma$就是sigmoid函数,它将任意实数映射到(0,1)区间。这个特性使逻辑回归特别适合处理概率估计问题。

在PyTorch中,sigmoid函数的实现非常直观:

import torch
x = torch.tensor([-1.0, 0.0, 1.0])
sigmoid = torch.nn.Sigmoid()
print(sigmoid(x))  # 输出: tensor([0.2689, 0.5000, 0.7311])

1.2 PyTorch实现逻辑回归的优势

PyTorch的动态计算图和自动微分机制使得逻辑回归的实现变得异常简单:

  1. 自动梯度计算 :无需手动推导梯度公式
  2. 模块化设计 nn.Module 提供了清晰的模型构建方式
  3. GPU加速 :只需简单调用 .to(device) 即可利用GPU加速
  4. 丰富的优化器 :内置SGD、Adam等多种优化算法
# 典型PyTorch训练循环结构
model = LogisticRegression()
criterion = torch.nn.BCELoss()  # 二分类交叉熵损失
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(100):
    # 前向传播
    outputs = model(inputs)
    loss = criterion(outputs, labels)
    
    # 反向传播
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

2. 逻辑回归模型的PyTorch实现

2.1 使用nn.Sequential快速构建

nn.Sequential 是PyTorch提供的容器类,可以像搭积木一样快速构建模型:

model = torch.nn.Sequential(
    torch.nn.Linear(input_dim, 1),  # 线性层
    torch.nn.Sigmoid()             # 激活函数
)

这种方式的优点是:

  • 代码简洁,适合简单模型
  • 自动处理层间数据传递
  • 参数初始化已经内置合理默认值

实际应用中发现:当input_dim较大时,建议手动初始化权重,默认初始化可能导致梯度消失或爆炸。

2.2 自定义模块实现

对于更复杂的场景,继承 nn.Module 创建自定义类更为灵活:

class LogisticRegression(torch.nn.Module):
    def __init__(self, input_dim):
        super().__init__()
        self.linear = torch.nn.Linear(input_dim, 1)
        
    def forward(self, x):
        return torch.sigmoid(self.linear(x))

自定义模块的优势:

  • 可以添加更复杂的逻辑
  • 方便添加自定义方法
  • 更清晰的代码结构
  • 支持保存和加载模型参数

2.3 参数初始化技巧

良好的参数初始化对模型性能至关重要。PyTorch提供了多种初始化方法:

# 手动初始化权重
def weights_init(m):
    if isinstance(m, torch.nn.Linear):
        torch.nn.init.xavier_uniform_(m.weight)
        torch.nn.init.zeros_(m.bias)

model.apply(weights_init)

常见初始化方法对比:

初始化方法 适用场景 特点
Xavier/Glorot sigmoid/tanh 考虑输入输出维度
Kaiming/He ReLU族 针对ReLU特性优化
均匀分布 小型网络 简单但效果一般
正态分布 深度网络 需要小心调参

3. 模型训练与评估

3.1 损失函数选择

二分类问题最常用的损失函数是二元交叉熵(BCE):

criterion = torch.nn.BCELoss()
# 或者带logits的版本(数值更稳定)
criterion = torch.nn.BCEWithLogitsLoss()

选择依据:

  • BCELoss :模型输出已经过sigmoid
  • BCEWithLogitsLoss :模型输出未经过sigmoid

3.2 优化器配置

PyTorch提供了多种优化器,逻辑回归常用:

# 基础SGD
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# Adam通常表现更好
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

优化器选择建议:

  • 小数据集:SGD with momentum
  • 大数据集:Adam/AdamW
  • 需要精细调参:L-BFGS(但内存消耗大)

3.3 训练循环实现

完整的训练循环应包括:

for epoch in range(epochs):
    model.train()
    for batch in train_loader:
        # 前向传播
        outputs = model(batch.inputs)
        loss = criterion(outputs, batch.labels)
        
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    
    # 验证集评估
    model.eval()
    with torch.no_grad():
        val_outputs = model(val_inputs)
        val_loss = criterion(val_outputs, val_labels)

关键技巧:记得在验证时调用 model.eval() torch.no_grad() ,这会关闭dropout和batch norm的train模式,并避免不必要的梯度计算节省内存。

4. 高级技巧与实战经验

4.1 类别不平衡处理

当正负样本比例悬殊时,可以采用:

  1. 加权损失函数:
pos_weight = torch.tensor([10.0])  # 正样本权重
criterion = torch.nn.BCEWithLogitsLoss(pos_weight=pos_weight)
  1. 过采样/欠采样
  2. 修改决策阈值(默认0.5)

4.2 特征工程建议

虽然逻辑回归是线性模型,但可以通过以下方式增强表达能力:

  1. 多项式特征
  2. 交互特征
  3. 分箱处理连续特征
  4. 标准化/归一化
# 特征标准化示例
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

4.3 模型部署优化

生产环境中需要考虑:

  1. 量化减小模型大小:
quantized_model = torch.quantization.quantize_dynamic(
    model, {torch.nn.Linear}, dtype=torch.qint8
)
  1. 导出为TorchScript:
traced_model = torch.jit.trace(model, example_input)
traced_model.save("logreg.pt")
  1. 使用ONNX格式实现跨平台部署

4.4 常见问题排查

  1. 损失不下降

    • 检查学习率(太大或太小)
    • 验证梯度是否正常传播( print(m.weight.grad)
    • 确认输入数据范围合理
  2. 预测结果全为0或1

    • 可能是梯度爆炸,尝试减小学习率
    • 检查特征是否有多重共线性
    • 添加正则化项(L1/L2)
  3. GPU内存不足

    • 减小batch size
    • 使用梯度累积:
    for i, batch in enumerate(data_loader):
        loss = model(batch) / accumulation_steps
        loss.backward()
        if (i+1) % accumulation_steps == 0:
            optimizer.step()
            optimizer.zero_grad()
    

逻辑回归虽然简单,但在许多实际业务场景中仍然是首选模型,特别是当需要模型可解释性时。在PyTorch中实现它,不仅能够理解深度学习的基础,也为后续更复杂模型的构建打下坚实基础。我在实际项目中发现,合理调参的逻辑回归性能常常能媲美复杂的深度学习模型,特别是在中小规模数据集上。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐