机器学习2021-HW1
HomeWork1: COVID-19 Cases Prediction (Regression)
kaggle:https://www.kaggle.com/competitions/ml2021spring-hw1/submissions#
初始code:https://colab.research.google.com/github/ga642381/ML2021-Spring/blob/main/HW01/HW01.ipynb
参考:
https://github.com/1am9trash/Hung_Yi_Lee_ML_2021/blob/main/hw/hw1/hw1_code.ipynb
https://github.com/pai4451/ML2021
问题与思路(9.27):
- 首先是python语法不熟悉,看得比较慢
- 一点点看下来,一点点gpt其实还好,慢慢地就学进去了
- 整理一下,多多复习
- 关键函数看不懂,涉及到复杂的python语法以及原理
- 一点点梳理,先理解原理,再去尝试看懂代码,可以手打一下或者抄一下
- 多看几遍,慢慢来
- 整个的流程还是不清晰的,有点困于细节
- 大的流程就是1.写带未知参的function。2.定义loss。3.优化
- 先把原始作业版本的流程搞清楚,再去看优化
- 先搞懂每段代码是做什么,把所有的代码块串接起来,关注重点内容,再去看细节
过程梳理:
- 目标:
- 用DNN解决一个Regression problem
- 了解DNN training tips
- 熟悉PyTorch
- 准备:
- Download Data, Import some packages and utilities
- Preprocess:(包含train,dev,test)
- DataSet
- read csv file
extract features
- split train into train and dev sets
normalize features
- DataLoader
- loads data from DataSet into
batches
- loads data from DataSet into
- DataSet
- Deep Neural Network:
- nn.Module designed for regression
- consists of
2 fully-connected
layer withReLU
activation cal_loss
for calculating loss
- Train/Dev/Test:
- Training
- 设置参数
- 训练循环(epoch)
- 训练模式
- 数据迭代(update)
- 梯度清零
- 数据传输
- 前向传播
- 计算损失(cal_loss)
- 反向传播
更新参数
- 记录损失
验证模型(dev)
- 更新最小损失
- 早停技术
- 增加epoch
- 记录验证损失
- 早停检查
- 结束打印,返回最小损失和损失记录
- Validation
- 评估模式
- 初始化损失为0
- 数据迭代
- 数据传输
禁用梯度计算
- 前向传播
- 计算损失(cal_loss)
- 累积损失
- 计算返回平均损失
- Testing
- 评估模式
- 初始化预测列表
- 数据迭代
- 数据传输
禁用梯度计算
- 前向传播
- 收集预测
- 合并结果为张量
- 返回预测结果
- Training
- Setup Hyper-parameters:
- 设置**
config
**里的超参数
- 设置**
- 实操调用
- Load data and model
- Start training(train()): 传入:tr_set,dev_set,model,config,device
- Testing(test()):传入:tt_set,model,device, 保存结果到一个csv文件中
重点代码理解:
1.extract features:
1 |
|
2.normalize features:减去均值,除以标准差,得到均值为0,标准差为1的数据集
1 |
|
3.批量数据加载器:调用之前写好的COVID19Dataset,对训练数据进行shuffle并返回批量数据
1 |
|
4.DNN:NeuralNet,设置神经网络层数和激活函数,以及在cal_loss里添加正则化
1 |
|
- nn.Sequential是一个容器,按顺序组合多个神经网络层
- nn.Linear(input_dim, 64)是一个全连接层,针对输入,输出64个特征
- nn.ReLU(),使用激活函数ReLU,增加模型的非线性,增加模型的表达能力
- nn.Linear(64, 1),针对64维的输入,输出最终的结果,一个标量
5.cal_loss以及正则化:
1 |
|
- 这里采取了RMSE作为loss function
- L1正则化就是计算参数绝对值的和,L2正则化就是计算参数平方的和
- 返回loss+正则化结果*超参数
6.设置超参数:
1 |
|
- ‘optimizer’: ‘SGD’是随机梯度下降优化算法
- momentum是考虑之前所有g的加权和,在梯度方向上积累历史信息,加快在平坦区域的收敛速度,减缓在梯度方向变化剧烈的收敛速度2
- early_stop:表示当dev_mse连续很久没有更新,就提前停止退出
分析和改善:
记录:
idx | version | valid | public | private | desc |
---|---|---|---|---|---|
1 | 什么都没增加,最原始的代码 | 0.7590 | 1.35281 | 1.43395 | 运行一遍,跑通所有代码 |
2 | 最完整的版本 | 0.9296 | 0.87971 | 0.89165 | 运行了一下完整的参考代码 |
3 | 增加强相关度的features筛选,增加了正则化,损失函数用RMSE计算 | 0.9138 | 1.02623 | 1.04953 | 在1的基础上只修改了features选址部分,增加了loss计算时的l1正则化,损失函数从MSE到RMSE |
4 | 增加强相关度的features筛选,增加了正则化,损失函数用MSE计算 | 0.8360 | 1.00645 | 1.04458 | 在3的基础上把RMSE改为MSE |
5 | 增加强相关度的features筛选,增加了正则化(参数修改为0.001),损失函数用MSE计算 | 1.0079 | 0.96859 | 1.00816 | 在4的基础上修改了L1正则化的强度参数,从0.0001到0.001 |
6 | 增加了epoch的上限 | 0.9229 | 0.95927 | 1.01704 | 在5的基础上增大了epoch上限为20000 |
7 | 增加了layer层数 | 0.9538 | 1.09354 | 1.17069 | 在6的基础上增加了一层全连接层。有点过拟合了。 |
8 | ReLU→Sigmoid | 0.9914 | 2.03473 | 2.05528 | 在6的基础上修改了激活函数——过拟合很严重 |
9 | 重新归一化和划分数据集 | 0.9354 | 1.01068 | 1.06830 | 在6的基础上进行了归一化和划分数据集的修改 |
TODO:
- 歸一化 ✔
- 原本範例code中是不同的dataset分別使用自己的mean跟std做歸一,這是不合理的,應該使用全部資料的mean跟data做歸一,才不會有太大的偏差
- Train跟Valid dataset切分✔
- 改為隨機切分,保證資料分布相同
- 由於資料集太小,建議多切幾次避免將異常值劃分到valid(k-fold應該是個比較好的做法)
- 修改了归一化和切分,并没有好的效果
- DNN architecture (layers? dimension? activation function?)✔
- 尝试增加了一层layer,发现dev上的loss大幅增加
- 将ReLU改为Sigmoid发现overfitting很严重
- Training (mini-batch? optimizer? learning rate?)✔
- 降低了learning rate,有比较好的效果,也方便观察
- L1 regularization✔
- There are some mistakes in the sample code, can you find them?
Hight light(Training tips):
1、在训练集上效果变差,在测试集上效果可能还是会变好
对比版本1和版本3发现了
一个有意思的现象
:
- 版本1在训练集和验证集上效果都比较好,但是在测试集上效果差
- 而增加了强相关度的features筛选,增加了正则化的版本3却在训练集和验证集上效果都相对比较差,但是在测试集上效果相对更好
原因:
过拟合与泛化能力
:
- 版本1: 由于其在训练集和验证集上表现较好,可能存在过拟合。模型过于复杂或参数过多,导致它很好地记住了训练数据,但在测试集上泛化能力较差。
- 版本3: 增加正则化后,模型的复杂度降低,更不容易过拟合。这可能导致训练和验证集的表现下降,但在测试集上提高了泛化能力,表现更好。
强相关度特征筛选
:
- 增加强相关特征可以帮助模型捕捉到数据的主要模式。这种特征选择可能提高了模型在未见数据(测试集)上的表现,尽管它在训练集上的拟合不如基础版本。
正则化的作用
:
- 正则化可以限制模型的复杂度,减少对训练数据噪声的敏感性。这样,即使在训练集上的损失相对较高,模型在面对新的数据时(如测试集)可能表现得更好。
损失函数的变化
:
- 从均方误差(MSE)改为均方根误差(RMSE)并不会改变模型的拟合过程,但 RMSE 在一定程度上会更加关注较大的误差。虽然这可能导致模型在训练和验证集上的表现不如基础版本,但有助于在测试集上提高表现,尤其是当测试集具有不同的分布时
总结:优化手段都有点降低模型的复杂度,防止过拟合,增强的泛化,所以会有在训练集和验证集上效果一般,但是在测试集上效果很好的现象,这是很正常的。
2、RMSE→MSE,在dev上测试提前结束了
在版本3的基础上想着loss在验证集上偏大可能有也因为loss的计算方法不一样,于是把损失函数从RMSE变为MSE,但是发生了一个有意思的现象
- 在dev上运行时,loss还很大,训练就停止了,触发了早停机制
原因:
优化算法的敏感性
:
- MSE 对较大误差更敏感,导致损失更新不如 RMSE 稳定,从而更容易达到早停的条件。
正则化影响
:
- 如果你在 MSE 损失中加入了正则化项,模型可能会更快地达到损失的阈值,从而提前结束训练。
数据集问题
:
- 数据集中可能存在噪声或不一致性,导致模型在训练时难以收敛,尤其是在使用 MSE 时。
总结:
- 设置的早停条件基于验证集损失在一定轮次内未改善,MSE 的波动可能导致模型在训练过程中的某个时刻没有明显改善,进而提前结束训练。
解决:
- 降低学习率:从0.001到0.0001,可以帮助平滑更新过程,减少损失的波动,最终训练出了不错的数据。
3、修改正则化L1的超参数,模型性能真的有提高
- 发现版本4在dev上loss比较小,而在public的loss变大了不少。猜测模型有一点点过拟合的倾向,于是增大了L1的超参数,从0.0001到0.001,发现loss在dev上增加了一点,但是在public和test上均有下降
- 原因:
- 该超参数为正则化强度
- 较小的值意味着正则化对损失的影响较小,可能导致过拟合,尤其是在训练数据较小或噪声较多的情况下。
- 较大的值: 增加该值将增强正则化的效果,使模型更简单、更平滑。这可能改善模型的泛化能力,但也可能导致欠拟合,因为模型可能无法捕捉到数据中的重要特征。
- 补充:如何调整这个正则化强度
- 可以通过交叉验证等方法尝试不同的正则化强度,观察对训练、验证和测试集性能的影响,找到最适合你模型的超参数。
- 使用网格搜索或随机搜索: 帮助系统地寻找最佳的正则化强度。
4、增加layer训练时才发现之前的几次训练因为epoch上限的原因都及时停止了
- 分析:
- 把epoch上限从3000提升到了20000,之前的模型效果在public上有变好,在private上略变差一点
- 增加了layer后,public的结果明显比dev上损失要高,猜测可能存在一些过拟合的风险
总结:
- 通过这次作业,对regression模型训练的实际操作流程有了更加深刻的认识
- 通过多次的反复调整模型,习得了一些training tip,如何判断是否是overfitting,进行optimize
- 强相关性features的选取
- 正则化防止模型过于复杂
- 损失函数MSE和RMSE
- learning rate的调整可以让模型走得更加平滑,减少损失波动(optimization)
- 所有数据统计归一化和train,dev数据集随机切分(效果不明显)、
- 修改DNN(layer,dimension,activation function)
- 待进步:
- 整个调优的过程还是有点混乱,想到什么做什么,逻辑可以更加清晰,逐步地进行一个优化是一个比较好的过程
- 应该把train_loss也进行输出,比较train和dev来初步判断是否是overfitting,而不是通过dev和public,private进行比较