一文上千字带你通透看懂神经网络中的梯度下降和反向传播!

文摘   2024-08-05 16:47   新加坡  

注:很多数学公式格式公众号不支持,便用了截图的方式展示

软件环境:

Pytorch1.10、Pycharm

基础知识:

要想训练一个网络,对于梯度的理解是必不可少的,下面首先介绍梯度的一些基础概念。

1、方向余弦与向量单位化

方向余弦是一个在向量中很常见的概念,它用来标定某一个向量的方向,说起来可能会一头雾水,不过没关系,我们使用画图来理解一下。

举个例子,如下图有一个坐标系xoy,其效果如下所示:

其中包含了一个向量向量的坐标为:那么上文中的向量就满足如下式子:

上文的式子实际上就是对向量进行单位化,此时新产生的向量,实际上就是我们常说的方向向量

方向向量实际上还可以再优化一下,我们看到图上还有两个标明的角分别是这两者的关系就不再多说,他们呢一对互余的角度,满足的条件��是相加等于90度。

此时我们就可以将这个式子转化成这样的形式:

同理也有:

这样方向的向量的表达式,就可以写为:

实际因为角度互余上可以化为:

2、多元函数求偏导

一元函数,即有一个自变量。类似

多元函数,即有多个自变量。类似

多元函数求偏导过程中:对某一个自变量求导,其他自变量当做常量即可

例1:

例2:

例3:

练习:

在继续讲解之前,允许我夹带私货一下,这是我给深度学习神经网络新手同学整理的463种主流神经网络模型及其变体模型的论文代码仓库,像什么CNNRNN、transformer、生成模型等等等等模型及其变体都有,论文PDF和实现代码也给大家整理好了。

需要的同学,可以直接长按扫码添加我的助手让她无偿及时发送给大家!

3、方向导数:

简单地说方向导数形容的是满足某个关系下(Y=KX+B),对于各个方向上本关系数值变化率(Y的变化率)的量化表达式。

从二维、三维入手

在二维关系中Y=KX+B中我们不太好理解什么是方向导数,我们知道对于一个函数来说,的导数实际上是这样的:

对于函数的某一点,导数等于切线在该点的斜率,他是一个极限概念。我们不妨这样来理解这个极限的过程:

下图是某个函数,其中包含三个点如下所示:

其中A、B是函数上随机的两个点。其中A、B两点满足如下:

然后AB两点相连接,形成一个割线,割线的斜率满足如下条件:

当有如下情况的时候,就会产生切线和导数:

当B无限趋近于A的时候,即无限趋近于0的时候,割线AB就会转化为切线,如下所示:

满足的数学关系如下:

而我们知道切线的斜率就是导数的值,这是在二维的情况下。

三维度方向导数

在二维的情况我们已经很了解了,我们来推广到到三维的情况下来试一试,举个例子:

我们先来下一个定义:

一般情况下的三位函数的方向导数实际上是平面XOY上一点在三维函数的值和其所代表的一点x,y,f(x,y)以向量l的方向向量为切面构成的曲线上(点(x,y))的一条切线的值。

说起来很抽象,我们举个例子就好理解一点了:

其中三维函数圆形抛物面大致如下:

如图所示:

图看起来很很复杂不过没关系,我们依靠颜色来分辨一下:

红色包含两部分内容:分别是在xy平面的点和切面构成的曲线。

蓝色部分包含一个内容:就是函数Z。

我们来解析一下这分别什么意思,当存在一个点c从点(x,y)出发沿着方向向量变化的时候,其坐标满足如下:

这时候c点实际上就是黑色虚线在l上的点。这时候这个在向量上的变化轨迹就是一段向量,他的方向和l向量的方向向量是一样的,并且在函数上映射了一段曲线,如红色部分曲线所示,我们针对这一种曲线来考虑一种特殊情况,当满足这个条件的时候,曲线会如何变化?

没错就是上文中二维的情况:

结果是一模一样的,只不过这里的切线是对应的在曲线上的切线,我们这里就引出方向导数的定义如下:

这里再说明一下方向导数和偏导数有什么区别呢?

偏导数实际上方向导数的特例,当向量取x的正轴的时候,此时方向导数就转变为了对于x的偏导数,推导如下:

如果你仔细看就会发现实际上这里的定义就是偏导数的定义,也就说是方向导数的一种情况。

其次再说明一下,这个式子的意义在哪里:

实际上,我们用来计算方向导数的时候就是使用这个式子,这个式子就是将对应的方向向量分解为x轴和y轴的方向余弦来进行计算,也就说方向向量实际上是由x轴和y轴的方向余弦构成的。

还有就是对于用同一个点,方向向量不同所构成的方向导数大小也不同,但是这些方向导数的方向始终会在一个平面内,这个平面就是这个点的切平面!

2、梯度

梯度是方向导数的特例:

