PyTorch框架学习四——计算图与动态图机制

  • 一、计算图
  • 二、动态图与静态图
  • 三、torch.autograd
    • 1.torch.autograd.backward()
    • 2.torch.autograd.grad()
    • 3.autograd小贴士
    • 4.代码演示理解
      • (1)构建计算图并反向求导:
      • (2)grad_tensors的理解:
      • (3)autograd.gard与create_graph的结合:
      • (4)小贴士1
      • (5)小贴士2
      • (6)小贴士3

一、计算图

计算图是用来描述运算的有向无环图,它包含了两个主要元素:结点(Node)与边(Edge)。其中结点表示数据,如向量、矩阵、张量等,而边表示运算,如加减乘除卷积等。

下面用计算图来表示:y=(x+w)×(w+1)这样的一个运算。

令 a = x + w,b = w + 1,则y = a×b。

计算图如下图所示:

构建这样的计算图是很方便求解梯度的,以对w求偏导为例,假设x和w的初始值为2和1:

强调两个概念:

  1. 叶子结点:用户创建的结点,如x与w,tensor中的is_leaf属性就是指示张量是否为叶子结点。非叶子结点运算后会被释放,叶子结点的梯度会被保留,若想保留非叶子结点的梯度,可以用retain_grad()。
  2. grad_fn:记录创建张量时所用的方法(函数),在梯度的反向传播时会用到,以上述的计算为例:y.grad_fn = <MulBackward 0>,a.grad_fn = <AddBackward 0>。

二、动态图与静态图

动态图 静态图
实现方式 运算与搭建同时进行 先搭建计算图,后计算
特点 灵活易调节 高效但不灵活
框架 PyTorch TensorFlow

三、torch.autograd

这是一个自动求导系统,提供了类和函数用来对任意标量函数进行求导。
下面介绍autograd中两个自动求导的函数:

1.torch.autograd.backward()

没有返回值,但是已经对数据进行了自动求导。

torch.autograd.backward(tensors: Union[torch.Tensor, Sequence[torch.Tensor]], grad_tensors: Union[torch.Tensor, Sequence[torch.Tensor], None] = None, retain_graph: Optional[bool] = None, create_graph: bool = False, grad_variables: Union[torch.Tensor, Sequence[torch.Tensor], None] = None)

  1. tensors:用于求导的张量们。
  2. grad_tensors:多梯度权重,下面用例子理解。
  3. retain_graph:(布尔,可选)若为False,计算图计算完之后就会被释放,若为True,则会保留。
  4. create_graph:(布尔,可选)若为True,会创建导数的计算图,用于更高阶的求导,默认为False。

2.torch.autograd.grad()

torch.autograd.grad(outputs: Union[torch.Tensor, Sequence[torch.Tensor]], inputs: Union[torch.Tensor, Sequence[torch.Tensor]], grad_outputs: Union[torch.Tensor, Sequence[torch.Tensor], None] = None, retain_graph: Optional[bool] = None, create_graph: bool = False, only_inputs: bool = True, allow_unused: bool = False)

3.autograd小贴士

  1. 梯度不会自动清零,若不清零,则会叠加上原来的数据,需要手动清零:grad.zero_()。
  2. 依赖于叶子结点的结点,requires_grad默认为True。
  3. 叶子结点不可执行in-place操作,in-place操作为在原始内存中改变数据的操作,如a += torch.ones((1, )) (加等操作a的内存地址不变,所以对张量不能做这项操作)。这是因为,在前向传播时,会记录叶子结点的地址,反向求导时是会依据记录的地址去取值进行运算的,若在中途用in-place操作改变了值,则梯度求解会出错。

4.代码演示理解

(1)构建计算图并反向求导:

# 设置 x 和 w 的初始值
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, x.grad)

结果如下,与手动计算结果一致:

tensor([5.]) tensor([2.])

(2)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 = 2loss = torch.cat([y0, y1], dim=0)       # [y0, y1]
grad_tensors = torch.tensor([1., 2.])loss.backward(gradient=grad_tensors)    # gradient 传入 torch.autograd.backward()中的grad_tensorsprint(w.grad)

grad_tensors的作用就类似于一个权重,当要求导的对象有多个梯度时,它就是各个梯度加和的权重,比如这里 dy0 / dw = 5,dy1/dw = 2,那么w的总梯度值为 5×1 + 2×2 = 9。
结果如下:

tensor([9.])

(3)autograd.gard与create_graph的结合:

x = torch.tensor([3.], requires_grad=True)
y = torch.pow(x, 2)     # y = x**2grad_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)

其中y就是用于求导的张量,x就是需要梯度的张量,grad_1就是第一次求导后x的梯度,因为create_graph为True,所以已经构建了导数的计算图,可以对grad_1再次求导,得到第二次求导后x的梯度grad_2:

(tensor([6.], grad_fn=<MulBackward0>),)
(tensor([2.]),)

(4)小贴士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)

若我们不对梯度手动清零,结果就如下所示:

tensor([5.])
tensor([10.])
tensor([15.])
tensor([20.])

因为每次的梯度都一样都为5,所以若不手动清零,则梯度会叠加起来。
我们在原来的基础上添加上手动清零:

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([5.])
tensor([5.])
tensor([5.])

这样才是正确的。

(5)小贴士2

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

(6)小贴士3

