PyTorch使用自动微分模块的方法和理解

 更新时间:2024年09月23日 15:15:54   作者:小言从不摸鱼  
自动微分模块Autograd为张量增加了自动求导功能,是神经网络训练不可或缺的组成部分,通过backward方法和grad属性,实现梯度的计算和访问,本小节主要讲解了 PyTorch 中非常重要的自动微分模块的使用和理解,感兴趣的朋友一起看看吧

自动微分(Autograd)模块对张量做了进一步的封装,具有自动求导功能。自动微分模块是构成神经网络训练的必要模块,在神经网络的反向传播过程中,Autograd 模块基于正向计算的结果对当前的参数进行微分计算,从而实现网络权重参数的更新。

🍔 梯度基本计算

我们使用 backward 方法、grad 属性来实现梯度的计算和访问.

import torch

1.1 单标量梯度的计算

   
 # y = x**2 + 20
    def test01():
    # 定义需要求导的张量
    # 张量的值类型必须是浮点类型
    x = torch.tensor(10, requires_grad=True, dtype=torch.float64)
    # 变量经过中间运算
    f = x ** 2 + 20
    # 自动微分
    f.backward()
    # 打印 x 变量的梯度
    # backward 函数计算的梯度值会存储在张量的 grad 变量中
    print(x.grad)

1.2 单向量梯度的计算

# y = x**2 + 20
def test02():
    # 定义需要求导张量
    x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)
    # 变量经过中间计算
    f1 = x ** 2 + 20
    # 注意:
    # 由于求导的结果必须是标量
    # 而 f 的结果是: tensor([120., 420.])
    # 所以, 不能直接自动微分
    # 需要将结果计算为标量才能进行计算
    f2 = f1.mean()  # f2 = 1/2 * x
    # 自动微分
    f2.backward()
    # 打印 x 变量的梯度
    print(x.grad)

1.3 多标量梯度计算

# y = x1 ** 2 + x2 ** 2 + x1*x2
def test03():
    # 定义需要计算梯度的张量
    x1 = torch.tensor(10, requires_grad=True, dtype=torch.float64)
    x2 = torch.tensor(20, requires_grad=True, dtype=torch.float64)
    # 经过中间的计算
    y = x1**2 + x2**2 + x1*x2
    # 将输出结果变为标量
    y = y.sum()
    # 自动微分
    y.backward()
    # 打印两个变量的梯度
    print(x1.grad, x2.grad)

1.4 多向量梯度计算

def test04():
    # 定义需要计算梯度的张量
    x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)
    x2 = torch.tensor([30, 40], requires_grad=True, dtype=torch.float64)
    # 经过中间的计算
    y = x1 ** 2 + x2 ** 2 + x1 * x2
    print(y)
    # 将输出结果变为标量
    y = y.sum()
    # 自动微分
    y.backward()
    # 打印两个变量的梯度
    print(x1.grad, x2.grad)
if __name__ == '__main__':
    test04()

1.5 运行结果💯

tensor(20., dtype=torch.float64)
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
tensor(40., dtype=torch.float64) tensor(50., dtype=torch.float64)
tensor([1300., 2800.], dtype=torch.float64, grad_fn=<AddBackward0>)
tensor([50., 80.], dtype=torch.float64) tensor([ 70., 100.], dtype=torch.float64)

🍔 控制梯度计算

我们可以通过一些方法使得在 requires_grad=True 的张量在某些时候计算不进行梯度计算。

import torch

2.1 控制不计算梯度

def test01():
    x = torch.tensor(10, requires_grad=True, dtype=torch.float64)
    print(x.requires_grad)
    # 第一种方式: 对代码进行装饰
    with torch.no_grad():
        y = x ** 2
    print(y.requires_grad)
    # 第二种方式: 对函数进行装饰
    @torch.no_grad()
    def my_func(x):
        return x ** 2
    print(my_func(x).requires_grad)
    # 第三种方式
    torch.set_grad_enabled(False)
    y = x ** 2
    print(y.requires_grad)

2.2 注意: 累计梯度

def test02():
    # 定义需要求导张量
    x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)
    for _ in range(3):
        f1 = x ** 2 + 20
        f2 = f1.mean()
        # 默认张量的 grad 属性会累计历史梯度值
        # 所以, 需要我们每次手动清理上次的梯度
        # 注意: 一开始梯度不存在, 需要做判断
        if x.grad is not None:
            x.grad.data.zero_()
        f2.backward()
        print(x.grad)

2.3 梯度下降优化最优解

