1. 项目概述与背景
这个深度学习回归项目源自李宏毅教授2021年春季课程,目标是基于前两天的新冠感染数据预测第三天的感染人数。作为一个经典的时序预测案例,它完美展示了如何将现实世界的数据科学问题转化为可操作的深度学习任务。
数据集包含两个CSV文件:
- 训练集(covid.train.csv):2701×94矩阵,最后一列为目标值(第三天感染人数)
- 测试集(covid.test.csv):2701×93矩阵,需要我们预测的正是缺失的最后一列
技术栈选择PyTorch框架,这是目前学术界和工业界最主流的深度学习工具之一。项目完整实现了从数据预处理、模型构建到训练评估的全流程,特别适合作为深度学习入门的第一个实战项目。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据预处理深度解析
2.1 数据集特征工程
原始数据需要经过几个关键处理步骤:
-
索引去除:删除第一行(表头)和第一列(序号),这些与预测无关
-
标准化处理:对93个特征列进行Z-score标准化
python复制self.X = (X - X.mean(dim=0, keepdim=True)) / X.std(dim=0, keepdim=True)这种处理能加速模型收敛,避免某些特征因量纲差异主导训练过程
-
验证集划分:采用"逢五取一"策略,20%数据用于验证
python复制indices = [i for i in range(len(csv_data)) if i % 5 == 0] # 验证集
经验提示:验证集的划分策略直接影响模型评估效果。本项目采用简单随机抽样,但对于时间序列数据,更严谨的做法是按时间划分,防止未来信息泄露。
2.2 Dataset类实现技巧
自定义CoivdDataset继承PyTorch的Dataset类,需要实现三个核心方法:
__init__:初始化时完成数据加载和预处理__getitem__:支持索引访问,返回单个样本__len__:返回数据集大小
关键实现细节:
python复制def __getitem__(self, item):
if self.mode != "test":
return self.X[item].float(), self.Y[item].float() # 训练/验证模式返回(X,Y)
else:
return self.X[item].float() # 测试模式只返回X
3. 模型架构设计与实现
3.1 全连接网络结构
项目采用经典的两层全连接网络:
code复制输入层(93维) → FC(128) → ReLU → FC(1) → 输出
代码实现要点:
python复制class Mymodel(nn.Module):
def __init__(self, inDim):
super().__init__()
self.fc1 = nn.Linear(inDim, 128) # 第一全连接层
self.relu = nn.ReLU() # 非线性激活
self.fc2 = nn.Linear(128, 1) # 输出层
def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x.squeeze(1) if len(x.size()) > 1 else x
3.2 关键设计考量
- 输入输出维度:输入93维对应前两天的特征,输出1维是预测值
- 激活函数选择:ReLU相比Sigmoid能有效缓解梯度消失问题
- 输出处理:
squeeze(1)确保输出维度与标签一致
实战建议:对于初学者,建议先用这种简单结构验证流程,后续可以尝试:
- 增加网络深度
- 使用BatchNorm层
- 尝试其他激活函数(如LeakyReLU)
4. 训练优化全流程
4.1 损失函数与正则化
自定义MSE损失函数加入L2正则化:
python复制def L_MSELoss(pred, target, model):
mse_loss = nn.MSELoss()
reg_loss = sum(param.pow(2).sum() for param in model.parameters())
return mse_loss(pred, target) + 0.00075 * reg_loss
正则化系数0.00075需要根据验证集效果调整:
- 太大导致欠拟合
- 太小无法抑制过拟合
4.2 优化器配置
使用带动量的SGD优化器:
python复制optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
参数选择经验:
- 学习率(lr):从1e-3开始尝试,每隔10epoch可衰减
- 动量(momentum):0.9是常用值,帮助逃离局部最优
4.3 训练循环实现
完整训练流程包含几个关键环节:
python复制for epoch in range(epochs):
model.train() # 训练模式
for x, y in train_loader:
optimizer.zero_grad()
pred = model(x)
loss = loss_fn(pred, y)
loss.backward()
optimizer.step()
model.eval() # 评估模式
with torch.no_grad():
# 验证集评估...
避坑指南:务必区分train()和eval()模式,这会影响Dropout、BatchNorm等层的表现。验证时忘记设置eval()会导致结果不稳定。
5. 模型评估与结果分析
5.1 训练监控策略
项目采用双损失曲线监控:
python复制plt.plot(plt_train_loss, label='train')
plt.plot(plt_val_loss, label='val')
plt.legend()
健康训练的特征:
- 训练损失稳步下降
- 验证损失同步下降后趋于平稳
- 两者最终差距不大
5.2 模型保存与加载
最优模型保存机制:
python复制if val_loss < min_val_loss:
min_val_loss = val_loss
torch.save(model, 'best_model.pth')
加载测试:
python复制model = torch.load('best_model.pth').to(device)
5.3 结果输出规范
测试结果需按指定格式保存:
csv复制id,tested_positive
0,56.3
1,48.7
...
6. 性能优化进阶技巧
6.1 超参数调优策略
-
网格搜索法:系统遍历参数组合
python复制for lr in [0.1, 0.01, 0.001]: for bs in [16, 32, 64]: # 训练评估... -
学习率调度:动态调整学习率
python复制scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
6.2 模型结构改进
- 深度扩展:增加隐藏层数量
- 残差连接:缓解深层网络梯度消失
- 注意力机制:增强重要特征权重
6.3 数据增强技巧
对于时序数据可以:
- 滑动窗口生成更多样本
- 添加随机噪声增强鲁棒性
- 采用时间序列特有的变换方法
7. 常见问题排查指南
7.1 梯度异常问题
现象:Loss出现NaN或剧烈波动
解决方案:
- 检查数据标准化
- 添加梯度裁剪
python复制torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
7.2 过拟合处理
现象:训练损失持续下降但验证损失上升
对策:
- 增强L2正则化强度
- 添加Dropout层
- 提前停止训练
7.3 性能瓶颈分析
使用PyTorch Profiler定位耗时操作:
python复制with torch.profiler.profile() as prof:
# 训练代码...
print(prof.key_averages().table())
8. 项目扩展方向
- 多步预测:预测未来多天而非单日数据
- 特征重要性分析:使用SHAP值解读模型
- 集成学习:结合多个模型的预测结果
- 在线学习:数据流式更新模型
这个项目虽然基于特定数据集,但其技术框架可以迁移到各类回归问题,如:
- 房价预测
- 股票价格分析
- 工业设备剩余寿命预测
在实际部署时,建议使用TorchScript将模型导出为独立于Python的运行格式,便于生产环境集成。