已知在某个点有方向导数存在下列关系:

在方向l上满足如下单位向量:

则方向导数可转化成如下:

点积就相当于做一个投影,方向导数 和 梯度 之间保持一定的夹角(做点积)来构成各个方向上的方向导数。什么时候方向向量最大呢?很容易想到不存在夹角的时候就可以满足,因为此时点积最大即满足下列条件:

函数在某点的梯度是个向量,他的方向与方向导数最大值取值的方向一致,其大小正好是最大的方向导数。

梯度概念理解:如下图所示,在p点放一个热源的等温线,则热源的辐射从里到外为10°、20°、30°、40°,若一个小蚂蚁在o点,要最快逃离热源,应该往oj方向逃离,若往om方向逃离则热源的变化率为0,即一直都是20°,也就是说蚂蚁一旦确定了某个逃离方向(0°,90°)方向角逃离,只要一直沿着该方向一直走,就是最快的热源降低的方向

对于一维线性函数其导数就是梯度。

各种函数的梯度与导数的关系,更详细的解释可以参考参考文献链接:https://zhuanlan.zhihu.com/p/384175778

Tensor的梯度与反向传播

回顾机器学习

收集数据 ,构建机器学习模型,得到

如何判断模型的好坏?判断模型好坏的方法:

通过最终 loss 的输出,来反向传播计算梯度大小进而调整参数的大小实现最优解。

当 loss 满足如图时候

计算出来梯度以后:朝着梯度变化的方向运算,随机选择一个起始点通过调整让loss函数取到最小值。

w的更新方法

  1. 计算的梯度(导数)

  2. 更新

其中:

总结:梯度就是多元函数参数的变化趋势(参数学习的方向),只有一个自变量时称为导数,拥有多个时称为偏导数。

反向传播?

计算图

为了方便描述,通过图的方式来描述函数。

对每个节点求偏导可有:

反向传播的过程就是一个上图的从右往左的过程,自变量a,b,c各自的偏导就是连线上的梯度的乘积:

为什么要算反向传播?:因为要计算梯度。

实战演示:

接下来尝试计算一个简单结构的梯度,问题描述如下:

假设我们的基础模型就是y = wx+b,其中w和b均为参数,我们使用y = 3x+0.8来构造数据x、y,所以最后通过模型应该能够得出w和b应该分别接近3和0.8。

简单的来说就是拟合出满足y = 3x+0.8这个曲线。

步骤分为四步:

  • # 1 构造数据

  • # 2 设计正向传播 和 反向传播函数 来训练网络

  • # 3 训练

  • # 4 画图画出拟合出来的曲线


过程如下图:

从左向右是正向传播部分,从右向左是反向传播部分。

对于WB其计算类似这里单独说B即可,对于B的梯度满足下式,值得注意的是这里的Loos求取的是平均值实际上出来的是一个标量,对于标量的梯度计算实际上也是一个平均值(这里值得思考一下)。

反向传播后对B进行梯度下降:

梯度下降以后再次进行正向传播即可,计算出来Y_p,最后计算出来Loss

正向传播满足下式:

代码如下:

import torchimport numpy as npimport matplotlib.pyplot as plt
# 1 构造数据x_number = 50x = torch.rand([x_number, 1])y = 3 * x + 0.8rate = 0.01study_time = 3000
# 2 正向传播 和 反向传播w = torch.rand([1, 1], requires_grad=True, dtype=torch.float32)b = torch.rand(1, requires_grad=True, dtype=torch.float32)y_preidct = torch.matmul(x, w) + b

def forward_propagation(): global x, w, b, y_preidct y_preidct = torch.matmul(x, w) + b # 计算 loss loss = (y - y_preidct).pow(2).mean() return loss

def back_propagation(): global x, w, b, loss, rate, y_preidct test = 0.0 if w.grad is not None: w.grad.data.zero_() if b.grad is not None: b.grad.data.zero_() # 反向传播 loss.backward() w.data -= w.grad * rate b.data -= b.grad * rate #此处为了验证b的梯度进行计算 # for j in range(x_number): # test += ((y[j] -y_preidct[j].item()) * 2) # print("b:", b.grad) # print("b_t:", test/x_number)

# 3 训练部分for i in range(study_time): loss = forward_propagation() back_propagation() if i % 10 == 0: print("w,b,loss", w.item(), b.item(), loss.item())
# 4 画图部分predict = x * w + b # 使用训练后的w和b计算预测值plt.scatter(x.data, y.data, c="r")plt.plot(x.data.numpy(), predict.data.numpy())plt.show()

红色的是数据集结果蓝色是训练出来的结果,当训练次数比较少的时候拟合曲线不正确:

当把学习率降低(变化范围减小),增加学习次数就可以得到很好的结果:

AI算法工程师Future
B站同名,日常分享人工智能领域知识及学习资源。
 最新文章