反向传播算法(BP):
前向传播通过训练数据和权重参数计算输出结果;反向传播通过导数链式法则计算损失函数对各参数的梯度,并根据梯度进行参数的更新。
1.前向传播
在前面的:全连接神经网络——前向传播中我们已经实现了神经网络的前向计算
这里就不过多介绍了,我们直接上代码:
import torch
import torch.nn as nn
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.layer=nn.Sequential(
nn.Linear(3*28*28,256),
nn.ReLU(),
nn.Linear(256,64),
nn.ReLU(),
nn.Linear(64, 10),
nn.Softmax(dim=1)
)
#前向传播
def forward(self,x):
return self.layer(x)#这里是返回前向计算的输出
if __name__ == '__main__':
net=Net()
x=torch.randn(2,3*28*28)
y=net.forward(x)
print(y.shape)#torch.Size([2, 10])
2.损失计算
在:深度学习——损失函数这篇文章中我们也得到了两种不同的损失函数,接下来,我们就将利用前向计算所得到损失函数进行反向传播,去修正我们的权值。前面前向计算得到两个10分类的概率分布,这时我们将前向传播的结果和标签(真实值做对比)求损失。
这里就不过多介绍了,我们直接上代码(这里用到的是MSE损失):
net=Net()
x=torch.randn(2,3*28*28)
y=net.forward(x)
print(y.shape)#torch.Size([2, 10])
loss_fun=nn.MSELoss()#构造损失函数
target = torch.zeros(2,10)
target[0:2,random.randrange(10)] = 1 # 定义标签,torch.Size([2, 10])
loss=loss_fun(y,target)
print(loss)
3.反向传播
如果,在输出层输出的数据和我们设定的目标以及标准相差比较大(损失函数较大),这个时候,就需要反向传播。利用反向传播,逐层求出目标函数对各神经元权值的偏导数(利用链式法则)。
构成目标函数对权值向量的梯度,之所以算这个,是为了对权值的优化提供依据(梯度下降的思想),等权值优化了之后,再转为正向传播……当输出的结果达到设定的标准时(损失函数足够低),算法结束。
反向传播的原理:(1)链式求导法则 (2)梯度下降
链式求导法则:
我们以逻辑回归的神经元为例子:
显然,在这神经元当中:
最后,这个线性方程z会被代入到Sigmoid函数当中,也就是说:
计算之后都会产生一定的损失值,我们把这个损失函数记为loss(a:输出,A:标签):
反向传播的最终目的是修正权值w,那么我们让loss对w求偏导,根据链式准则:
(公式0)
正向传播与反向传播其实是同时使用的。首先,你需要正向传播,来计算z对w的偏导,进而求出sigmoid(z)是多少。然后,根据输出层输出的数据进行反向传播,计算出loss对z的偏导是多少,最后,代入到(公式0)当中,即可求出loss对w的偏导是多少。注意,这个偏导,其实反应的就是梯度。然后我们利用梯度下降法,对这个w不断进行迭代(也就是权值优化的过程),使得损失函数越来越小,整体模型也越来越接近于真实值。
代码示例:
opt = optim.Adam(net.parameters())
opt.zero_grad()#梯度清空
loss.backward()#反向传播
opt.step()