第二周周报:深度学习基础内容

目录

摘要

Abstract

一、什么是深度学习

二、反向传播

2.1 反向传播的涵义

2.2 主要步骤

三、如何更好的训练神经网络

3.1 局部极小值与鞍点

3.2 批量与动量

3.3 自适应学习率

3.3.1 AdaGrad:根据梯度大小自动调节学习率

3.3.2 RMSProp:与AdaGrad不同的是,RMSProp可以动态调整梯度的重要程度

3.3.3 Adam:在RMSProp的基础上加上动量,是最常用的优化器。

3.4 学习率调度

3.4.1学习率退火(衰减)

3.4.2 预热

四、批量归一化、特征归一化

4.1 批量归一化(BN)

4.2 特征归一化

五、激活函数

5.1 Sigmoid函数

5.2 Tanh函数

5.3 ReLU函数

5.4 Leak ReLU函数

5.5 PReLU函数

5.6 ELU函数

5.7 Softmax函数

六、Pytorch的基础语法

总结


摘要

本周跟着李宏毅老师的课程,学习了深度学习相关的基础知识。详细学习了深度学习在参数更新时所必须的反向传播;以及将来为了更好的训练神经网络时,需要注意的局部极小值与鞍点的问题,优化模型时需要分批量的训练,还有引入动量的方法,以及学习率该如何调的问题。本周还学习了几类激活函数,以及PyTorch的基础语法。

Abstract

This week, I followed Professor Li Hongyi's course and learned the basic knowledge related to deep learning. Detailed learning of the necessary backpropagation for parameter updates in deep learning; And in order to better train neural networks in the future, attention should be paid to the issues of local minima and saddle points. When optimizing models, batch training is required, as well as the introduction of momentum methods and how to adjust the learning rate. This week, I also learned several types of activation functions and the basic syntax of PyTorch.

一、什么是深度学习

深度学习是使用深度神经网络来学习数据的表示和提取特征。这些网络由多个层次组成,每一层都执行特定的数据变换,从而将数据从原始形式转换为更高层次、更抽象的表达。

神经网络结构:每一层神经元接收前一层神经元的输出作为输入,并经过线性转变和非线性变换后产生输出。这些输出再作为下一层神经元的输入,直到最后一层产生模型的最终输出。

深度学习神经网络如下图所示:

二、反向传播

2.1 反向传播的涵义

神经网络中使用梯度下降等优化算法进行模型训练时,通过计算损失函数对模型参数的梯度,然后反向传播这些梯度从输出层到输入层,以更新模型的过程。基于微积分的链式法则,将其分解为一系列简单的局部梯度计算。

2.2 主要步骤

(1)前向传播:通过神经网络,使用当前模型的参数,从输入层到输出层,得到模型的预测结果。

前向传播过程如图:

(2)计算损失:预测结果与真实值比较(如均方差)。

在完成(1)中的前向传播后,我们就可以计算f_{6}的输出值与真实值之间的误差。然后再根据误差反向计算每个神经元所产生的误差,如下图:

\sigmaf_{6}与真实值之间的误差,反向根据参数w_{46}计算出f_{4 }所产生的误差\sigma _{4}

(3)反向传播梯度:

我们已经在上述步骤中,我们计算出了每个神经元的损失,接下就需要用到上一篇文章所学习的梯度下降算法进行参数的更新。

反向传播主要依靠“链式求导”,我们求出f_{6}的表达式之后,我们就可以借助f_{6}反向对f_{5}f_{4}求偏导。

举一个简单的例子,如果我们计算出了损失J(\vec{w},\vec{b}),要求对w_{5}的偏导。需要先对out_{1}做偏导,求出的式子在对net_{1}做偏导。

公式如下:

\frac{\partial J(\vec{w},\vec{b})}{\partial w_{5}}=\frac{\partial J(\vec{w},\vec{b})}{\partial out_{1}}\frac{\partial out_{1}}{\partial net_{1}}\frac{\partial net_{1}}{\partial w_{5}}

(4)参数更新

w_{5}=w_{5}-\alpha\frac{\partial J(\vec{w},\vec{b})}{\partial w_{5}}

重复上述(1)-(4)的步骤就可以不断更新迭代,实现模型的优化。

反向传播的学习参考了这篇博客

三、如何更好的训练神经网络

3.1 局部极小值与鞍点

模型在做优化时,参数不断的更新,损失值不在下降。通常因为收敛在梯度为0的临界点,即局部最小值和鞍点。

实际情况下,输入的参数维度通常较大,所以遇到局部极小值的情况不常见,因为几乎遇不到特征值都为正的临界点。所以大多是遇到了鞍点。所以下文将讲述遇到鞍点时该如何继续更新参数。

