链式法则
对于单条计算链来说,如上图所示,已知输入变量
x
x
x,经过计算过程
g
g
g之后进入计算过程
f
f
f,得到最终计算结果
f
(
g
(
x
)
)
f(g(x))
f(g(x))。当我们要计算
f
(
g
(
x
)
)
f(g(x))
f(g(x))关于变量x的导数的时候,根据高中或者大学的数学,可以表示为
d
f
d
x
=
d
f
d
g
d
g
d
x
\frac{d_f}{d_x}=\frac{d_f}{d_g}\frac{d_g}{d_x}
dxdf=dgdfdxdg。
当链的长度特别长,如下所示:
假定最终的计算函数为
L
o
s
s
Loss
Loss函数,则
L
o
s
s
Loss
Loss关于
x
x
x的导数计算过程为:
d
L
o
s
s
d
x
=
d
L
o
s
s
d
?
⋅
⋅
⋅
d
f
d
g
d
g
d
x
\frac{d_{Loss}}{d_x}=\frac{d_{Loss}}{d_?}···\frac{d_f}{d_g}\frac{d_g}{d_x}
dxdLoss=d?dLoss⋅⋅⋅dgdfdxdg。由于神经网络中影响
L
o
s
s
Loss
Loss函数值的变量不仅仅只有
x
x
x这一个变量,所以引用高等数学中的偏导数来表示,形如
∂
L
o
s
s
∂
x
\frac{\partial_{Loss}}{\partial_x}
∂x∂Loss,如图中所示。如图中箭头所示:这个求偏导数的过程是由最终结果往前推的过程,所以也就叫做反向传播(Back Propagation)过程。
举例说明
前向传播过程
以下针对上述过程举出一个详细的示例来讲解梯度的前向传播和反向传播过程。
事前规定: 首先取神经网络中某一部分,该部分输入项由
x
x
x和
y
y
y两个变量组成,该部分计算过程
f
f
f定义为四则运算中的乘法运算,
z
z
z表示输出结果,图中所示单元仅仅为神经网络中的起始层,记最终的函数结果为
L
o
s
s
Loss
Loss。
如上所示,可以知道计算过程
f
f
f的函数式表示为:
f
=
x
⋅
y
f=x·y
f=x⋅y,其中
“
⋅
”
“·”
“⋅”表示四则运算中的乘法运算。根据高等数学中偏导数的计算定义,该计算过程对于变量
x
x
x和
y
y
y的偏导数计算值如下所示:
∂
z
∂
x
=
∂
x
⋅
y
∂
x
=
y
\frac{\partial_z}{\partial_x}=\frac{\partial_{x·y}}{\partial_x}=y
∂x∂z=∂x∂x⋅y=y
∂
z
∂
y
=
∂
x
⋅
y
∂
y
=
x
\frac{\partial_z}{\partial_y}=\frac{\partial_{x·y}}{\partial_y}=x
∂y∂z=∂y∂x⋅y=x,将等式
x
=
2
,
y
=
3
x=2,y=3
x=2,y=3代入,可得:
∂
z
∂
x
=
y
=
3
,
∂
z
∂
y
=
x
=
2
\frac{\partial_z}{\partial_x}=y=3,\frac{\partial_z}{\partial_y}=x=2
∂x∂z=y=3,∂y∂z=x=2。
反向传播过程
如上所示:已知神经网络的损失函数记做
L
L
L,现在要求
L
L
L关于变量
x
x
x的偏导数,根据前面所述的链式法则,计算过程如下:
∂
L
∂
x
=
∂
L
∂
z
∂
z
∂
x
=
5
∗
3
=
15
\frac{\partial_L}{\partial_x}=\frac{\partial_L}{\partial_z}\frac{\partial_z}{\partial_x}=5*3=15
∂x∂L=∂z∂L∂x∂z=5∗3=15 同理,损失函数
L
L
L关于变量
y
y
y的偏导数为:
∂
L
∂
y
=
∂
L
∂
z
∂
z
∂
y
=
5
∗
2
=
10
\frac{\partial_L}{\partial_y}=\frac{\partial_L}{\partial_z}\frac{\partial_z}{\partial_y}=5*2=10
∂y∂L=∂z∂L∂y∂z=5∗2=10
神经网络为什么需要反向传播过程
BP(Back Propagation:反向传播)算法是一种与最优化方法(如梯度下降法)结合使用的,用来训练人工神经网络的常见方法。该方法对网络中所有权重计算损失函数的梯度(即如上所示的偏导数)。这个梯度会反馈给最优化方法,用来更新权值以最小化损失函数。
思考:
- 在给定数量的数据集上,神经网络的训练容易使得损失函数得到局部最小值,以此训练出来神经网络可能对其他样本数据的预测是不准确的。
自动求梯度
Pytorch通过对某个Tensor变量设置其requires_grad为True,然后使用backward()函数即可启用对该变量进行自动求梯度的过程。
以下根据实际例子使用pytorch编写如何求梯度的简单程序示例,假设输入、输出、损失函数、权重、偏置项如下图所示
以下使用pytorch编写python进行梯度的求解:
import torch # 引入torch模块
from torch.autograd import Variable
x_data = [1.0,2.0,3.0] # 三个样本数据组成的向量
y_data = [2.0,4.0,6.0] # 三个样本分别对应的输出值
w = Variable(torch.Tensor([1.0]),requires_grad=TRue) # 权重值封装为Tensor,启用自动求梯度(后面可以使用backward()以启用pytorch的自动求梯度机制求损失函数对于w的梯度)
# 定义要算的函数
def forward(x):
return x*w # 此处先不取偏置项
# 定义损失函数:此处取预测值与实际值差的平方
def loss(x,y):
y_prediction = forward(x)
return (y_prediction-y)*(y_prediction-y)
# 定义训练过程
for epoch in range(10): # 此处暂定训练10次
for x_val,y_val in zip(x_data,y_data): # 每一轮中都对该数据集进行一次训练,查看梯度变化
l = loss(x_val,y_val) # 计算每一个样本对应的损失函数的值
l.backward() # 对参数进行反向传播,计算梯度
print("\tgrad:",x_val,y_val,w.grad.data[0])# 因为权重变量中元素只有1个,所以用0下标取得对应的数据
w.data = w.data - 0.01*w.grad.data # 自定义的权重更新策略
# 对刚才求出来的梯度置0(初始化)
w.grad.data.zero_()
print("progress:",epoch,l.data[0]) # 输出每一轮的损失函数的值
# 训练结束后,输入变量4查看网络的预测结果
print("predict(after trainning)",4,forward(4).data[0])
以上代码为我从Youtube-PyTorch Lecture 04: Back-propagation and Autograd摘抄而来,并加上自己认为的注释,本人未经过程序验证,但是该过程从理解上来说应该是正确过程,仅供参考。原作者的运行结果如下:
总结:
- 简要介绍了神经网络中前向传播和反向传播过程
- 编写简要程序介绍了pytorch中autograd机制及其使用过程
- backward()函数的介绍如下所示: