2、PyTorch 简介


一、PyTorch 简介

在这里插入图片描述在这里插入图片描述

1.1、PyTorch 模块

ComponentDescription
torchA Tensor library like NumPy, with strong GPU support
torch.utilsDataLoader and other utility functions for convenience
torch.nnA neural networks library deeply integrated with autograd designed for maximum flexibility
torch.autogradA tape-based automatic differentiation library that supports all differentiable Tensor operations in torch
torch.multiprocessingPython multiprocessing, but with magical memory sharing of torch Tensors across processes. Useful for data loading and Hogwild training
torch.jitA compilation stack (TorchScript) to create serializable and optimizable models from PyTorch code

1.2、PyTorch 计算图

1.2.1、静态计算图

老版的TensorFlow 使用静态图(提前创建好) 来表示计算任务,由节点和边组成,节点表示 Tensor 或者 op(运算符),边表示 Tensor 和 op 之间的依赖关系;Tensor 在图中通过运算(op, eg:ADD)进行传递和变换, 一个 op 可以获得 0 个或多个张量(Tensor), 通过创建会话(Session)对象来执行计算,产生 0 个或多个Tensor。所以,TensorFlow 的工作模式分为以下两步:

  • Define the computation graph
  • Run the graph (with data) in Session

为什么需要提前定义好计算图,然后再去执行运算?

  • Save computation:only run subgraphs that lead to the values you want to fetch
  • Facilitate distributed computation: spread the work across multiple CPUs, GPUs, or devices
  • Facilitates auto-differentiation:break computation into small, differential pieces

这里写图片描述


1.2.2、动态计算图

Pytorch 中的计算图是动态图,由节点和边组成,节点表示 Tensor 或者 op(运算符),边表示 Tensor 和 op 之间的依赖关系

  • Tensor 在图中通过运算(op, eg:ADD)进行传递和变换, 一个 op 可以获得 0 个或多个张量(Tensor),通过 op 运算,产生 0 个或多个 Tensor,一般 op 可继承于torch.autograd.Function,同时支持正向传播和反向传播
  • 动态图的正向传播是立即执行得出结果的(方便 Debug),无需等待完整的计算图创建完毕
  • 动态图在反向传播后立即销毁,释放存储空间,下次调用需要重新构建计算图
    • 如果程序中使用了torch.autograd.backward方法执行了反向传播,那么创建的计算图会被立即销毁,下次调用需要重新创建
    • 如果程序中使用了torch.autograd.grad方法计算了梯度,那么创建的计算图会被立即销毁,下次调用需要重新创建
    • 若不想立即销毁,则需指明 retain_graph 参数为 True 来保留计算图

在这里插入图片描述


二、PyTorch 张量系统:torch


三、PyTorch 自动求导机制:torch.autograd

  • torch.autograd 能够根据输入和前向传播过程 自动构建计算图,并自动计算梯度用于反向传播:
    • 每个 Tensor 都有一个 requires_grad 标志,默认为 False,可用于冻结某些层的参数
    • 如果一个节点 requires_grad 被设置为 True,那么计算图中所有依赖它的节点都需要求解梯度
    • 优化器使用 autograd 来计算每个参数的梯度(存储在 tensor.grad 属性中)并进行更新
# requires_grad=False by default
>>> x = torch.randn(5, 5)  
>>> y = torch.randn(5, 5)
>>> z = torch.randn((5, 5), requires_grad=True)
>>> a = x + y
>>> a.requires_grad
False
>>> b = a + z

# 依赖于叶子结点的结点,requires_grad 默认为 True,叶子节点(z)不可执行 in-place 操作
>>> b.requires_grad  
True

在这里插入图片描述

2.1、torch.autograd.backward:自动求取梯度

