刘二大人《PyTorch深度学习实践》反向传播

该文介绍了如何使用PyTorch进行线性模型y=wx和二次模型y=w1x^2+w2x+b的拟合,通过梯度下降法优化权重,利用反向传播计算梯度,并展示了训练过程中的损失函数变化。文章强调了在动态计算图中正确处理张量和梯度的重要性。
摘要由CSDN通过智能技术生成

 

 输入为x_1,x_2,x_3,x_4,x_5,每个圆圈为一个神经元,连接神经元之间的线对应不同的权值,所以从输入到第一个隐藏层h_1(hidden layer)共有5*6=30个权值如下图

\begin{bmatrix} h_1 \\ h_2 \\ h_3 \\ h_4 \\ h_5 \\ h_6 \end{bmatrix}=W\begin{bmatrix}x_1 \\ x_2 \\ x_3 \\ x_4 \\ x_5 \end{bmatrix} w为6*5的矩阵

整个函数的解析式不容易直接写出,所以直接端到端的求\frac{\partial loss}{\partial w}很困难,故使用链式法则反向传播导数,最终\frac{\partial loss}{\partial w}=\frac{\partial loss}{\partial f}\frac{\partial f}{\partial w}

对于矩阵的求导,cookbook有现成的公式,pytorch也有现成的函数调用

\hat{y}=W_2(W_1\cdot X+b_1)+b_2,计算图(Computational Graph)如下

 发现函数可以简化如下

\hat{y}=W_2(W_1\cdot X+b_1)+b_2\\=W_2\cdot W_1\cdot X+(W_2b_1+b_2)\\=W\cdot X+b

y的计算公式可简化,对于这种线性变换不管多少层都可以简化,这样模型的复杂度不够高,中间的权重没有意义,所有在每一层的输出都要加一层非线性的变化函数(激活函数sigmoid relu)如\frac{1}{1+e^{-x}}

 

Tensor是pytorch里存数据的东西,包含两个数据类型data,grad(导数),可以是数值、向量、矩阵

构建模型就是构建一个计算图

①先计算整个模型的损失(前向传播forward)
②反向传播backward,得到梯度值
③对权重进行更新
pytorch框架的backward()相当于把梯度计算函数(对loss函数进行求导,以及多层嵌套函数的求导链式法则)给提前封装好进行调用了

因此在实际应用中使用梯BP算法,我们只需要根据实际问题定义好损失函数即可
 

写一个使用pytorch拟合y=wx 并画图,使用SGD

import matplotlib.pyplot as plt
import torch


x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]

#随机梯度下降拟合y=wx

w = torch.Tensor([1.0])  #初始权值为1,设置为Tensor类型
w.requires_grad=True #设置w需要反向传播

a=0.01 #学习率为0.01

def forward(x):     #求当前权值下预测值
    return x*w   #运算符重载


def loss(x,y):    ##求单个点的loss值
    y_pred=forward(x)
    return (y_pred-y)**2


epoch_list=[]
cost_list=[]
print('predict(before training)','x=4 y=',forward(4).item())  ###训练前对x=4.0的y值预测

for epoch in range(100):
    for x,y in zip(x_data,y_data):
        loss_val=loss(x,y)  #一个点求loss
        loss_val.backward() #自动反向传播,自动求计算图需要求梯度的权值,并存到w.grad中,并释放计算图
        print('\tgrad:',x,y,w.grad.item())
        w.data=w.data-a*w.grad.data  #更新权值,要加data,不然又创建计算图了
        w.grad.data.zero_() #梯度清零

    print('epoch:',epoch,'w=',w.item(),'loss=',loss_val.item())
    epoch_list.append(epoch)
    cost_list.append(loss_val.item()) #一轮中最后一个样本的loss


print('predict(after training)','x=4 y=',forward(4).item())  ###训练后对x=4.0的y值预测

plt.plot(epoch_list,cost_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()


if __name__ == "__main__":
    main()

 

 

每调用一次loss函数,就构造一次计算图

调用backward()自动计算计算图里的梯度即反向传播,然后释放计算图(动态计算图) 

构建计算图时直接使用张量,权重w更新的时候使用.data,不能直接使用张量,否则创建新的计算图(不要在释放后用tensor直接计算,会构建新的计算图,要用item()标量)

最后w.grad.data.zero_()把梯度清零,避免影响下一次计算结果 

写一个使用pytorch拟合y=w1x ^2+w2x+b 

import matplotlib.pyplot as plt
import torch
from mpl_toolkits.mplot3d import Axes3D

x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]

#随机梯度下降拟合y=w1x^2+w2x+b

w1 = torch.Tensor([1.0])  #初始权值为1,设置为Tensor类型
w2 = torch.Tensor([1.0])
b = torch.Tensor([1.0])

w1.requires_grad=True #设置w1需要反向传播更新
w2.requires_grad=True #设置w2需要反向传播更新
b.requires_grad=True #设置b需要反向传播更新

a=0.001 #学习率为0.001

def forward(x):     #求当前权值下预测值
    return x**2*w1+x*w2+b                  #运算符重载

def loss(x,y):    ##求单个点的loss值
    y_pred=forward(x)
    return (y_pred-y)**2

epoch_list=[]
cost_list=[]
print('predict(before training)','x=4 y=',forward(4).item())  ###训练前对x=4.0的y值预测

for epoch in range(100):
    for x,y in zip(x_data,y_data):
        loss_val=loss(x,y)  #一个点求loss
        loss_val.backward() #自动反向传播,自动求计算图需要求梯度的权值,并存到w.grad中,并释放计算图
        print('\tgrad:',x,y,w1.grad.item(),w2.grad.item(),b.grad.item())
        w1.data=w1.data-a*w1.grad.item()  #更新权值,要加data,不然又创建计算图了
        w2.data=w2.data-a*w2.grad.item()
        b.data=b.data-a*b.grad.item()
        w1.grad.data.zero_() #梯度清零
        w2.grad.data.zero_()
        b.grad.data.zero_()

    print('epoch:',epoch,'loss=',loss_val.item())
    epoch_list.append(epoch)
    cost_list.append(loss_val.item()) #一轮中最后一个样本的loss


print('predict(after training)','x=4 y=',forward(4).item())  ###训练后对x=4.0的y值预测

plt.plot(epoch_list,cost_list)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.show()


if __name__ == "__main__":
    main()

 

.data(a) 

将变量a变为tensor,将requires_grad设置为Flase

a.item()

Tensor类型的变量a转换成float类型

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值