详解Pytorch自动求导机制

 更新时间:2023年07月19日 08:31:18   作者:山河亦问安  
自动求导是一种计算梯度的技术,它允许我们在定义模型时不需要手动推导梯度计算公式,PyTorch 提供了自动求导的功能,使得梯度的计算变得非常简单和高效,这篇文章主要介绍了Pytorch自动求导机制详解,需要的朋友可以参考下

1. 自动求导

在深度学习中,我们通常需要训练一个模型来最小化损失函数。这个过程可以通过梯度下降等优化算法来实现。梯度是函数在某一点上的变化率,可以告诉我们如何调整模型的参数以使损失函数最小化。自动求导是一种计算梯度的技术,它允许我们在定义模型时不需要手动推导梯度计算公式。PyTorch 提供了自动求导的功能,使得梯度的计算变得非常简单和高效。

PyTorch是动态图,即计算图的搭建和运算是同时的,随时可以输出结果。在pytorch的计算图里只有两种元素:数据(tensor)和 运算(operation)。

运算包括了:加减乘除、开方、幂指对、三角函数等可求导运算。

数据可分为:叶子节点(leaf node)和非叶子节点;叶子节点是用户创建的节点,不依赖其它节点;它们表现出来的区别在于反向传播结束之后,非叶子节点的梯度会被释放掉,只保留叶子节点的梯度,这样就节省了内存。如果想要保留非叶子节点的梯度,可以使用retain_grad()方法。

torch.tensor 具有如下属性:

  • 查看 是否可以求导 requires_grad
  • 查看 运算名称 grad_fn
  • 查看 是否为叶子节点 is_leaf
  • 查看 导数值 grad

针对requires_grad属性,自己定义的叶子节点默认为False,而非叶子节点默认为True,神经网络中的权重默认为True。判断哪些节点是True/False的一个原则就是从你需要求导的叶子节点到loss节点之间是一条可求导的通路。当我们想要对某个Tensor变量求梯度时,需要先指定requires_grad属性为True,指定方式主要有两种:

x = torch.tensor(1.).requires_grad_() # 第一种
x = torch.tensor(1., requires_grad=True) # 第二种

总结: 

(1)torch.tensor()设置requires_grad关键字参数

(2)查看tensor是否可导,x.requires_grad 属性

(3)设置叶子变量 leaf variable的可导性,x.requires_grad_()方法

(4)自动求导方法 y.backward() ,直接调用backward()方法,只会计算对计算图叶节点的导数。

(5)查看求得的到数值, x.grad 属性

1.1 梯度计算

自动求导的核心是反向传播算法(Backpropagation)。反向传播算法是一种高效地计算梯度的方法,它使用链式法则计算每个可导操作的梯度,然后利用这些梯度更新参数。一旦我们创建了可导张量,PyTorch 将会自动追踪所有涉及这些张量的操作,并构建一个计算图。计算图是一个有向无环图,表示了计算过程中张量之间的依赖关系。

1.1.1 一阶导数

然后我们举个例子:z=w*x+b

import torch
x=torch.tensor(1.,requires_grad=True)
b=torch.tensor(2.,requires_grad=True)
w=torch.tensor(3.,requires_grad=True)
z=w*x+b
z.backward()#反向传播
print(x.grad)#x导数值
print(w.grad)#w导数值
print(b.grad)#b导数值

运行结果如下图:

要想使上面的x,b,w支持求导,必须让它们为浮点类型,也就是我们给初始值的时候要加个点:“.”。不然的话,就会报错。 

 1.1.2 二阶导数

import torch
x = torch.tensor(2.).requires_grad_()
y = torch.tensor(3.).requires_grad_()
z = x * x * y
z.backward(create_graph=True) # x.grad = 12
print(x.grad)
x.grad.data.zero_() #PyTorch使用backward()时默认会累加梯度,需要手动把前一次的梯度清零
x.grad.backward() #对x一次求导后为2xy,然后再次反向传播
print(x.grad)

运行结果如下图:

 1.1.3 向量

在pytorch里面,默认:只能是【标量】对【标量】,或者【标量】对向【量/矩阵】求导

在深度学习中在求导的时候是对损失函数求导,损失函数一般都是一个标量,参数又往往是向量或者是矩阵。

比如有一个输入层为3节点的输入层,输出层为一个节点的输出层,这样一个简单的神经网络,针对一组样本而言,有

X=(x1,x2,x3)=(1.5,2.5,3.5),X是(1,3)维的,输出层的权值矩阵为W=(w1,w2,w3)W=(0.2,0.4,0.6)T,这里表示初始化的权值矩阵,T表示转置,则W表示的是(3,1)维度,偏置项为b=0.1,是一个标量,则可以构建一个模型如下:

Y=XW+b,其中W,b就是要求倒数的变量,这里Y是一个标量,W是向量,b是标量,W,b是叶节点。

将上面展开得到:

Y=x1*w1+x2*w2*x3*w3+b   

