Task 2
学习 深度学习基础:线性模型自适应学习率(文字+视频)
学习 深度学习基础:分类(文字 + 视频)
跑通 实践任务CNN代码
Task 2.1 自适应学习率
自适应学习率(adaptive learning rate)
如下图所示,训练网络时,随着迭代次数增加,虽然损失(loss)不再下降,但是梯度的范数并没有变得很小,训练“卡住了”,但这种情况常常并不是卡在了上一节学习的临界点(局部最小值或者鞍点),只是单纯的损失无法再下降了。
因为在原始梯度下降中,所有的参数都是设置同样的学习率,但是训练误差表面是不均匀的,某些区域梯度变化非常小,非常平坦;某些区域坡度非常陡峭,梯度变化非常大,这就需要引入自适应学习率为每一个参数定制学习率,平坦坡度小的方向,我们设置大一点的学习率;陡峭坡度大的方向,我们设置较小的学习率,如下图所示。
常见的自适应学习率方法有:
- AdaGrad(Adaptive Gradient):根据梯度大小自动调整学习率,梯度比较大的时候,学习率就减小,梯度比较小的时候,学习率就放大。
- RMSProp(Root Mean Squared propagation):考虑参数学习率随时间改变,引入一个超参数 α ∈ ( 0 , 1 ) \alpha \in (0, 1) α∈(0,1) 用于调整梯度更新时当前梯度的重要性:如果 α \alpha α 设很小趋近于 0,代表新算出来的梯度更重要;如果 α \alpha α 设很大趋近于 1,代表 之前算出来的梯度比较重要。
- Adam(Adaptive moment estimation):理解为 RMSprop + 动量,其使用动量作为参数更新方向,并且能够自适应调整学习率,实践时直接使用Pytorch中预设即可。
注:RMSprop 是Geoffrey Hinton 在 Coursera 上深度学习的课程里面提出,如果要引用,需要引用对应视频:
[1] Tieleman, T., & Hinton, G. (2012). Lecture 6.5-rmsprop: Divide the gradient by a running average of its recent magnitude. COURSERA: Neural networks for machine learning, 4(2), 26-31.
学习率调节(learning rate scheduling)
如上图所示,自适应学习率应用后,另一个可能遇到的问题是:在训练优化到接近终点时,由于之前的梯度累计,步伐可能会变得很大,快走到终点时突然暴走了,这时就需要引入**学习率调度(learning rate scheduling)**来解决问题,最终实现下图的效果。
具体的方法有:
- 学习率衰减(learning rate decay),也称为学习率退火(learning rateannealing):随着参数的不断更新,让学习率衰减,达到慢慢走到终点的效果。
- 预热(warmup):让学习率先变大后变小,至于变到多大、变大的速度、变小的速度是超参数,即类似于不同的阶段手动设定相应的学习率。(RAdam 使用预热的方法来解决 Adam 容易收敛到局部最优解的问题,前期选用比较稳的SGD + Momentum来进行训练,来稳定缩小方差。)
Task 2.2 分类
分类操作
深度学习两种常见问题:
- 回归:输入一个向量 x x x,输出 y ^ \hat{y} y^,我们希望 y ^ \hat{y} y^ 跟某一个标签 y y y 越接近越好, y y y 是要学习的目标。
- 分类:从回归理解,输入 x x x 后,输出 y ^ \hat{y} y^,我们希望它跟正确类别 y y y 越接近越好,这时候类别需要进行编码。
常用类别编码方式如独热编码(one-hot encoding):如果有三个类,标签 y y y 就是一个三维的向量,比如类 1 是 [ 1 , 0 , 0 ] ⊤ [1, 0, 0]\top [1,0,0]⊤,类 2 是 [ 0 , 1 , 0 ] ⊤ [0, 1, 0]\top [0,1,0]⊤,类3 是 [ 0 , 0 , 1 ] ⊤ [0, 0, 1]\top [0,0,1]⊤,用独热向量计算距离的话,类两两之间的距离都是一样的。
实际做分类时,在得到最终输出前会做一个softmax操作,简单理解: y y y 是独热向量,考虑到目标只有 0 跟 1,但 y ^ \hat{y} y^ 有任何值,可以先把它归一化到 0 到 1 之间,这样才能跟标签的计算相似度。
另外,一般有两个类时,可以直接取sigmoid,此时sigmoid和softmax是等价的。
分类损失
分类损失即我们计算 y ^ \hat{y} y^ 与 y y y 的距离 e e e,常见计算方式:
- 均方误差(mean square error, MSE):把
y
y
y 里每一个元素拿出来,计算它们的平方和当作误差:
e = ∑ i ( y i − y ^ i ) 2 e = \sum_i(y_i - \hat{y}_i)^2 e=i∑(yi−y^i)2 - 交叉熵(cross entropy):当
y
^
\hat{y}
y^ 跟
y
y
y 相同时,可以最小化交叉熵的值,此时均方误差也是最小的。最小化交叉熵其实就是最大化似然(maximize likelihood):
e = − ∑ i y i ln y ^ i e = - \sum_i y_i \ln \hat{y}_i e=−i∑yilny^i
分类任务时,交叉熵更常用,有以下原因:
- 交叉熵损失函数直接衡量了两个概率分布之间的差异,能够有效地反映预测分布与真实分布之间的差距。而平方误差衡量的主要是预测值与真实值的直接差异,但对于分类任务中的概率输出,平方误差并不能有效区分预测的好坏。
- 同时交叉熵损失函数的梯度在接近正确分类时仍然较大,这意味着它可以在训练过程中对预测的微小调整更加敏感,帮助模型更快收敛。而平方误差损失在预测接近真实值时,其梯度会变得非常小,导致学习速度减慢。
- 交叉熵损失函数对错误分类的惩罚更为严格,尤其是在模型非常自信地做出错误预测时,损失会变得非常大。而平方误差在这种情况下不会有如此强烈的反应,这可能导致模型在错误类别上持续做出不良预测。
- 在分类任务中,softmax和sigmoid函数常用于输出层,这些函数与交叉熵损失函数在数学上是良好结合的。它们共同作用可以使得损失函数的优化更加有效。平方误差损失则不能很好地利用这些非线性激活函数的特性。
因此,在分类任务中,交叉熵损失函数通常比平方误差损失函数表现得更好,能更有效地引导模型学习出准确的分类边界。
Task 2.3 实践任务:HW3(CNN)卷积神经网络-图像分类
直接本地3080Ti跑了下,教程很简单,跟着操作就行:
准备项目代码
git clone https://www.modelscope.cn/datasets/Datawhale/LeeDL-HW3-CNN.git
项目目录结构:
.
├── hw3_data.zip
├── HW3-ImageClassification.ipynb
└── README.md
代码调整
修改 transform:
train_tfm = transforms.Compose([
# 将图像调整为固定大小(高度和宽度均为128)
transforms.Resize((128, 128)),
# 你可以在这里添加一些图像增强的操作。
transforms.RandomHorizontalFlip(),
transforms.RandomVerticalFlip(),
# ToTensor()应该是所有变换中的最后一个。
transforms.ToTensor(),
])
修改配置:
# 定义训练轮数
n_epochs = 50
# 如果在'patience'轮中没有改进,则提前停止
patience = 10
一键运行代码
分类准确率达到 70.84%
可视化效果: