1.自适应学习率
我们在训练的过程中,随着参数的更新,损失不断下降,直到下降卡在一个临界点,我们以前可能会把这个点当作局部最低点或者鞍点。但是,我们会发现有时这个点的梯度并不是很小,那就说明这个点并不是到达了临界点,它其实是这样一种情况:这个点在临界点两侧来回震荡。
对于这个问题,我们第一个想到通过调整学习率来解决,但是经过尝试,当把学习率调整到足够小,虽然解决了在临界点两侧震荡的问题,但是却很难在趋于平缓的低估处通过这么小的"步伐"到达最低点。
所以在梯度下降里面,所有的参数都是设同样的学习率,这显然是不够的,应该要为每一个参数定制化学习率,即自适应学习率(adaptive learning rate),给每一个参数不同的学习率。
1.1AdaGrad(自适应梯度算法)
AdaGrad(Adaptive Gradient)是一种在深度学习中常用的优化算法,它属于梯度下降优化算法的扩展。AdaGrad的主要特点是能够自适应地调整每个参数的学习率。
简单来说,AdaGrad算法会记录每个参数的历史梯度信息,并根据这些信息来调整每个参数的学习率。对于那些在训练过程中更新频繁(即梯度较大)的参数,AdaGrad会给予它们较小的学习率,避免它们更新过快导致模型震荡;而对于那些更新不频繁(即梯度较小)的参数,AdaGrad会给予它们较大的学习率,使它们能够更快地更新。
例如更新一个参数θit的过程:
即:
AdaGrad在处理稀疏数据时特别有效,因为稀疏数据中的很多特征可能只在少数样本中出现,使用统一的学习率很难达到最优的训练效果。但这也导致AdaGrad对于非凸优化问题也可能存在陷入局部最优解的风险。
1.2RMSProp(均方根传播)
在有些更复杂的优化任务中,存在同一个特征同一个方向坡度也不同的情况,考虑到这些非凸优化问题,刚刚的AdaGrad难以胜任,于是有了一个新的方法--RMSprop(Root Mean Squared propagation)
RMSprop 第一步计算θ跟 Adagrad 的方法相同,σ的计算方法发生变化:
RMSProp 通过 改变α ,可以改变 g项 的影响。即可以在不同的坡度调整步伐的大小。
1.3Adam
Adam(Adaptive Moment Estimation)是一种在深度学习中广泛使用的优化算法,它结合了两种不同优化算法的优点:AdaGrad(自适应梯度算法)和RMSProp(均方根传播)。Adam通过计算梯度的一阶矩估计和二阶矩估计来为不同的参数设计独立的自适应学习率。
简单来说,Adam算法在每次迭代中都会更新每个参数的学习率,以适应不同的参数和数据特征。它首先计算梯度(即损失函数对每个参数的偏导数),然后使用这些梯度来更新两个关键的估计值:梯度的一阶矩估计(即梯度的均值)和二阶矩估计(即梯度的未中心化的方差)。接着,Adam使用这两个估计值来调整每个参数的学习率,以便更高效地更新参数。
2.学习率调度
我们通过使用Adam方法后会发现优化效果得到明显的改善,可以逐渐找到临界值,但是我们通常会在等高线图中出现这样的情况:在接近最小值的附件会出现几次梯度误差“爆炸”,即梯度突然增长。出现这种情况的原因是在梯度平滑区,Adam自动逐渐增大学习率,增大到一个数值后步幅超过了临界值使其又开始在两侧震荡,可以简单理解为学习率增大过头了。不过没关系,Adam的方法可以自动缩小学习率,使变化“回到正轨”,直到逼近临界值。
当然,可以通过学习率调度(learning rate scheduling)可以解决这个问题。
学习率调度中最常见的策略是学习率衰减(learning rate decay),也称为学习率退火(learning rateannealing)。该策略通过设置初始学习率、学习率下降的速率以及学习率下降的位置等参数,依据当前训练的step来计算得到当前的学习率。随着step的增加,学习率按照设定的策略进行衰减。
学习率调度中另外一种策略是预热(Warm-up),学习率预热是在训练开始前的一段时间内,逐步将学习率从初始值增加到一个预设的最大值然后再使学习率下降。增长到什么时候,最大值的参数这些都是需要手动调整。
3.分类
3.1分类与回归的关系
之前了解到的回归(Regression)是通过输入一个向量x,然后输出一个数值y,使数值y和目标标签y^越接近越好。
分类(Classification)问题,也是输入一个向量x,然后输出一个数值y,但是分类问题需要让输出的y与类别作比较,如何让数字与类别比较呢,我们可以给类比编号例如类别1、类别2、类别3分别为1、2、3,但是从数字角度我们通常认为1、2、3之间是有不同程度的关联的,1、2之间密切,1、3之间疏远。所以为了更好的区分不同的三类,要采用向量作为类别1、类别2、类别3的标签,这些向量叫独热向量(one-hot vector)。
使用例如上面三个数的向量来表示类别,也就要求输出的y需要有三个数值,把 a1、a2 和 a3 乘上三组不同权重加上三个不同的偏置输出三个数值
3.2带有 softmax 的分类
按照上面的描述,实际分类是输入一个向量x,然后输出一个向量y。但实际做分类的时候,往往会把 yˆ 通过 softmax 函数得到 y′,才去计算 y′ 跟 yˆ 之间的距离。通过 softmax 函数的目的用简单的话来说就是把输出的各种不同数值归一化为0、1,这样就可以和独热向量比较从而完成分类。
但一般有两个类的时候,不使用 softmax,而是直接取 sigmoid。当只有两个类的时候,sigmoid 和 softmax 是等价的。
3.3分类损失
分类损失就是计算出的y′与实际yˆ间的距离,计算这个距离有不同的方法。
1.均方误差(MSE(Mean Square Error)):
2.交叉熵(Cross-entropy):当 yˆ 跟 y′ 相同时,可以最小化交叉熵的值,此时均方误差也是最小的。最小化交叉熵其实就是最大化似然(maximize likelihood)
再实际分类任务中,最常用的就是交叉熵(Cross-entropy),甚至在pytorch中Cross-entropy和softmax是绑在一起使用。
图片分类实践
通过利用10类食物的图片数据训练一个卷积神经网络模型,来对图像进行分类。
图像数据集的每个图像都有统一格式的命名作为标签
使用的CNN网络:
class Classifier(nn.Module):
"""
定义一个图像分类器类,继承自PyTorch的nn.Module。
该分类器包含卷积层和全连接层,用于对图像进行分类。
"""
def __init__(self):
"""
初始化函数,构建卷积神经网络的结构。
包含一系列的卷积层、批归一化层、激活函数和池化层。
"""
super(Classifier, self).__init__()
# 定义卷积神经网络的序列结构
self.cnn = nn.Sequential(
nn.Conv2d(3, 64, 3, 1, 1), # 输入通道3,输出通道64,卷积核大小3,步长1,填充1
nn.BatchNorm2d(64), # 批归一化,作用于64个通道
nn.ReLU(), # ReLU激活函数
nn.MaxPool2d(2, 2, 0), # 最大池化,池化窗口大小2,步长2,填充0
nn.Conv2d(64, 128, 3, 1, 1), # 输入通道64,输出通道128,卷积核大小3,步长1,填充1
nn.BatchNorm2d(128), # 批归一化,作用于128个通道
nn.ReLU(),
nn.MaxPool2d(2, 2, 0), # 最大池化,池化窗口大小2,步长2,填充0
nn.Conv2d(128, 256, 3, 1, 1), # 输入通道128,输出通道256,卷积核大小3,步长1,填充1
nn.BatchNorm2d(256), # 批归一化,作用于256个通道
nn.ReLU(),
nn.MaxPool2d(2, 2, 0), # 最大池化,池化窗口大小2,步长2,填充0
nn.Conv2d(256, 512, 3, 1, 1), # 输入通道256,输出通道512,卷积核大小3,步长1,填充1
nn.BatchNorm2d(512), # 批归一化,作用于512个通道
nn.ReLU(),
nn.MaxPool2d(2, 2, 0), # 最大池化,池化窗口大小2,步长2,填充0
nn.Conv2d(512, 512, 3, 1, 1), # 输入通道512,输出通道512,卷积核大小3,步长1,填充1
nn.BatchNorm2d(512), # 批归一化,作用于512个通道
nn.ReLU(),
nn.MaxPool2d(2, 2, 0), # 最大池化,池化窗口大小2,步长2,填充0
)
# 定义全连接神经网络的序列结构
self.fc = nn.Sequential(
nn.Linear(512*4*4, 1024), # 输入大小512*4*4,输出大小1024
nn.ReLU(),
nn.Linear(1024, 512), # 输入大小1024,输出大小512
nn.ReLU(),
nn.Linear(512, 11) # 输入大小512,输出大小11,最终输出11个类别的概率
)
def forward(self, x):
"""
前向传播函数,对输入进行处理。
参数:
x -- 输入的图像数据,形状为(batch_size, 3, 128, 128)
返回:
输出的分类结果,形状为(batch_size, 11)
"""
out = self.cnn(x) # 通过卷积神经网络处理输入
out = out.view(out.size()[0], -1) # 展平输出,以适配全连接层的输入要求
return self.fc(out) # 通过全连接神经网络得到最终输出
可视化结果:
加入kaggle的竞赛,提交预测csv文件来进行评估