目录
(一)自适应学习率(adaptive learning rate)
(2)RMSprop(Root Mean Squared propagation)
(3)Adam(Adaptive moment estimation)
(二)学习率调度(learning rate scheduling)
(1)学习率衰减(learning rate decay),又称学习率退火(learning rateannealing)。
一、学习资料
Datawhale提供的pdf:Datawhale (linklearner.com)
李宏毅老师对应视频课程:神经网络训练不起来怎么办(3):自动调整学习速率(Learning Rate)_哔哩哔哩_bilibili
二、学习笔记
(一)自适应学习率(adaptive learning rate)
1、什么是+为什么要用
在训练一个网络时,损失随着参数不断更新而越来越小,最后卡在临界点(损失不再下降),此时梯度非常小。但损失不再下降的时候,并不意味着此时梯度很小。
如图所示,随着迭代次数增多,虽然损失不再下降,但是梯度的范数并没有真的变得很小。
(截图自datawhale教程,如无特殊说明,下同)
从误差表面的图也可以看出,梯度可能是卡在“山谷”里来回“震荡”:
在实际训练中,使用一般的梯度下降法走到鞍点或局部最小值是一件困难的事情。往往会在梯度还很大的时候,损失就已经降了下去。所以,多数时候训练在还没有走到临界点的时候就已经停止了。
此时,我们可以通过调整学习率来改变现状。但如何确定学习率的大小?学习率太大了容易miss最优解,太小了又浪费时间。所以,我们引入动态学习率,给每个参数一个不同的学习率(在原本的梯度下降里,所有参数都设定为相等的学习率),即自适应学习率(adaptive learning rate):
在某一个方向上的梯度值很小(图像平坦,坡度小)则把学习率调大;
在某一个方向上的梯度值很大(图像陡峭,坡度大)则把学习率调小。
2、三种自适应学习率方法
(1)AdaGrad(Adaptive Gradient)
AdaGrad(Adaptive Gradient)是典型的自适应学习率方法,能够根据梯度大小自动调整学习率:当梯度较大时,减小学习率;当梯度较小时,增加学习率。
原本的梯度下降的更新过程:
之前我们在第一节课(入门深度学习)学到的,更新公式:
(截图来自李宏毅老师课程)
本次的未知数为θ,则公式为:
现在我们要做一个随着参数定制化的学习率,即自适应学习率AdaGrad,则改变原本公式中的学习率η为,更新过程使用新的公式:
上标为 i,这代表参数 σ 与 i 相关:不同的参数的 σ 不同。
下标为 t,这代表参数 σ 与迭代相关:不同的迭代也会有不同的 σ。
学习率从 η 改成的时候,学习率就变得参数相关(parameter dependent)。
参数相关的常见类型:算梯度的均方根(root mean square)。
更新过程:(0代表初始化的参数,g是梯度)
所以第一次更新参数的情况为:
以此来限制第一次更新的情况。
接下来第二次更新参数:(把初始化的0换成1)
第三次:
以此类推,第t+1次:
结论:
(2)RMSprop(Root Mean Squared propagation)
同一个参数的同个方向,学习率也是需要动态调整的,于是我们引入新方法———RMSprop(Root Mean Squared propagation)
第一次与AdaGrad相同:
第二次:
第三次:
第t+1次:
其中α(0 < α < 1)是超参数,可自行调整的。
AdaGrad算均方根时,每一个梯度都有同等的重要性,但在RMSprop里面,可以通过α看出现在正在运算的梯度的重要性:
如果 α 趋近于 0,则相较于之前算出来的梯度,更重要;如果 α 趋近于 1,则代表之前算出来的梯度比较重要, 不重要。
结论:
(3)Adam(Adaptive moment estimation)
这个是最常用的优化的策略(或称优化器optimizer)
Adam=RMSprop+动量(使用动量作为参数更新方向)
而且PyTorch里有预设的参数~
没太理解所以还是问了一下AI:
Adam算法不仅计算了梯度平方的加权平均数(即二阶矩估计),还计算了梯度的加权平均数(即一阶矩估计)。这两个估计值分别用于调整学习率的两个不同方面:一阶矩估计有助于加速收敛,因为它考虑了梯度的方向性;而二阶矩估计则有助于调整学习率的大小,因为它考虑了梯度的变化性。Adam算法通过结合这两个估计值来动态地调整每个参数的学习率,从而实现了更加高效和稳定的优化过程。
(简要概括一下:Adam算法同时考虑了梯度的一阶矩估计和二阶矩估计,通过这两个估计值的结合来动态调整学习率)
(二)学习率调度(learning rate scheduling)
1、为什么要用
加上自适应学习率以后,使用AdaGrad方法优化的结果如图 3.27 所示。
一开始优化的时候很顺利:在左转的时候,有 AdaGrad以后,可以再继续走下去,走到非常接近终点的位置。
走到 BC 段时:因为横轴方向的梯度很小,所以学习率会自动变大,步伐就可以变大,从而不断前进。
但接下来出现问题(红圈里):在AB段梯度很大,走到BC段时,纵轴的方向梯度变小,就累计了很小的σ,因此步伐(学习率)变大,于是就会突然上下喷射起来。
而因为刚才的步伐很大,所以导致走到了梯度变大的地方,σ也变大,此时步伐(学习率)就会变小,于是慢慢又被拉了回来。
如何解决这个问题呢?我们引入学习率调度的两种方法。
2、两种学习率调度方法
(1)学习率衰减(learning rate decay),又称学习率退火(learning rateannealing)。
这个是最常见的策略。之前的学习率调整方法中,η是一个固定值。而之前也学到,在学习率调度中,η与时间有关。
现在随着参数的不断更新,让 η 越来越小,使得步伐乘 η 也变小,就可以使图像慢慢走到终点了。
(2)预热
另一种经典的方法:预热。让学习率先变大后变小。
至于变到多大、变大的速度、变小的速度都是超参数。
此处再贴一个QA:
(三)优化总结
以上,我们从最开始学到的梯度下降的更新公式:θ=θ0−η⋅∇J(θ),进化到增加了自适应学习率、学习率调度、动量的公式:
这个是目前优化的最完整版本:动量不是顺着某个时刻算出的梯度方向来更新参数,而是把过去所有算出梯度的方向做一个加权总和当作更新的方向。
接下来的步伐大小为。最后通过ηt实现学习率调度。
(四)机器学习之分类
1、分类与回归的关系
机器学习可分为三个大类:
(截图自我自己入门班第一节课的笔记:Datawhale X 李宏毅苹果书 AI夏令营 深度学习入门笔记01-CSDN博客)
回归问题:y 是要学习的目标。输入一个向量x,希望y'跟某一个label(标签,实际数值)y越接近越好,最后输出y'。
而分类问题也可以用回归的视角来看:输入向量x后,输出仍然是一个标量 y',要让它跟正确答案y那个类越接近越好。把类也变成数字来看就是:
如果三个类有特定关系:比如根据一个人的身高跟体重,预测他是一年级、二年级还是三年级。一年级跟二年级关系比较近,一年级跟三年级关系比较远。用数字来表示类会预设1和2关系更近,1和3关系较远。
如果三个类没有特定的关系:引入独热向量来表示类(在做分类的问题的时候,比较常见的做法也是用独热向量表示类),此时标签y就是一个三维的向量,比如类1是 [1, 0, 0]T,类2是 [0, 1, 0]T,类3是 [0, 0, 1]T(都是转置的,写不出角标,加个注释提醒自己一下)
(如果每个类都用一个独热向量来表示,就没有类 1 跟类 2 比较接近,类 1 跟类 3 比较远的问题。如果用独热向量计算距离的话,类两两之间的距离都是一样的。)
(y是独热向量,所以其里面的值只有 0 跟 1,但是y'里面有任何值。既然目标只有 0 跟 1,但y' 有任何值,可以先把它归一化到 0 到 1 之间,这样才能跟标签的计算相似度。)
把a1, a2, a3分别各自乘上三个不同的权重w1, w2, w3,加上偏置b1, b2, b3,得到y1', y2', y3',并希望它们跟label越接近越好;
2、带有softmax的分类
有三个类的情况下,我们可以套 softmax 函数。(当然两个类也可以直接套)
但一般有两个类的时候,我们选择不套 softmax,而是直接取 sigmoid(即,当只有两个类的时候,sigmoid 和 softmax 是等价的)
按照上述的设定,分类实际过程是:输入 x,乘上 W,加上 b,通过激活函数 σ,乘上W′,再加上 b′ 得到向量 yˆ。但实际做分类的时候,往往会把 yˆ 通过 softmax 函数得到 y′,才去计算 y′ 跟 yˆ 之间的距离。
softmax步骤:
①把所有的y取一个指数(负数取指数后也会变成正的)
②归一化(除掉所有 y 的指数值的和)得到 y′
③根据下图softmax 的块(block),输入 y1、y2 和 y3,产生 y′1、y′2 和 y′3。
比如 y1 = 3,y2 = 1,y3 = −3
取指数:exp(3) = 20、exp(1) = 2.7 和 exp(−3) = 0.05
做完归一化后,就变成 0.88、0.12 、 0(−3取完指数,再做归一化以后,会变成趋近于 0 的值)
所以 softmax 除了归一化,让 y′1、y′2 和y′3,变成 0 到 1 之间,和为 1 以外,它还会让大的值跟小的值的差距更大。
计算式如下:
3、分类损失
当我们把 x 输入到一个网络里面产生 yˆ 后,通过 softmax 得到 y′,再去计算 y′ 跟 y 之间的距离 e:
此时有两种方法可以选择:
(1)均方误差
把 y 里面每一个元素拿出来,计算它们的平方和当作误差,公式如下:
(2)交叉熵
这个方法更常用一点。当 yˆ 跟 y′ 相同时,可以最小化交叉熵的值,此时均方误差也是最小的。最小化交叉熵其实就是最大化似然(maximize likelihood)。公式如下:
那么为什么交叉熵更常用呢?举一个实例来分析一下(从优化角度)
如果我们有一个三类的分类。
把向量x输入到一个网络→输出y1, y2, y3→通过 softmax →输出y′1、y′2 和 y′3。
(假设正确答案是 [1, 0, 0]T,要计算 [1, 0, 0]T 跟 y′1、y′2 和 y′3 之间的距离 e,e 可以是均方误差或交叉熵)
假设 y1 的变化是从-10 到 10,y2 的变化也是从-10 到 10,y3 就固定设成-1000。因为 y3 的值很小,通过 softmax 以后,y′3 非常趋近于 0,它跟正确答案非常接近,且它对结果影响很少,所以此处我们只看 y1 跟 y2 有变化的时候,对损失 e 的影响。
此时把图做出来:左右两图分别是e为均方误差和交叉熵时,y1、y2 的变化对损失L的影响(对误差表面的影响),越红色越损失大,越蓝色越损失小。
从两图中我们可以看出共性:均为左上角损失大,右下角损失小。
还能看出:不管 e 取均方误差或交叉熵,如果 y1 大、y2 小,损失都是小的;如果 y1小,y2 大,y′1 是 0,y′2 是 1,则损失大。
(如果 y1 很大,y2 很小,代表 y′1 会很接近 1,y′2会很接近 0)
此时,我们假设参数优化最开始的时候,对应的损失是在左上角。我们优化的过程,就是从左上角“走”到右下角。
如果选择交叉熵(即左图),左上角的点是有斜率的,所以可以通过梯度一路往右下的地方“走”(优化);
如果选均方误差(即右图),由于均方误差在这种损失很大的地方梯度非常小(趋近于0),图像非常平坦,因此左上角的点就“卡住”了。所以如果初始时在左上角的点的位置,离目标非常远,其梯度又很小时,我们无法用梯度下降顺利地“走”(优化)到右下角。
因此选择均方误差做分类时,如果没有好的优化器,很可能性会训练不起来。
如果用 Adam,虽然右图中的梯度很小,但 Adam 会自动调大学习率,还是有机会走到右下角的,不过训练的过程比较困难。
总之,使用不同的分类损失可以改变优化的难度。
(五)CNN卷积神经网络-图像分类
实践作业求助:
在阿里云的算力已经过期了,只能用魔搭平台提供的paidsw,但是不知道为什么...我的魔搭登陆不上去了......一登陆就显示bad gateway,又给我弹出来了,有没有大佬知道是怎么回事()甚至进不到notebook界面,一直停留在首页一直在把我踢出来......
——————分割线——————
Datawhale教程里给出了代码,这里就不再全部复制粘贴过来了,直接给出教程链接:Datawhale (linklearner.com)
这里就总结一下步骤,再补充一点备注,方便自己复习用~
1、导入所需的库/工具包
import numpy as np #前两行太常用了,略
import pandas as pd
import torch #PyTorch,用于计算机视觉和自然语言处理等任务
import os #os模块,提供许多与操作系统交互的功能,比如文件和目录管理
import torch.nn as nn #nn是PyTorch中构建神经网络所需的层的集合
import torchvision.transforms as transforms #该模块提供了许多图像预处理功能,如裁剪、旋转、归一化等
from PIL import Image #从PIL(Python Imaging Library)导入Image模块,PIL是Python的一个图像处理库
# “ConcatDataset” 和 “Subset” 在进行半监督学习时可能是有用的。
# 这里从torch.utils.data模块一口气导入了多个用于数据加载的类
# DataLoader:用于封装数据集并提供批量数据加载的迭代器。
# Subset:用于从数据集中选择子集。
# Dataset:所有数据集类的基类。
# ConcatDataset:用于将多个数据集连接成一个。
from torch.utils.data import ConcatDataset, DataLoader, Subset, Dataset
from torchvision.datasets import DatasetFolder, VisionDataset
from tqdm.auto import tqdm #tqdm是一个快速、可扩展的Python进度条库,可以在长循环中添加进度提示信息。auto模块会根据你的环境(如Jupyter Notebook或命令行)自动选择合适的tqdm版本
import random #用于随机数生成,这在数据打乱、样本抽样等场景中非常有用
# 以下为复制教程,感觉前后这两块具有连贯性所以还是贴上来了
# 设置随机种子以确保实验结果的可重复性
myseed = 6666
# 确保在使用CUDA时,卷积运算具有确定性,以增强实验结果的可重复性
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
# 为numpy和pytorch设置随机种子
np.random.seed(myseed)
torch.manual_seed(myseed)
# 如果使用CUDA,为所有GPU设置随机种子
if torch.cuda.is_available():
torch.cuda.manual_seed_all(myseed)
2、数据准备与预处理
(1)从指定路径加载图像数据。
(2)预处理:包括调整大小、将图像转换为Tensor格式。
(3)为了增强模型的鲁棒性,可以对训练集进行数据增强。
注:鲁棒性(Robustness)是指使机器学习模型在面对数据中的噪声、异常值或分布外(out-of-distribution, OOD)、对抗性样本等问题数据时,仍能保持良好性能的能力。一个具有高鲁棒性的模型能够在不同的条件下稳定工作,并且对输入数据的变化不敏感。
-
数据增强(Data Augmentation):通过变换训练数据(如图像旋转、缩放、翻转等),使得模型能够看到更多的变化形式,从而更好地泛化到未见数据上。
-
正则化(Regularization):如L1和L2正则化,可以防止模型过拟合,提高其在新数据上的表现。
-
增加对抗样本训练(Adversarial Training):通过加入对抗样本,即那些被故意修改以误导模型的输入,来增强模型对抗小幅度输入扰动的能力。
-
提高模型复杂度或采用集成方法(Ensemble Methods):使用更复杂的模型或者结合多个模型的预测结果,可以减少单一模型的偏差和方差,提高整体鲁棒性。
-
使用预训练模型(Pre-trained Models):从大量数据中预训练的模型通常有更好的泛化能力,然后可以在特定任务上进行微调。
-
模型结构改进:设计更加健壮的网络架构,比如ResNet通过残差连接解决了深层网络的梯度消失问题。
-
Dropout:在训练过程中随机丢弃一部分神经元的输出,以防止依赖于特定的特征组合,从而增加模型的泛化能力。
这部分教程代码里的注释很详细了,直接对照教程复习。
3、定义模型
定义了一个图像分类器类(classifier),继承自PyTorch的nn.Module。
该分类器通过一系列卷积层、批归一化层、激活函数和池化层构建卷积神经网络(CNN),用于提取图像特征。
随后,这些特征被输入到全连接层进行分类,最终输出11个类别的概率,用于图像分类任务。
同上,这部分教程代码里的注释很详细了,直接对照教程复习。
4、定义损失函数、优化器等其他配置
这部分实现了图像分类模型的初始化和训练配置,属于准备工作中的准备好训练环境和参数,为后续的模型训练奠定了基础。
选择合适的设备(GPU或CPU),设置模型、批量大小、训练轮数、提前停止策略,定义了损失函数和优化器。
5、训练模型
这段代码实现了一个图像分类模型的训练和验证循环,目的是通过多轮训练(epochs)逐步优化模型的参数,以提高其在验证集上的性能,并保存效果最好的模型。
训练阶段通过前向传播、计算损失、反向传播和参数更新来优化模型,验证阶段评估模型在未见过的数据上的表现。如果验证集的准确率超过了之前的最好成绩,保存当前模型,并在连续多轮验证性能未提升时提前停止训练。
6、评估模型
计算准确率,衡量模型在测试集上的表现。
7、开始预测任务
构建一个测试数据集+数据加载器,以便高效地读取数据。
实例化并加载预训练的分类器模型,并将其设置为评估模式。在不计算梯度的情况下,遍历测试数据,使用模型进行预测,并将预测标签存储在列表中。将预测结果与测试集的ID生成一个DataFrame,并将其保存为submission.csv文件。
标签:02,进阶,训练,AI,梯度,模型,学习,参数,softmax From: https://blog.csdn.net/ensoleille_clair/article/details/141753768