def test03():
    # y = x**2
    x = torch.tensor(10, requires_grad=True, dtype=torch.float64)
    for _ in range(5000):
        # 正向计算
        f = x ** 2
        # 梯度清零
        if x.grad is not None:
            x.grad.data.zero_()
        # 反向传播计算梯度
        f.backward()
        # 更新参数
        x.data = x.data - 0.001 * x.grad
        print('%.10f' % x.data)
if __name__ == '__main__':
    test01()
    test02()
    test03()

2.4 运行结果💯

True
False
False
False
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
tensor([ 5., 10., 15., 20.], dtype=torch.float64)
tensor([ 5., 10., 15., 20.], dtype=torch.float64)

🍔 梯度计算注意

当对设置 requires_grad=True 的张量使用 numpy 函数进行转换时, 会出现如下报错:

Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.

此时, 需要先使用 detach 函数将张量进行分离, 再使用 numpy 函数.

注意: detach 之后会产生一个新的张量, 新的张量作为叶子结点,并且该张量和原来的张量共享数据, 但是分离后的张量不需要计算梯度。

import torch

3.1 detach 函数用法

def test01():
    x = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)
    # Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
    # print(x.numpy())  # 错误
    print(x.detach().numpy())  # 正确

3.2 detach 前后张量共享内存

def test02():
    x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)
    # x2 作为叶子结点
    x2 = x1.detach()
    # 两个张量的值一样: 140421811165776 140421811165776
    print(id(x1.data), id(x2.data))
    x2.data = torch.tensor([100, 200])
    print(x1)
    print(x2)
    # x2 不会自动计算梯度: False
    print(x2.requires_grad)
if __name__ == '__main__':
    test01()
    test02()

3.3 运行结果💯

10. 20.]
140495634222288 140495634222288
tensor([10., 20.], dtype=torch.float64, requires_grad=True)
tensor([100, 200])
False

🍔 小节

本小节主要讲解了 PyTorch 中非常重要的自动微分模块的使用和理解。我们对需要计算梯度的张量需要设置 requires_grad=True 属性,并且需要注意的是梯度是累计的,在每次计算梯度前需要先进行梯度清零。

到此这篇关于PyTorch使用自动微分模块的文章就介绍到这了,更多相关PyTorch自动微分模块内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • 解决keras GAN训练是loss不发生变化,accuracy一直为0.5的问题

    解决keras GAN训练是loss不发生变化,accuracy一直为0.5的问题

    这篇文章主要介绍了解决keras GAN训练是loss不发生变化,accuracy一直为0.5的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • python先序遍历二叉树问题

    python先序遍历二叉树问题

    这篇文章主要介绍了python先序遍历二叉树问题,简单分析了问题,然后向大家分享了代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Django创建一个后台的基本步骤记录

    Django创建一个后台的基本步骤记录

    这篇文章主要给大家介绍了关于Django创建一个后台的基本步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • 用Q-learning算法实现自动走迷宫机器人的方法示例

    用Q-learning算法实现自动走迷宫机器人的方法示例

    这篇文章主要介绍了用Q-learning算法实现自动走迷宫机器人的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • python面向对象 反射原理解析

    python面向对象 反射原理解析

    这篇文章主要介绍了python面向对象 反射原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • NumPy 数学函数及代数运算的实现代码

    NumPy 数学函数及代数运算的实现代码

    这篇文章主要介绍了NumPy 数学函数及代数运算的实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Python yield 的使用浅析

    Python yield 的使用浅析

    这篇文章主要为大家详细介绍了Python yield的使用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • Python字符串模糊匹配工具TheFuzz的用法详解

    Python字符串模糊匹配工具TheFuzz的用法详解

    在处理文本数据时,常常需要进行模糊字符串匹配来找到相似的字符串,Python的TheFuzz库提供了强大的方法用于解决这类问题,本文将深入介绍TheFuzz库,探讨其基本概念、常用方法和示例代码,需要的朋友可以参考下
    2023-12-12
  • 详解解决jupyter不能使用pytorch的问题

    详解解决jupyter不能使用pytorch的问题

    这篇文章主要介绍了详解解决jupyter不能使用pytorch的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • Python生成器generator和yield关键字的使用

    Python生成器generator和yield关键字的使用

    生成器是一种特殊的迭代器,可以通过列表推导式的修改或者使用yield关键字来创建,生成器函数能够在迭代时动态产生值,而不是一次性生成所有值,这有助于节省内存,yield关键字使函数执行暂停并保存当前状态,下次调用时从停止处继续执行
    2024-09-09

最新评论