Kaggle房价预测实战:我用PyTorch MLP踩过的那些坑(附完整代码与Wandb调参记录)

Kaggle房价预测实战:我用PyTorch MLP踩过的那些坑(附完整代码与Wandb调参记录) Kaggle房价预测实战从数据清洗到模型调优的完整避坑指南第一次接触Kaggle房价预测比赛时我被数据集中那些看似简单却暗藏玄机的特征列弄得焦头烂额。作为沐神《动手学深度学习》课程的实践作业这个项目远没有想象中那么简单——从数据预处理到模型构建几乎每一步都布满了新手容易踩中的陷阱。本文将分享我在复现这个项目时遇到的实际问题与解决方案希望能为同样在复现过程中遇到困难的初学者提供一份实用的排雷手册。1. 数据预处理那些容易被忽视的细节数据清洗是任何机器学习项目的第一步但往往也是最容易被低估的环节。在房价预测项目中我最初天真地认为pandas的read_csv()读入数据后就可以直接开始建模结果很快遇到了第一个障碍。1.1 高基数类别特征的处理当我开始检查数据集中的类别型特征时发现了令人头疼的问题for in_object in all_features.dtypes[all_features.dtypesobject].index: print(in_object.ljust(20), len(all_features[in_object].unique()))输出结果显示某些特征的唯一值数量惊人Heating 2660 Cooling 911 Parking 9913 Elementary School 3568 Appliances included 11290这些高基数(high-cardinality)特征如果直接进行one-hot编码会导致特征维度爆炸。我的第一次尝试就因为这个问题导致特征矩阵从原始的19列膨胀到470列不仅增加了计算负担还容易引发维度灾难。解决方案仅保留基数较低的类别特征如Type、Bedrooms对高基数特征考虑使用目标编码(Target Encoding)或嵌入层(Embedding Layer)删除明显不相关的特征如Address、Summary1.2 数值特征的标准化与对数变换另一个常见陷阱是忽视数值特征的尺度差异。原始数据中有些特征的值范围极大large_vel_cols [Lot, Total interior livable area, Tax assessed value, Annual tax amount, Listed Price, Last Sold Price]对这些特征直接使用原始值会导致模型训练不稳定。我尝试了两种处理方法对数变换对价格类特征取log(1x)压缩尺度Z-score标准化对所有数值特征进行(x-μ)/σ标准化# 对数变换 for c in large_vel_cols: train_data[c] np.log(train_data[c]1) test_data[c] np.log(test_data[c]1) # Z-score标准化 numeric_features all_features.dtypes[all_features.dtypes float64].index all_features[numeric_features] all_features[numeric_features].apply( lambda x: (x - x.mean()) / (x.std()))2. 模型构建MLP架构的设计考量确定了数据处理流程后模型架构的选择同样充满挑战。作为初学者我最初对神经网络层数、激活函数等超参数的选择毫无头绪。2.1 网络深度与宽度我尝试的第一个MLP结构非常简单class MLP(nn.Module): def __init__(self, in_features): super().__init__() self.layer1 nn.Linear(in_features, 256) self.layer2 nn.Linear(256, 64) self.out nn.Linear(64, 1) def forward(self, X): X F.relu(self.layer1(X)) X F.relu(self.layer2(X)) return self.out(X)这个结构看似合理但在实际训练中却出现了梯度爆炸的问题。通过Wandb的监控我发现损失值在某些epoch会突然变为nan。改进方案添加Batch Normalization层稳定训练使用梯度裁剪(Gradient Clipping)尝试更小的初始学习率2.2 激活函数的选择最初我对激活函数的选择没有特别考虑直接使用了ReLU。但在资料后我了解到ReLU计算高效但存在神经元死亡问题LeakyReLU解决了死亡ReLU问题但需要调参Swish自门控特性在深度网络中表现更好最终我选择了LeakyReLU作为折中方案def forward(self, X): X F.leaky_relu(self.layer1(X), negative_slope0.01) X F.leaky_relu(self.layer2(X), negative_slope0.01) return self.out(X)3. 训练过程监控与调参技巧模型训练阶段是最能体现深度学习工程实践的环节也是我踩坑最多的地方。3.1 学习率与优化器配置我的第一次训练尝试使用了以下配置optimizer torch.optim.Adam(net.parameters(), lr0.005, weight_decay0.05)结果训练过程极不稳定损失值波动剧烈。通过Wandb的可视化我逐步调整了以下参数参数初始值调整后效果学习率0.0050.001训练更稳定权重衰减0.050.01防止过拟合批量大小256128内存更友好3.2 使用Wandb进行实验跟踪Wandb成为了我的调参救星。通过简单的集成我可以实时监控训练过程import wandb wandb.init(projectkaggle_predict, config{ learning_rate: lr, weight_decay: weight_decay, batch_size: batch_size, architecture: MLP }) # 在训练循环中 for epoch in range(num_epochs): # ...训练代码... wandb.log({loss: loss.item(), epoch: epoch})这让我能够比较不同超参数组合的效果及时发现训练异常如梯度爆炸保存最佳模型检查点4. 提交与结果分析经过多次调整我的最佳提交在Kaggle上获得了0.28的RMSE分数虽然不及顶级方案但对于第一次尝试来说已经是不错的成绩。4.1 模型集成技巧为了提高最终成绩我尝试了以下几种集成方法检查点平均保存训练过程中多个检查点预测时取平均值多模型融合训练不同结构的MLP组合它们的预测结果Bagging对训练数据进行多次采样训练多个模型# 检查点平均示例 preds [] for epoch in [100, 200, 300, 400]: net.load_state_dict(torch.load(fcheckpoint_{epoch})) preds.append(net(test_features)) final_pred torch.mean(torch.stack(preds), dim0)4.2 特征工程进阶在基础方案之上我还尝试了以下特征工程技巧交互特征将相关特征相乘或相除如价格/面积分箱处理将连续变量离散化为多个区间时间特征从日期中提取周数、季度等信息这些技巧虽然提升了模型性能但也增加了过拟合风险需要谨慎使用。