最小值比例=正特征值数/总特征值数

  •  判断临界值种类

我们取\theta的临近点\theta ',根据泰勒级数展开得:

L(\theta )=L(\theta ')+(\theta-\theta')^{T}g+\frac{1}{2}(\theta-\theta')^{T}H(\theta-\theta')

g为g_{i}=\frac{\partial L(\theta ')}{\partial \theta _{i}}梯度,H为海森矩阵H_{ij}=\frac{\partial ^{2}}{\partial \theta_{i} \partial \theta_{j} }L(\theta ')

又因为临界点时,梯度g=0;所以L(\theta )=L(\theta ')+\frac{1}{2}(\theta-\theta')^{T}H(\theta-\theta')

  • 通过\frac{1}{2}(\theta-\theta')^{T}H(\theta-\theta')判断误差表面

我们令v=\theta-\theta'

(1)当v^{T}Hv>0,则L(\theta )>L(\theta '),为局部极小值;

(2)当v^{T}Hv<0,则L(\theta )<L(\theta '),为局部极大值;

(3)当v^{T}Hv有时>0时,有时<0时:为鞍点。

简易方法:无需代入所有的v,只需计算H的特征值,若H为正定矩阵,则为局部极小值;同理。 

  • 更新参数

\lambda为H的一个特征值,\upsilon为对应的特征向量,令v=\theta-\theta',则:

v^{T}Hv=v^{T}(\lambda v)=\lambda ||v||^{2}

\lambda<0,则\lambda ||v||^{2}<0,所以\frac{1}{2}(\theta-\theta')^{T}H(\theta-\theta')<0;则L(\theta )<L(\theta '),且\theta =\theta'+v。所以沿着\upsilon的方向更新,损失就会下降。

3.2 批量与动量

  • 批量(batch)

由于在梯度优化过程中,大批量的训练准确率较低;但很小批量的训练计算时间又很长,因为采用GPU计算时,只有批量增加到一点限度时时间才会明显增加,所以选择合适大小的batch进行训练才会有较好的优化效果。批量大小与时间的关系如下图所示:

 便利完所有的batch的过程称为一个回合(epoch),每完成一个batch就更新一次参数。批量大小与回合和时间之间的关系如下:

 采用batch的好处:当批量梯度下降时,若梯度为0时,不看海森矩阵就无法继续更新梯度;而小批量更新每次挑一个batch计算梯度,所以每次更新参数的函数都有所差异,所以下一批batch训练时不一定会被卡住。综上,这样的噪声对参数更新反而有帮助。

小批量梯度下降与批量梯度下降的比较如下:

  • 动量

 一个可以对抗鞍点或局部极小值的方法。每次更新参数时,不只往梯度的反方向移动,还要加上上一步的移动方向决定。如下图所示:

3.3 自适应学习率

有时损失不再下降,并非走到了临界点,梯度也没有变得很小。而是在“山谷”之间来回“震荡”(如下图所示)。所有的参数都设置相同的学习率显然是不明智的,需要给每一个参数定制化学习率。例如:某方向梯度值很小,那步长就应该调大一些;反之。

3.3.1 AdaGrad:根据梯度大小自动调节学习率

\theta _{t+1}=\theta _{t}-\alpha g_{t}^{i}

\alpha =\frac{\eta }{\sigma _{t}^{i}}

\sigma _{t}^{i}=\sqrt{\frac{1}{t+1}\sum_{t=0}^{T}(g_{t}^{i})^{2}}

3.3.2 RMSProp:与AdaGrad不同的是,RMSProp可以动态调整梯度的重要程度

\theta _{t+1}=\theta _{t}-\frac{\eta }{\sigma _{t}^{i}} g_{t}^{i}

\sigma _{t}^{i}=\sqrt{\alpha (\sigma _{t-1}^{i})^{2}+(1-\alpha )(g_{t}^{i})^{2}}

可通过\alpha调节。 

3.3.3 Adam:在RMSProp的基础上加上动量,是最常用的优化器。

3.4 学习率调度

在3.3 自适应学习率中\eta是一个固定值,但是\eta也是和时间有关的。

3.4.1学习率退火(衰减)

\eta随时间t而逐渐减少。

3.4.2 预热

\eta先变大后逐渐减小。因为  统计的结果需要足够多的数据才精准,一开始统计结果 σ 是不精准的。所以开始学习率比较小是用来探索收集一些有关误差表面的情报,此时\eta较大,更利于收集有关 σ 的统计数据,等 σ 统计得比较精准以后,再让学习率慢慢爬升,同时\eta开始减小。  

四、批量归一化、特征归一化

4.1 批量归一化(BN)

批量归一化是一种正则化技术,它通过对每一层的输入进行归一化处理,使得每一层的输入分布相对稳定,从而加速网络的收敛速度,提高模型的泛化性能。批量归一化能够减少内部协变量偏移,即训练过程中由于数据分布变化而导致的网络参数更新不稳定的问题。此外,批量归一化还可以减少模型的过拟合风险,因为它降低了网络对训练数据中微小变化的敏感性。

PyTorch中,使用nn.BatchNorm2d实现。

4.2 特征归一化

在数据预处理阶段,对整个数据集的所有特征进行预处理。将不同特征的数据范围缩放到相同的尺度上,以便模型公平的评估每一个特征的重要性。

下图可以说明,如果输入不在同一尺度下,及时参数w很小,对损失的影响依旧很大。

采用Z值归一化, 对每一个维度都做一样的归一化,所有特征不同维度的数值都在0 上下,就可以制造一个比较好的误差表面。
Z值归一化:x_{i}^{r}`=\frac{x_{i}^{r}-m_{i}}{\sigma _{i}}

 

五、激活函数

激活函数通常在每个神经元(除了输入层)的输出上方,作为输入加权和的非线性转变。如果没有激活函数的神经网络仅是一个线性回归模型,激活函数使得神经网络能够学习和理解复杂的数据模式。

5.1 Sigmoid函数

公式:\sigma (x)=\frac{1}{1+e^{-x}}

特点:将任意实值压缩到0和1之间,常用于二分类问题的输出层。但因其梯度消失问题(当输入值非常大或非常小时,梯度接近0),在深度网络中较少使用。

5.2 Tanh函数

公式:tanh(x)\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}

特点:将任意实值压缩到-1和1之间,输出以0为中心,有助于加快收敛速度。但它同样存在梯度消失问题。

5.3 ReLU函数

公式:f(x)=max(0,x)

特点:当输入为正时,输出等于输入;当输入为负时,输出为0。ReLU解决了梯度消失问题(在输入为正时),计算简单且高效,是目前最常用的激活函数之一。然而,它可能导致“神经元死亡”问题,即某些神经元可能永远不会被激活。

5.4 Leak ReLU函数

公式:f(x)=max(ax,x)

特点:旨在解决ReLU的“神经元死亡”问题,通过允许小的负梯度通过,保持神经元在训练过程中的活性。

5.5 PReLU函数

公式:与Leaky ReLU类似,但α是一个可学习的参数,通过反向传播进行更新。

特点:增加了模型的灵活性,允许网络自动调整负输入部分的斜率。

5.6 ELU函数

公式:当x>0时,f(x)=x;当x<=0时,f(x)=a(e^{x}-1)

特点:结合了ReLU和Sigmoid的优点,对于负输入值,输出逐渐趋近于0但不等于0,有助于缓解梯度消失问题,并有助于捕获负值的输入信息。

5.7 Softmax函数

公式:\sigma (z_{j})=\frac{e^{z_{j}}}{\sum_{k=1}^{K}e^{z_{k}}}

特点:常用于多分类问题的输出层,将输出转换为概率分布,每个类别的输出值在0和1之间,且所有类别的输出值之和为1。

六、Pytorch的基础语法

如果还没有配置Pytorch环境的哥们,请移步这篇博客

import torch

# ------- ------- 基础 ------- -------
x = torch.empty(5, 3)  # 创建一个未初始化的5x3矩阵
print(x)

x = torch.rand(5, 3)  # 创建一个随机初始化的5x3矩阵
print(x)

x = torch.zeros(5, 3, dtype=torch.long)  # 创建一个5x3的零矩阵,类型为long
print(x)

x = torch.tensor([5.5, 3])  # 直接从数据创建tensor
print(x)

x = torch.ones(2, 2, requires_grad=True)  # 创建一个tensor,并设置requires_grad=True以跟踪计算历史
print(x)

y = x + 2  # 对tensor进行操作
print(y)

print(y.grad_fn)  # y是操作的结果,所以它有grad_fn属性(该张量是如何生成的)

z = y * y * 3  # 对y进行更多操作
out = z.mean()  # .mean()求均值
print(z, out)

out.backward()  # 使用.backward()来进行反向传播,计算梯度。因为out包含一个标量,out.backward()等价于out.backward(torch.tensor(1.))
print(x.grad)  # 打印梯度 d(out)/dx


if torch.cuda.is_available():  # 判断是否有GPU
    x = x.to('cuda')  # 移动tensor到GPU上
    x = torch.tensor([1.0, 2.0], device='cuda')  # 直接在GPU上创建tensor

输出结果如下:

总结

本周的学习到此结束,下周将继续跟着李宏毅老师的课程,学习CNN、RNN等经典神经网络模型。如有错误,请各位大佬指出,谢谢!

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值