PyTorch_自动微分模块

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


梯度基本计算

使用 backward 方法,grad 属性来实现梯度的计算和访问。

import torch 
import numpy as np 

# 标量的梯度计算
def test01():
    # 对于需要求导的张量,需设置 requires_grad = True
    x = torch.tensor(10, requires_grad=True, dtype=torch.float64)

    # 对 x 的中间计算
    f = x ** 2 + 20  # 求导获得 2x

    # 自动微分
    f.backward()

    # 访问梯度
    print(x.grad)


# 向量的梯度计算
def test02():
    x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)

    # 定义变量的计算过程
    y1 = x ** 2 + 20 

    # 注意:自动微分的时候,必须是一个标量
    y2 = y1.mean()  # 对 y1 / 4 的操作

    # 自动微分,求导
    y2.backward()


    print(x.grad)

# 多标量梯度计算
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.backward()

    # 打印梯度值
    print(x1.grad)
    print(x2.grad)


# 多向量的梯度计算
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 

    # 将输出结果变为标量
    y = y.sum()

    # 自动微分
    y.backward()

    # 打印张量的梯度值
    print(x1.grad)
    print(x2.grad)

if __name__ == "__main__":
    test04() 

控制梯度计算

当 requires_grad = True 时,张量在某些时候计算不进行梯度计算。

import torch 
import numpy as np 

# 控制梯度计算
# 训练时才用到梯度计算
def test01():
    x = torch.tensor(10, requires_grad=True, dtype=torch.float64)
    print(x.requires_grad)

    # 1. 第一钟方法
    with torch.no_grad():
        y = x**2
    print(y.requires_grad)

    #2. 针对函数
    # 第二种方式
    @torch.no_grad()
    def my_func(x):
        return x ** 2 

    y = my_func(x)
    print(y.requires_grad)

    #3. 第三种方式: 全局的方式
    torch.set_grad_enabled(False)
    y = x ** 2 
    print(y.requires_grad)

# 梯度累加和梯度清零
def test02():
    x = torch.tensor([10, 20, 30, 40], requires_grad=True, dtype=torch.float64)

    # 当我们重复对x进行梯度计算的时候,是会将历史的梯度值累加到 x.grad 属性中
    # 不要取累加历史梯度
    for _ in range(3):
        # 对输入x的计算过程
        f1 = x ** 2 + 20
        # 将向量转换为标量
        f2 = f1.mean()
        # 梯度清零
        if x.grad is not None:
            x.grad.data.zero_()

        # 自动微分
        f2.backward()
        print(x.grad)

# 梯度下降优化函数
def test03():
    x = torch.tensor(10, requires_grad=True, dtype=torch.float64)

    for _ in range(100):
        # 正向计算
        y = x ** 2

        # 梯度清零
        if x.grad is not None:
            x.grad.data.zero_()
        
        # 自动微分
        y.backward()

        # 更新参数
        x.data = x.data - 0.001 * x.grad 

        # 打印 x 的值
        print('%.10f' % x.data)


if __name__ == "__main__":
    test03() 


梯度计算注意点

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

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

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

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

import torch 
import numpy as np 

# 错误方式
def test01():
    x = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)

    # RuntimeError: Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
    # print(x.numpy())

    # 正确的做法
    print(x.detach().numpy())


# 共享数据
def test02():
    # x 是叶子节点
    x1 = torch.tensor([10, 20], requires_grad=True, dtype=torch.float64)

    # 使用 detach 函数来分离出一个新的张量
    x2 = x1.detach()

    print(id(x1.data), id(x2.data))

    # 修改分离后产生的新的张量
    x2[0] = 100 

    print(x1)
    print(x2)

    # 通过结果我么发现,x2 张量不存在 requires_grad = True 
    # 表示:对 x1 的任何计算都会影响到对 x1 的梯度计算
    # 但是,对 x2 的任何计算不会影响到 x1 的梯度计算

    print(x1.requires_grad)
    print(x2.requires_grad)

if __name__ == "__main__":
    test02() 

### PyTorchPyTorch Lightning 的区别及应用场景 #### 功能差异 PyTorch 是一个灵活而强大的开源机器学习库,主要用于深度学习研究和开发工作。它提供了张量计算功能以及自动微分机制,允许开发者构建并训练神经网络模型。 相比之下,PyTorch Lightning 则是在 PyTorch 基础上建立的一个轻量级封装框架[^1]。该框架旨在简化实验流程中的重复性代码编写过程,使研究人员能够专注于核心算法实现而非基础设施建设。具体来说: - **抽象层次更高**:通过定义 `LightningModule` 类来替代原始的 PyTorch 模型类,在其中实现了诸如优化器配置、前向传播逻辑等功能模块化处理; - **内置最佳实践支持**:提供了一系列预设选项用于加速调试周期(如梯度裁剪)、提升性能表现(分布式训练集成)等; - **易于扩展维护**:遵循面向对象编程原则设计而成的应用程序结构更加清晰易懂,便于团队协作和技术债务管理。 ```python import pytorch_lightning as pl from torch.utils.data import DataLoader, random_split from torchvision.datasets import MNIST from torchvision.transforms import ToTensor class LitModel(pl.LightningModule): def __init__(self): super().__init__() self.layer_1 = ... def forward(self, x): return self.layer_1(x) def training_step(self, batch, batch_idx): ... def configure_optimizers(self): optimizer = torch.optim.Adam(...) scheduler = torch.optim.lr_scheduler.StepLR(optimizer, ...) return [optimizer], [scheduler] dataset = MNIST('', train=True, download=True, transform=ToTensor()) train_loader = DataLoader(dataset) model = LitModel() trainer = pl.Trainer(max_epochs=3) trainer.fit(model, train_loader) ``` 上述代码展示了如何利用 PyTorch Lightning 创建一个简单的卷积神经网络,并完成其训练过程。可以看到相比于纯 PyTorch 实现方式减少了大量样板代码书写负担的同时还增强了可读性和移植性。 #### 使用场景对比 对于个人项目或是小型科研任务而言,如果追求极致灵活性并且愿意投入更多时间精力去定制细节,则可以选择直接基于原生 API 进行开发。然而当面临大型工程项目时,考虑到长期迭代更新需求以及多人合作环境因素的影响下,采用 PyTorch Lightning 可以为整个研发周期带来显著效率增益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值