import torch
# 创建一个多元函数,即Y=XW+b=Y=x1*w1+x2*w2*x3*w3+b,x不可求导,W,b设置可求导
X = torch.tensor([1.5, 2.5, 3.5], requires_grad=False)
W = torch.tensor([0.2, 0.4, 0.6], requires_grad=True)
b = torch.tensor(0.1, requires_grad=True)
Y = torch.add(torch.dot(X, W), b)
# 求导,通过backward函数来实现
Y.backward()
# 查看导数,也即所谓的梯度
print(W.grad)
print(b.grad)

运行截图如下:

 1.2 线性回归实战

定义一个y=2*x+1线性方程,下面是一个使用 PyTorch 实现线性回归模型,并利用自动求导训练模型的示例:

 
import torch
import numpy as np
import torch.nn as nn
import torch.optim as optim
x_values=[i for i in range(11)]
x_train=np.array(x_values,dtype=np.float32)
x_train=x_train.reshape(-1,1)
y_values=[2*i +1 for i in x_values]
y_values=np.array(y_values,dtype=np.float32)
y_train=y_values.reshape(-1,1)
#这里线性回归就相当于不加激活函数的全连接层
class LinearRegression(nn.Module):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.linear = nn.Linear(1, 1)
    def forward(self, x):
        return self.linear(x)
#使用GPU训练
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 创建模型实例和优化器
model = LinearRegression()
model.to(device)
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 定义损失函数
criterion = nn.MSELoss()
for epoch in range(100):
    # 创建数据集
    inputs = torch.from_numpy(x_train).to(device)
    targets = torch.from_numpy(y_train).to(device)
    # 前向传播
    outputs = model(inputs)
    loss = criterion(outputs, targets)
    # 反向传播和优化器更新
    #梯度清零每一次迭代
    optimizer.zero_grad()
    #反向传播
    loss.backward()
    #更新权重参数
    optimizer.step()
    #每10轮,打印一下损失函数
    if epoch%10==0:
        print("epoch {}, loss {}".format(epoch,loss.item()))
#使用训练完的模型进行数据的预测
predicted=model(torch.from_numpy(x_train).to(device))
print(predicted)
print(targets)

在上面的例子中,我们首先创建了一个简单的线性回归模型 LinearRegression,并创建了一个包含11个样本的数据集。然后,我们定义了损失函数 criterion 和优化器 optimizer,并在训练循环中进行模型训练。

模型训练中损失值变化如下:

 在模型中预测结果和标签值对比如下图:上面的为模型预测结果,下面的为标签值

到此这篇关于Pytorch自动求导机制详解的文章就介绍到这了,更多相关Pytorch自动求导内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python使用tkinter实现屏幕中间倒计时

    python使用tkinter实现屏幕中间倒计时

    这篇文章主要为大家详细介绍了python使用tkinter实现屏幕中间倒计时,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • Python图像运算之图像掩膜直方图和HS直方图详解

    Python图像运算之图像掩膜直方图和HS直方图详解

    这篇文章将为大家详细讲解图像掩膜直方图和HS直方图,并分享一个通过直方图判断白天与黑夜的案例。文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2022-08-08
  • Flask搭建Web应用程序的方法示例

    Flask搭建Web应用程序的方法示例

    Flask是一个使用Python编写的轻量级Web应用框架,本文我们将介绍一个使用Flask逐步搭建Web应用程序的简单入门示例,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-01-01
  • jupyter notebook 实现matplotlib图动态刷新

    jupyter notebook 实现matplotlib图动态刷新

    这篇文章主要介绍了jupyter notebook 实现matplotlib图动态刷新,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-04-04
  • pycharm安装深度学习pytorch的d2l包失败问题解决

    pycharm安装深度学习pytorch的d2l包失败问题解决

    当新生在学习pytorch时,导入d2l_pytorch包总会遇到问题,下面这篇文章主要给大家介绍了关于pycharm安装深度学习pytorch的d2l包失败问题的解决方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-03-03
  • 如何在Flask中实现数据分组流程详解

    如何在Flask中实现数据分组流程详解

    在Flask中,数据分组是指将一组数据按照某种方式进行分类,以便更好地对数据进行处理和展示,可以使用Python内置的itertools模块中的groupby方法,或者使用SQL语句中的GROUP BY子句来实现数据分组,这篇文章介绍了在Flask中实现数据分组,感兴趣的同学可以参考下文
    2023-05-05
  • pyqt5+opencv 实现读取视频数据的方法

    pyqt5+opencv 实现读取视频数据的方法

    这篇文章主要介绍了pyqt5+opencv 实现读取视频数据的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-01-01
  • 使用Python实现租车计费系统的两种方法

    使用Python实现租车计费系统的两种方法

    本文通过两种方法给大家分享了使用Python实现租车计费系统,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-09-09
  • 深入理解Python3 内置函数大全

    深入理解Python3 内置函数大全

    本篇文章主要介绍了Python3 内置函数,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • Python中new方法的详解

    Python中new方法的详解

    今天小编就为大家分享一篇关于Python中new方法的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01

最新评论