learn_pytorch03
第三章
深度学习分为如下几个步骤
1:数据预处理,划分训练集和测试集
2:选择模型,设定损失函数和优化函数
3:用模型取拟合训练数据,并在验证计算模型上表现。
接着学习了一些数据读入
模型构建
损失函数的构建
以及训练
第四章
主要是基础实战。
一些细节:
class MLP(nn.Module):
声明带有模型参数的层,这里声明了两个全连接层
def init(self, **kwargs):
# 调用MLP父类Block的构造函数来进行必要的初始化。这样在构造实例时还可以指定其他函数
super(MLP, self).init(**kwargs)
self.hidden = nn.Linear(784, 256)
self.act = nn.ReLU()
self.output = nn.Linear(256,10)
定义模型的前向计算,即如何根据输入x计算返回所需要的模型输出
def forward(self, x):
o = self.act(self.hidden(x))
return self.output(o)
net(X) 会调用MLP继承自Module类的call函数,这个函数会调用MLP类定义的forward函数来完成前向计算
一个神经网络的典型训练过程如下:
定义包含一些可学习参数(或者叫权重)的神经网络
在输入数据集上迭代
通过网络处理输入
计算 loss (输出和正确答案的距离)
将梯度反向传播给网络的参数
更新网络的权重,一般使用一个简单的规则:weight = weight - learning_rate * gradient
torch.nn.init 作用
All the functions in this module are intended to be used to initialize neural network parameters, so they all run in torch.no_grad() mode and will not be taken into account by autograd.
损失函数的构建
torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction=‘mean’)
功能:计算二分类任务时的交叉熵(Cross Entropy)函数。在二分类中,label是{0,1}。对于进入交叉熵函数的input为概率分布的形式。一般来说,input为sigmoid激活层的输出,或者softmax的输出。
weight:每个类别的loss设置权值
size_average:数据为bool,为True时,返回的loss为平均值;为False时,返回的各样本的loss之和。
reduce:数据类型为bool,为True时,loss的返回是标量
torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction=‘mean’)
功能:计算交叉熵函数
主要参数:
weight:每个类别的loss设置权值。
size_average:数据为bool,为True时,返回的loss为平均值;为False时,返回的各样本的loss之和。
ignore_index:忽略某个类的损失函数。
reduce:数据类型为bool,为True时,loss的返回是标量。
torch.nn.L1Loss(size_average=None, reduce=None, reduction=‘mean’)
功能: 计算输出y和真实标签target之间的差值的绝对值。
我们需要知道的是,reduction参数决定了计算模式。有三种计算模式可选:none:逐个元素计算。 sum:所有元素求和,返回标量。 mean:加权平均,返回标量。 如果选择none,那么返回的结果是和输入元素相同尺寸的。默认计算方式是求平均。
torch.nn.MSELoss(size_average=None, reduce=None, reduction=‘mean’)
功能: 计算输出y和真实标签target之差的平方
torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction=‘mean’, beta=1.0)
L1的平滑输出,其功能是减轻离群点带来的影响
reduction参数决定了计算模式。有三种计算模式可选:none:逐个元素计算。 sum:所有元素求和,返回标量。默认计算方式是求平均。
torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction=‘mean’, beta=1.0)
L1的平滑输出,其功能是减轻离群点带来的影响
reduction参数决定了计算模式。有三种计算模式可选:none:逐个元素计算。 sum:所有元素求和,返回标量。默认计算方式是求平均。
torch.nn.PoissonNLLLoss(log_input=True, full=False, size_average=None, eps=1e-08, reduce=None, reduction=‘mean’)
功能: 泊松分布的负对数似然损失函数
主要参数:
log_input:输入是否为对数形式,决定计算公式。
full:计算所有 loss,默认为 False。
eps:修正项,避免 input 为 0 时,log(input) 为 nan 的情况。
torch.nn.KLDivLoss(size_average=None, reduce=None, reduction=‘mean’, log_target=False)
功能: 计算KL散度,也就是计算相对熵。用于连续分布的距离度量,并且对离散采用的连续输出空间分布进行回归通常很有用。
reduction:计算模式,可为 none/sum/mean/batchmean。
none:逐个元素计算。
sum:所有元素求和,返回标量。
mean:加权平均,返回标量。
batchmean:batchsize 维度求平均值
torch.nn.MarginRankingLoss(margin=0.0, size_average=None, reduce=None, reduction=‘mean’)
功能: 计算两个向量之间的相似度,用于排序任务。该方法用于计算两组数据之间的差异。
margin:边界值,(x_{1}) 与(x_{2}) 之间的差异值。
reduction:计算模式,可为 none/sum/mean
torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction=‘mean’)
功能: 对于多标签分类问题计算损失函数。
torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction=‘mean’)torch.nn.(size_average=None, reduce=None, reduction=‘mean’)
功能: 计算二分类的 logistic 损失。
reduction:计算模式,可为 none/sum/mean。
torch.nn.MultiMarginLoss(p=1, margin=1.0, weight=None, size_average=None, reduce=None, reduction=‘mean’)
功能: 计算多分类的折页损失
主要参数:
reduction:计算模式,可为 none/sum/mean。
p:可选 1 或 2。
weight:各类别的 loss 设置权值。
margin:边界值
torch.nn.TripletMarginLoss(margin=1.0, p=2.0, eps=1e-06, swap=False, size_average=None, reduce=None, reduction=‘mean’)
功能: 计算三元组损失。
三元组: 这是一种数据的存储或者使用格式。<实体1,关系,实体2>。在项目中,也可以表示为< anchor, positive examples , negative examples>
在这个损失函数中,我们希望去anchor的距离更接近positive examples,而远离negative examples
主要参数:
reduction:计算模式,可为 none/sum/mean。
p:可选 1 或 2。
margin:边界值
torch.nn.HingeEmbeddingLoss(margin=1.0, size_average=None, reduce=None, reduction=‘mean’)
功能: 对输出的embedding结果做Hing损失计算
主要参数:
reduction:计算模式,可为 none/sum/mean。
margin:边界值
torch.nn.CosineEmbeddingLoss(margin=0.0, size_average=None, reduce=None, reduction=‘mean’)
功能: 对两个向量做余弦相似度
主要参数:
reduction:计算模式,可为 none/sum/mean。
margin:可取值[-1,1] ,推荐为[0,0.5] 。
torch.nn.CTCLoss(blank=0, reduction=‘mean’, zero_infinity=False)
功能: 用于解决时序类数据的分类
计算连续时间序列和目标序列之间的损失。CTCLoss对输入和目标的可能排列的概率进行求和,产生一个损失值,这个损失值对每个输入节点来说是可分的。输入与目标的对齐方式被假定为 “多对一”,这就限制了目标序列的长度,使其必须是≤输入长度。
主要参数:
reduction:计算模式,可为 none/sum/mean。
blank:blank label。
zero_infinity:无穷大的值或梯度值为
训练和评估
model.train() # 训练状态
model.eval() # 验证/测试状态
for data, label in train_loader:
之后将数据放到GPU上用于后续计算,此处以.cuda()为例
data, label = data.cuda(), label.cuda()
开始用当前批次数据做训练时,应当先将优化器的梯度置零:
optimizer.zero_grad()
之后将data送入模型中训练:
output = model(data)
根据预先定义的criterion计算损失函数:
loss = criterion(output, label)
将loss反向传播回网络:
loss.backward()
使用优化器更新模型参数:
optimizer.step()
这样一个训练过程就完成了,后续还可以计算模型准确率等指标,这部分会在下一节的图像分类实战中加以介绍。
验证/测试的流程基本与训练过程一致,不同点在于:
需要预先设置torch.no_grad,以及将model调至eval模式
不需要将优化器的梯度置零
不需要将loss反向回传到网络
不需要更新optimizer
反向传播有什么作用
在模型训练过程中,反向传播(Backpropagation)是一种极为重要的算法,它主要用于计算损失函数相对于模型参数的梯度,进而指导参数的更新,最终让模型学习到数据中的模式和规律。下面详细介绍反向传播的作用:
计算梯度
链式法则的应用:在深度学习模型中,损失函数通常是一个复合函数,涉及众多的参数和中间变量。反向传播算法利用链式法则,从损失函数开始,沿着网络的反向路径,逐层计算损失函数相对于每个参数的梯度。
具体示例:以一个简单的多层感知机(MLP)为例,假设输入层有 两个输入,经过隐藏层和激活函数后得到输出 ,损失函数为 ( 是真实标签)。反向传播会从损失函数 开始,依次计算 对输出层权重、隐藏层权重等参数的偏导数,即梯度。
指导参数更新
梯度下降的基础:梯度代表了函数在某一点上升最快的方向,而我们的目标是最小化损失函数,因此需要朝着梯度的反方向更新模型参数。反向传播计算得到的梯度为梯度下降算法提供了必要的信息。
参数更新公式:在随机梯度下降(SGD)算法中,参数更新公式为 ,其中 是模型参数, 是学习率, 是通过反向传播计算得到的梯度。
模型学习与优化
自动调整参数:通过不断地进行前向传播计算损失,再通过反向传播计算梯度并更新参数,模型能够自动调整自身的权重和偏置,使得损失函数逐渐减小,从而提高模型的预测能力。
提高泛化能力:反向传播算法帮助模型在训练数据上学习到有效的特征表示,同时通过适当的正则化方法(如 L1、L2 正则化),可以避免模型过拟合,提高模型在未知数据上的泛化能力。
支持复杂网络结构
深度网络的训练:在深度神经网络中,网络结构通常非常复杂,包含多个隐藏层和大量的参数。反向传播算法能够有效地处理这种复杂的网络结构,通过逐层计算梯度,使得深度模型的训练成为可能。
不同类型的层:反向传播算法可以应用于各种类型的神经网络层,如全连接层、卷积层、循环层等,为不同类型的深度学习模型提供了统一的训练方法。
综上所述,反向传播在模型训练中起着核心作用,它使得深度学习模型能够高效地学习数据中的模式,不断优化自身的性能,从而在各种任务中取得良好的效果。
深度学习的目标是通过不断改变网络参数,使得参数能够对输入做各种非线性变换拟合输出,本质上就是一个函数去寻找最优解,只不过这个最优解是一个矩阵,而如何快速求得这个最优解是深度学习研究的一个重点,以经典的resnet-50为例,它大约有2000万个系数需要进行计算,那么我们如何计算出这么多系数,有以下两种方法:
第一种是直接暴力穷举一遍参数,这种方法实施可能性基本为0,堪比愚公移山plus的难度。
为了使求解参数过程更快,人们提出了第二种办法,即BP+优化器逼近求解。
因此,优化器是根据网络反向传播的梯度信息来更新网络的参数,以起到降低loss函数计算值,使得模型输出更加接近真实标签。
在训练深度学习模型时,每次迭代计算梯度之前通常需要将梯度置为 0,主要是基于 PyTorch、TensorFlow 等深度学习框架中梯度计算和更新的机制,下面从多个方面为你详细解释原因。
梯度累加机制
框架的梯度计算方式:在大多数深度学习框架里,梯度并不是每次计算后就自动清零,而是会进行累加。这是因为框架考虑到可能存在需要多次前向传播和反向传播来累积梯度,再进行一次参数更新的情况(如使用大批次数据但内存有限时)。
避免梯度错误累加:如果在每次迭代开始时不将梯度置为 0,那么新计算得到的梯度会和上一次迭代的梯度累加在一起。这样会导致梯度值不断增大,使得参数更新的步长失去控制,模型无法按照预期收敛,甚至可能导致梯度爆炸。
独立计算每次迭代的梯度
保证每次迭代的独立性:模型训练是通过多次迭代不断更新参数以最小化损失函数的过程。每次迭代都应该基于当前的参数状态和当前批次的数据独立计算梯度,这样才能准确反映当前批次数据对损失函数的影响,进而正确更新参数。
示例说明:以随机梯度下降(SGD)为例,每次迭代使用一个小批次的数据计算梯度并更新参数。如果不将梯度置为 0,那么下一次迭代计算的梯度就会受到上一次批次数据的干扰,无法准确反映当前批次数据的信息,从而影响模型的学习效果。