PyTorch学习—4.计算图与动态图机制以及torch.autograd(自动求导系统)

一、计算图与动态图机制

  计算图是用来描述运算的有向无环图。计算图有两个主要元素:结点(Node)和边(Edge)。结点表示数据,如向量,矩阵,张量;边表示运算,如加减乘除卷积等。下面用计算图表示: y = ( x + w ) ∗ ( w + 1 ) y =(x+ w)* (w+1) y=(x+w)(w+1)
在这里插入图片描述
采用计算图描述运算的好处:不仅使得运算更加简洁,而且使得梯度求导更加方便。下面用代码展示上述计算图梯度求导过程:

import torch

# 需要计算梯度-requires_grad=True
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)

# 前向传播
a = torch.add(w, x)     # retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)

# 反向传播-自动求导
y.backward()
print(w.grad)
# 5

由第2节,我们可以知道Tensor中有叶子节点(is_leaf)与grad_fn的概念

叶子结点︰用户创建的结点称为叶子结点,如 x 与 w x与w xw
is_leaf:指示张量是否为叶子结点
为什么要设置叶子节点这一概念?主要是为了节省内存,在梯度反向传播之后,非叶子节点的梯度是会被释放掉的。

import torch

# 需要计算梯度-requires_grad=True
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)

# 前向传播
a = torch.add(w, x)     # retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)

# 反向传播-自动求导
y.backward()
print(w.grad)

# 查看叶子结点
print("is_leaf:\n", w.is_leaf, x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf)

# 查看梯度
print("gradient:\n", w.grad, x.grad, a.grad, b.grad, y.grad)
is_leaf:
 True True False False False
gradient:
 tensor([5.]) tensor([2.]) None None None

如果我们想要保存非叶子节点的梯度,那么应该怎么做呢?

import torch

# 需要计算梯度-requires_grad=True
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)

# 前向传播
a = torch.add(w, x)     
# 保存非叶子节点a的梯度
a.retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)

# 反向传播-自动求导
y.backward()
print(w.grad)

# 查看叶子结点
print("is_leaf:\n", w.is_leaf, x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf)

# 查看梯度
print("gradient:\n", w.grad, x.grad, a.grad, b.grad, y.grad)
tensor([5.])
is_leaf:
 True True False False False
gradient:
 tensor([5.]) tensor([2.]) tensor([2.]) None None

grad_fn:grad_fn:记录创建该张量时所用的方法(函数),是自动求导的关键

import torch

# 需要计算梯度-requires_grad=True
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)

# 前向传播
a = torch.add(w, x)
# 保存非叶子节点a的梯度
a.retain_grad()
b = torch.add(w, 1)
y = torch.mul(a, b)

# 反向传播-自动求导
y.backward()
print(w.grad)

# 查看创建张良所使用的函数
print("grad_fn:\n", w.grad_fn, x.grad_fn, a.grad_fn, b.grad_fn, y.grad_fn)
tensor([5.])
grad_fn:
 None None <AddBackward0 object at 0x0000021BCD8FB710> <AddBackward0 object at 0x0000021BCD900128> <MulBackward0 object at 0x0000021BCD9000F0>
1.静态图与动态图

  根据计算图搭建方式,可将计算图分为静态图与动态图。静态图是先搭建图后运算。静态图的特点:高效不灵活。TensorFlow是静态图。动态图是运算与搭建同时进行。动态图的特点:灵活易调节。PyTorch是动态图。

二、torch.autograd—自动求导系统

  深度学习模型的训练就是不断更新权值。权值的更新需要求解梯度。PyTorch提供自动求导系统解决这一问题。自动求导系统autograd只需要搭建前向传播的计算图,然后通过torch.autograd就可以得到每个张量的梯度。下面我们讲解torch.autograd中的方法。
  torch.autograd.backward()

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

功能:自动求取梯度

  • tensors:用于求导的张量,如loss

  • retain_graph :保存计算图(如果想多次使用计算图)

  • create_graph :创建导数计算图,用于高阶求导

  • grad_tensors:多梯度权重(用于多个梯度权重的设置)

    w = torch.tensor([1.], requires_grad=True)
    x = torch.tensor([2.], requires_grad=True)
    
    a = torch.add(w, x)     # retain_grad()
    b = torch.add(w, 1)
    
    y0 = torch.mul(a, b)    # y0 = (x+w) * (w+1)
    y1 = torch.add(a, b)    # y1 = (x+w) + (w+1)    dy1/dw = 2
    
    loss = torch.cat([y0, y1], dim=0)       # [y0, y1]
    grad_tensors = torch.tensor([1., 2.])
    
    loss.backward(gradient=grad_tensors)    # gradient 传入 torch.autograd.backward()中的grad_tensors
    
    print(w.grad)
    
    tensor([9.])	
    

  torch.autograd.grad()

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

功能:求取梯度

  1. outputs: 用于求导的张量,如 loss

  2. inputs :需要梯度的张量

  3. create_graph :创建导数计算图,用于高阶求导

  4. retain_graph :保存计算图

  5. grad_outputs:多梯度权重

    x = torch.tensor([3.], requires_grad=True)
    y = torch.pow(x, 2)     # y = x**2
    
    grad_1 = torch.autograd.grad(y, x, create_graph=True)   # grad_1 = dy/dx = 2x = 2 * 3 = 6
    print(grad_1)
    
    grad_2 = torch.autograd.grad(grad_1[0], x)              # grad_2 = d(dy/dx)/dx = d(2x)/dx = 2
    print(grad_2)
    
    (tensor([6.], grad_fn=<MulBackward0>),)
    (tensor([2.]),)
    

  torch.autograd()中需要注意如下几点:

  1. 梯度不自动清零,需要手动清零

    w = torch.tensor([1.], requires_grad=True)
    x = torch.tensor([2.], requires_grad=True)
    
    for i in range(4):
        a = torch.add(w, x)
        b = torch.add(w, 1)
        y = torch.mul(a, b)
    
        y.backward()
        print(w.grad)
        # 梯度清零
        # w.grad.zero_()
    
    tensor([5.])
    tensor([10.])
    tensor([15.])
    tensor([20.])
    
  2. 依赖于叶子节点的节点,requires_grad默认为True

    w = torch.tensor([1.], requires_grad=True)
    x = torch.tensor([2.], requires_grad=True)
    
    a = torch.add(w, x)
    b = torch.add(w, 1)
    y = torch.mul(a, b)
    
    print(a.requires_grad, b.requires_grad, y.requires_grad)
    
    True True True
    
  3. 叶子节点不可执行in-place(原地操作)


如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论或者私信!
在这里插入图片描述


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值