a = torch.ones((1, ))
print(id(a), a)a += torch.ones((1, ))
print(id(a), a)

结果为:

2379593847576 tensor([1.])
2379593847576 tensor([2.])

可见加等操作是in-place操作,是在原始内存中改变数据的操作。
而加法操作就不是,如下所示:

a = torch.ones((1, ))
print(id(a), a)a = a + torch.ones((1, ))
print(id(a), a)

内存不一样:

3019154559688 tensor([1.])
3019156480632 tensor([2.])

如果我们对叶子结点进行in-place操作:

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 += torch.ones((1,))
# w.add_(1)y.backward()print(w.grad)

会报如下错误提示:

PyTorch框架学习四——计算图与动态图机制相关推荐

  1. pytorch——计算图与动态图机制

    1.计算图 计算图是用来描述运算的有向无环图: 计算图有两个主要元素:结点(Node)和边(Edge): 结点表示数据,如向量.矩阵.张量,边表示运算,如加减乘除卷积等: 用计算图表示:y=(x+w) ...

  2. 若依框架学习(四)部门树状图

    部门树状图的实现 点击用户管理,观察网络活动大概可以猜出treeselect应该是该方法,根据请求url:http://localhost/dev-api/system/dept/treeselect ...

  3. PyTorch框架学习十四——学习率调整策略

    PyTorch框架学习十四--学习率调整策略 一._LRScheduler类 二.六种常见的学习率调整策略 1.StepLR 2.MultiStepLR 3.ExponentialLR 4.Cosin ...

  4. PyTorch框架学习十五——可视化工具TensorBoard

    PyTorch框架学习十五--可视化工具TensorBoard 一.TensorBoard简介 二.TensorBoard安装及测试 三.TensorBoard的使用 1.add_scalar() 2 ...

  5. PyTorch框架学习十八——Layer Normalization、Instance Normalization、Group Normalization

    PyTorch框架学习十八--Layer Normalization.Instance Normalization.Group Normalization 一.为什么要标准化? 二.BN.LN.IN. ...

  6. PyTorch框架学习十七——Batch Normalization

    PyTorch框架学习十七--Batch Normalization 一.BN的概念 二.Internal Covariate Shift(ICS) 三.BN的一个应用案例 四.PyTorch中BN的 ...

  7. PyTorch框架学习十——基础网络层(卷积、转置卷积、池化、反池化、线性、激活函数)

    PyTorch框架学习十--基础网络层(卷积.转置卷积.池化.反池化.线性.激活函数) 一.卷积层 二.转置卷积层 三.池化层 1.最大池化nn.MaxPool2d 2.平均池化nn.AvgPool2 ...

  8. PyTorch框架学习六——图像预处理transforms(二)

    PyTorch框架学习六--图像预处理transforms(二) (续)二.transforms的具体方法 4.图像变换 (1)尺寸变换:transforms.Resize() (2)标准化:tran ...

  9. 【PyTorch 】静态图与动态图机制

    [PyTorch 学习笔记] 1.4 静态图与动态图机制 - 知乎 PyTorch 的动态图机制 PyTorch 采用的是动态图机制 (Dynamic Computational Graph),而 T ...

最新文章

  1. 重构手法之简化函数调用【1】
  2. ICCV 2017 《Unsupervised Learning from Video to Detect Foreground Objects in Single Images》论文笔记
  3. hdu5461(2015沈阳网络赛L题)
  4. 关系型数据库、非关系型数据库
  5. SAP Spartacus名为Configuration的injection token
  6. IE下列表框不能给option绑定click事件的解决办法
  7. oracle 查看白名单,oracle配置访问白名单教程
  8. sqlserverv中处理字符串包含、截取
  9. C++ and Java template class and function 模板类和模板函数
  10. python软件下载3版本-Python3.9下载
  11. java2实用教程第五版耿祥义电子版_Java2实用教程(第5版)答案_耿祥义
  12. Terms of Service - Screen Capture
  13. 字节跳动 IconPark 免费图标库、阿里巴巴矢量图标库
  14. html a标签链接 点击下载文件
  15. 上海大学计算机考证时间表
  16. uboot利用uEnv.txt文件实现灵活功能(加载PL侧bit,修改uenvcmd,配置bootargs,配置bootm,配置bootz)
  17. dnw驱动更新,支持全系统(xp,win7,win8/win10)
  18. android(9)_数据存储和访问3_scard基本介绍
  19. 小猫爪:i.MX RT1050学习笔记3-CCM
  20. 解决:RuntimeError: CUDA out of memory. Tried to allocate 64.00 MiB (GPU 0; 4.00 GiB total capacity; 2

热门文章

  1. Google 资深软件工程师 LeetCode 刷题笔记首次公开
  2. 高性能平台设计—美团旅行结算平台实践
  3. 史上最强多线程面试44题和答案:线程锁+线程池+线程同步等
  4. 李涓子 | 机器智能加速器:大数据环境下知识工程的机遇和挑战
  5. Base64加解密的实现方式
  6. 中文幽默语料库构建与计算项目(幽默等级识别,幽默类型识别,隐喻类型识别,隐喻情绪识别)
  7. 知识图谱最新权威综述论文解读:开篇部分
  8. 20190423面试记录
  9. (数据科学学习手札45)Scala基础知识
  10. 五十个小技巧提高PHP执行效率