一、反向传播(Back Propogation)原理

为了提高模型的复杂程度,即不能够让其叠加后还能展开成线性函数,需要在每层神经网络后都加上一个非线性的函数(激活函数)。损失函数loss对权重w的导数可以通过前向传播存储的子节点梯度相乘得到,即链式法则。
​​Alt

二、PyTorch实现反向传播

PyTorch的基本数据类型:Tensor(张量、向量、矩阵);Tensor包含两个数据成员:data(权重本身的值);grad(损失函数对权重的导数)。如果要取数据成员的标量(即数值),用w.data.item()或者w.grad.item()

当满足以下两个条件时,Tensor可以实现自动计算梯度的功能:

  • is_leaf = True
    is_leaf表示将参数设置成叶子节点,将其计算得到的梯度值保存下来。默认为True。在反向传播中,如果明确不需要保存的中间变量的梯度,可以令is_leaf = False,这样能减少内存占用。
  • requires_grad = True
    是否自动计算梯度,默认是False,需要声明。

前向传播,即l = loss(x, y)时会构造计算图。在传播过程中,只有requires_grad设置为True的时候才能得到梯度,例如代码中的w.grad

计算图在进行一次反向传播后会被释放,重新再执行backward()会报错。而计算图中的叶子结点的梯度信息会被存储grad中,所以在本文中,每次进行反向传播之前,都要使用zero_grad()进行梯度清零;否则,grad会自动更新为两次的梯度之和。

参考文章:关于Pytorch中tensor的自动梯度求导与反向传播的理解

代码

import torch
import matplotlib.pyplot as plt

#1.training set
x_data = [1.0,2.0,3.0,4.0]
y_data = [2.0,4.0,6.0,8.0]

#2.initial_w 
w = torch.Tensor([1.0])
#需要计算梯度
w.requires_grad = True

#3.定义函数
def forward(x):
    return x * w

def loss(x, y):
    y_pred = forward(x)
    return (y_pred - y) ** 2
    
print("Predict (Before Training):", 4, forward(4).item())
#w是tensor,所以相乘得到的forward(x)也是tensor,取其值时需要用item()将其转换成标量

#4.记录迭代数值
epoch_list = []
loss_list = []

#5.迭代
for epoch in range(100):
    for x, y in zip(x_data, y_data): #遍历每一组数据
        l = loss(x, y) #先把从w到loss的流程走一遍,相当于前向传播
        l.backward() #反向传播,程序会自动求出所需要的梯度
        print('\tgrad:', x, y, w.grad.item()) #梯度值
        w.data = w.data - 0.01 * w.grad.data #更新权重w
        w.grad.data.zero_() #梯度值清零
        
    epoch_list.append(epoch)
    loss_list.append(l.data)  #l.data的类型是tensor
    
    print("progress:", epoch, l.item()) #输出最后一组数据的损失值
print("Predict (After Training)", 4, forward(4).item())

plt.plot(epoch_list, loss_list)
plt.ylabel("loss")
plt.xlabel("epoch")
plt.show()

运行结果

Alt
Alt

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