torch.autograd.backward(tensors, grad_tensors=None, retain_graph=None, create_graph=False, grad_variables=None, inputs=None)

  • tensors(Sequence[Tensor] or Tensor): 用于求导的张量,如 loss
  • grad_tensors(Sequence[Tensor or None] or Tensor, optional):与根节点 loss 形状相同的张量,最终梯度为 loss 求出梯度与 grad_tensors 张量的点积;在 Tensor 的方法中是 gradient 参数
    • 若调用的 loss 是标量(或者 loss 张量通过loss.sum() 转成标量),则可以不提供此参数,默认为 1;有多个 loss 时,若提供该参数则可以看做是各个 loss 的权重
    • 若调用的 loss 是张量,则必须提供与 loss 相同形状的参数
  • retain_graph(bool, optional) :
    • 保持计算图,如果需要多次调用 backward 可设置为 True,但梯度会累加
    • 当有多个输出需要同时进行梯度反传时,需要将其设置为 True,从而保证在计算多个输出的梯度时互不影响
  • create_graph(bool, optional) : 创建导数计算图,用于高阶求导
  • inputs (Sequence[Tensor] or Tensor, optional):输入数据
  • Note: 调用 backward() 方法后,叶子节点的梯度(grad)会在反向传播的过程中累加。所以在梯度进行参数更新后(下一次反向传播前)需要把梯度清零x.grad.zero_() or optimizer.zero_grad()
########################## 0、Tensor 中 backward 方法的定义 ##########################
def backward(self, gradient=None, retain_graph=None, create_graph=False, inputs=None):
    if has_torch_function_unary(self):
        return handle_torch_function(
            Tensor.backward,
            (self,),
            self,
            gradient=gradient,
            retain_graph=retain_graph,
            create_graph=create_graph,
            inputs=inputs,
        )
    torch.autograd.backward(
        self, gradient, retain_graph, create_graph, inputs=inputs
    )



########################## 1、gradient 与 retain_graph 的用法 ##########################
import torch

x = torch.tensor([[0.0, 0.0], [1.0, 2.0]], requires_grad=True)  # x 需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a * torch.pow(x, 2) + b * x + c  # f(x) = a*x**2 + b*x + c

gradient = torch.tensor([[1.0, 1.0], [1.0, 2.0]])
y.backward(gradient=gradient, retain_graph=True)  # 转换成标量来进行反向传播:torch.sum(y*gradient).backward()

print("y_grad:\n", y.grad)  # None, 为了节约存储空间,非叶子节点的梯度均为 None,只在计算过程中被用到,不会最终存储到 grad 属性中
print("x_grad:\n", x.grad)
y.backward(gradient=gradient)
print("x_grad:\n", x.grad)  # retain_graph=True 会出现梯度累积,可在 backward 前执行 x.grad.zero_() 进行梯度清零

# 输出如下
y_grad:
 None
x_grad:
 tensor([[-2., -2.],
        [ 0.,  4.]])
x_grad:  # 梯度未清零造成梯度累积
 tensor([[-4., -4.],
        [ 0.,  8.]])


########################## 2、非叶子节点梯度显示 ##########################
import torch

# 正向传播
x = torch.tensor(3.0, requires_grad=True)
y1 = x + 1
y2 = 2 * x
loss = (y1 - y2) ** 2

# 非叶子节点梯度显示控制
# 1、利用 retain_grad 可以保留非叶子节点的梯度值
# 2、利用 register_hook 可以查看非叶子节点的梯度值(需要定义在 backward 前面),但不会保留其值
y1.register_hook(lambda grad: print('y1.register_hook grad: ', grad))
y2.register_hook(lambda grad: print('y2.register_hook grad: ', grad)) 
y1.retain_grad()  
y2.retain_grad()
loss.retain_grad()

# 反向传播
loss.backward()  # 通过 register_hook 可以查看非叶子节点的梯度值
print("loss.grad:", loss.grad)
print("y1.grad:", y1.grad)
print("y2.grad:", y2.grad)
print("x.grad:", x.grad)

# 输出如下
y2.register_hook grad:  tensor(4.)
y1.register_hook grad:  tensor(-4.)
loss.grad: tensor(1.)  # 若 loss 为高维张量,则输出高维张量 
y1.grad: tensor(-4.)
y2.grad: tensor(4.)
x.grad: tensor(4.)


########################## 3、网络前向传播和反向传播求解梯度,更新参数示例 ##########################
import torch
import torchvision

# 生成数据
data = torch.rand(1, 3, 64, 64)
labels = torch.rand(1, 1000)

# 构建模型
model = torchvision.models.resnet18(weights="ResNet18_Weights.DEFAULT")

