Pytorch入门(四)——计算图与自动求导

1 计算图

1.1 计算图介绍

计算图是用来描述运算的有向无环图,其中有两个主要元素:结点(Node)和边(Edge)

结点表示数据,如向量,矩阵,张量

边表示运算,如加减乘除卷积等

实例:

用计算图表示y=(x+w) * (w+1)

a = x + w

b = w + 1

y = a * b
在这里插入图片描述

1.2 计算图与梯度求导

通过计算图,我们可以对求导的过程一目了然,例如:y=(x+w)(w+1)y = (x+w)*(w+1),我们需要对w求导,

且$a = x+w ,,b = w+1$

y=aby=a*b

则有
θyθw=θyθaθaθw+θyθbθbθw\frac{\theta y}{\theta w}=\frac{\theta y}{\theta a}\frac{\theta a}{\theta w}+\frac{\theta y}{\theta b}\frac{\theta b}{\theta w}
=b1+a1=b*1 + a*1
=b+a=b +a
=(w+1)+(x+w)=(w+1)+(x+w)
=2w+x+1=2*w+x+1
=21+2+1=5=2*1+2+1=5
通过计算图,我们则可以清晰的看到梯度求导的逆向流程步骤。其实就是对y到w上的所有路径的导数的积进行求和。
在这里插入图片描述

#代码显示
%matplotlib inline
import torch
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)

y.backward()
print(w.grad)
tensor([5.])

通过代码我们可以得到y对w求导后的值为5。
其中x,w分别为这个计算图中的叶子节点,在程序中我们认为用户创建的节点称为叶子节点

is_leaf:判别张量是否为叶子节点
程序在运行完后,对于非叶子节点将会自动清空其求导值,以减少内存占用。

#可以看到,除了w,x以外,其余均为非叶子节点,且除叶子节点外均不显示梯度值
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

如果需要显示非叶子节点的梯度值,则需要使用retain_grad()

w = torch.tensor([1.],requires_grad=True)
x = torch.tensor([2.],requires_grad=True)

a = torch.add(w,x)
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记录创建该张量时所用的方法

print("grad_fn:\n", w.grad_fn, x.grad_fn, a.grad_fn, b.grad_fn, y.grad_fn)
grad_fn:
 None None <AddBackward0 object at 0x000001C66977F548> <AddBackward0 object at 0x000001C66977F108> <MulBackward0 object at 0x000001C66977F248>

可以发现,除了叶子节点显示为None以外,其他非叶子节点均可以显示器创建该张量时所用到的方法。

2 动态图

动态图:运算与搭建同时进行。——Pytorch

静态图:搭建图,运算——TensorFlow

3 计算图与自动求导torch.autograd

通过上面的计算图,我们了解了计算机求导的大致原理,这对于我们理解自动求导更为清晰一些。接下来我们介绍自动求导中的常用方法。

3.1 torch.autograd.backward

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

功能:自动求取梯度

  • tensor:用于求导的张量
  • 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)
b = torch.add(w, 1)
y = torch.mul(a, b)
#这里的backward调用的就是torch.autograd.backward()方法
y.backward(retain_graph=True) #这里设置retain_graph=True,是为了保留计算图,如果retain_graph=False,则无法二次求导。
print(w.grad)

tensor([5.])

对于多梯度权重,通过backward()中的gradient将权重传入torch.autograd.backward()方法grad_tensors参数中

flag = True
if flag:
    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.])

3.2 torch.autograd.grad

功能:求取梯度

  • outputs:用于求导的张量,如loss
  • inputs:需要梯度的张量
  • cerate_graph:创建导数计算图,用于高阶求导
  • retain_graph:保存计算图
  • grad_outputs:多梯度权重
flag = True
if flag:

    x = torch.tensor([3.], requires_grad=True)
    y = torch.pow(x, 2)     # y = x**2
    #create_graph=True创建一阶求导的计算图,便于二姐求导时使用
    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.]),)

autograd小贴士:

  • 梯度不会自动清零
  • 依赖于叶子结点的结点,require_grad默认为True
  • 叶子节点不可执行in-place(原位操作)即以“_”结尾的方法
if flag:
# 梯度不会自动清零
    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)
        #grad.zero_表示原位清零
        w.grad.zero_()
tensor([5.])
tensor([5.])
tensor([5.])
tensor([5.])
if flag:
#依赖于叶子结点的结点,require_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
if flag:

    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)

    w.add_(1)

    y.backward()
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

<ipython-input-26-5f1c347bd270> in <module>
      8     y = torch.mul(a, b)
      9 
---> 10     w.add_(1)
     11 
     12     y.backward()


RuntimeError: a leaf Variable that requires grad has been used in an in-place operation.

a leaf Variable that requires grad has been used in an in-place operation.
提示无法进行原位操作。


©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值