1. 逻辑回归与交叉熵损失函数基础

逻辑回归作为机器学习中最经典的分类算法之一,其核心思想是通过线性变换加非线性映射将输入特征转换为概率输出。在PyTorch框架下实现时,理解其数学本质对正确编码至关重要。

1.1 逻辑回归的数学表达

逻辑回归模型可以表示为:

y_pred = sigmoid(W^T * X + b)

其中sigmoid函数将线性输出压缩到(0,1)区间,形成概率预测。这个看似简单的公式背后有几个关键点需要注意:

  • 权重矩阵W的维度是(num_features, num_classes),对于二分类问题num_classes=1
  • 输入特征X需要包含偏置项或在forward()中单独处理bias
  • sigmoid在极端值区域会出现梯度消失,影响训练稳定性

1.2 交叉熵损失的本质

交叉熵损失函数衡量的是预测概率分布与真实分布的差异。对于二分类问题,其数学形式为:

loss = -(y * log(y_pred) + (1-y) * log(1-y_pred))

这个损失函数有几个重要特性:

  1. 当预测值接近真实标签时,loss趋近于0
  2. 对错误预测的惩罚呈对数增长
  3. 与MSE相比,对分类任务更敏感

实际编码时需要注意:PyTorch的BCELoss已经内置了对数运算,不要在输入前手动做log处理

2. PyTorch实现方案设计

2.1 模型架构设计要点

一个完整的逻辑回归实现需要考虑以下组件:

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

关键设计选择:

  1. 输出层不使用激活函数(BCELoss内部处理)
  2. 确保输入数据已经标准化(特别是数值型特征)
  3. 初始化权重采用Xavier初始化

2.2 数据准备最佳实践

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

# 转换为PyTorch张量
train_data = TensorDataset(torch.FloatTensor(X_train), 
                          torch.FloatTensor(y_train))
train_loader = DataLoader(train_data, batch_size=64, shuffle=True)

数据处理中的常见陷阱:

  • 在完整数据集上做标准化(应该只在训练集fit)
  • 忽略类别型特征的编码处理
  • 验证集数据泄露

3. 训练过程实现细节

3.1 训练循环标准实现

model = LogisticRegression(input_dim=8)
criterion = nn.BCELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

for epoch in range(100):
    for inputs, labels in train_loader:
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs.squeeze(), labels)
        loss.backward()
        optimizer.step()

关键参数说明:

  • BCELoss的输入需要是float类型
  • squeeze()处理单输出维度的压缩
  • 学习率设置需要根据数据规模调整

3.2 学习率动态调整策略

scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
    optimizer, 
    mode='min',
    factor=0.1,
    patience=5
)

# 在训练循环中加入
scheduler.step(val_loss)

其他优化技巧:

  • 早停机制(Early Stopping)
  • 梯度裁剪(Gradient Clipping)
  • 不同参数组设置不同学习率

4. 模型评估与调试

4.1 分类任务评估指标

with torch.no_grad():
    y_pred = model(X_test)
    y_pred_class = (y_pred > 0.5).float()
    
    accuracy = (y_pred_class == y_test).float().mean()
    precision = precision_score(y_test, y_pred_class)
    recall = recall_score(y_test, y_pred_class)
    f1 = f1_score(y_test, y_pred_class)

指标选择建议:

  • 不平衡数据关注AUC-ROC
  • 多阈值场景使用PR曲线
  • 业务指标优先于统计指标

4.2 常见问题诊断

  1. 损失不下降:

    • 检查数据预处理
    • 可视化权重分布
    • 尝试更小的学习率
  2. 模型过拟合:

    • 增加L2正则化
    • 添加Dropout层
    • 获取更多训练数据
  3. 预测结果偏差:

    • 检查类别平衡
    • 校准概率输出
    • 调整决策阈值

5. 高级优化技巧

5.1 类别不平衡处理

# 加权交叉熵损失
pos_weight = torch.tensor([10.0])  # 少数类权重
criterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)

其他处理方法:

  • 过采样/欠采样
  • 异常检测思路
  • 代价敏感学习

5.2 分布式训练实现

# 多GPU训练
model = nn.DataParallel(model)
model.to('cuda')

# 混合精度训练
scaler = torch.cuda.amp.GradScaler()
with torch.cuda.amp.autocast():
    outputs = model(inputs)
    loss = criterion(outputs, labels)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()

性能优化方向:

  • 数据加载并行化
  • 梯度累积
  • 模型量化

6. 工程化部署考量

6.1 模型保存与加载

# 保存完整模型
torch.save(model, 'model.pth')

# 保存状态字典(推荐)
torch.save(model.state_dict(), 'model_weights.pth')

# 加载时
model.load_state_dict(torch.load('model_weights.pth'))
model.eval()

生产环境注意事项:

  • ONNX格式导出
  • 版本兼容性检查
  • 输入数据验证

6.2 推理性能优化

# 启用推理模式
@torch.no_grad()
def predict(x):
    return model(x)

# 使用TorchScript
traced_model = torch.jit.trace(model, example_input)
traced_model.save('traced_model.pt')

优化手段:

  • 层融合技术
  • 量化推理
  • 服务化部署

在实际项目中,我发现逻辑回归虽然结构简单,但在特征工程到位的情况下,往往能取得与复杂模型相近的效果。特别是在需要模型可解释性的场景,线性模型的系数可以直接反映特征重要性。一个实用的技巧是在训练完成后,可视化权重绝对值大小来快速识别关键特征。

Logo

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

更多推荐