# 指定参数学习算法
optimizer = torch.optim.SGD(model.parameters(), lr=1e-2, momentum=0.9)

# 模型训练
for i in range(500):
    # 前向传播 [1, 1000]
    prediction = model(data)

    # 计算 loss:使用 .sum() 方法求和,loss 是一个标量
    loss = (prediction - labels).sum()  # 通常使用 loss = criterion(outputs, labels),返回标量

    # 反向传播 loss:实际调用 torch.autograd.backward 为每个模型参数计算梯度并将其存储在参数的.grad 属性中
    loss.backward()

    # 参数更新:调用 .step() 启动梯度下降,优化器通过.grad 中存储的梯度来调整每个参数
    optimizer.step()

    # 清空梯度:调用 backward 会导致导数值在叶节点处累积,所以将其用于参数更新后,需要将梯度显式清零
    optimizer.zero_grad()
    print("iter {}".format(i))

########################## 4、网络微调示例 ##########################
import torch
import torchvision

# 生成数据
data = torch.rand(1, 3, 64, 64)
labels = torch.rand(1, 10)

# 构建模型
model = torchvision.models.resnet18(weights="ResNet18_Weights.DEFAULT")

for param in model.parameters():
    param.requires_grad = False

# Replace the last fully-connected layer
# Parameters of newly constructed modules have requires_grad=True by default
model.fc = torch.nn.Linear(512, 10)  # 1000-->10 类

# 指定参数学习算法:Optimize only the classifier
optimizer = torch.optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)  # 只更新 fc 层进行 finetune

# 模型训练
for i in range(500):
    # 前向传播 [1, 10]
    prediction = model(data)

    # 计算 loss:使用 .sum() 方法求和,loss 是一个标量
    loss = (prediction - labels).sum()

    # 反向传播 loss:实际调用 torch.autograd.backward 为每个模型参数计算梯度并将其存储在参数的.grad 属性中
    loss.backward()

    # 参数更新:调用 .step() 启动梯度下降,优化器通过.grad 中存储的梯度来调整每个参数
    optimizer.step()

    print("iter {}".format(i))

2.2、torch.autograd.grad:求取梯度

torch.autograd.grad(outputs, inputs, grad_outputs = None, retain_graph = None, create_graph = False)

  • outputs: 用于求导的张量,如 loss,如果有多个因变量,相当于把多个因变量的梯度结果求和
  • inputs : 需要求解梯度的张量,允许同时对多个自变量求导数
  • create_graph : 创建导数计算图,用于高阶求导
  • retain_graph : 保持计算图
  • grad_outputs:多梯度权重
import torch

x = torch.tensor(0.0, requires_grad=True)  # x 需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a * torch.pow(x, 2) + b * x + c  # f(x) = ax**2 + bx + c 

# create_graph 设置为 True 将允许创建更高阶的导数
dy_dx = torch.autograd.grad(y, x, create_graph=True)[0]  # f(x)‘ = 2ax+b
print(dy_dx.data)  # tensor(-2.)

# 求二阶导数
dy2_dx2 = torch.autograd.grad(dy_dx, x)[0]  # f(x)" = 2
print(dy2_dx2.data)  # tensor(2.)

2.3、使用梯度上下文管理器控制自动求导

# torch.no_grad()/torch.set_grad_enabled()/torch.enable_grad() 的上下文管理器可用于控制是否需要自动求导
>>> x = torch.zeros(1, requires_grad=True)
>>> with torch.no_grad():
...     y = x * 2
>>> y.requires_grad
False

>>> is_train = False
>>> with torch.set_grad_enabled(is_train):
...     y = x * 2
>>> y.requires_grad
False

四、PyTorch 层级结构: torch.nn


五、PyTorch 并行:torch.multiprocessing


六、PyTorch 常用工具:torch.utils


七、参考资料

1、https://pytorch.org/
2、https://github.com/pytorch
3、https://github.com/pytorch/pytorch
4、https://pytorch.org/docs/stable/index.html
5、PyTorch 中文文档
6、https://pytorch.apachecn.org/
7、https://github.com/awfssv/pytorch-cn
8、pytorch 多 gpu并行训练
9、Pytorch多机多卡分布式训练
10、https://download.pytorch.org/whl/torch_stable.html

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值