PyTorch框架学习四——计算图与动态图机制
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:
强调两个概念:
- 叶子结点:用户创建的结点,如x与w,tensor中的is_leaf属性就是指示张量是否为叶子结点。非叶子结点运算后会被释放,叶子结点的梯度会被保留,若想保留非叶子结点的梯度,可以用retain_grad()。
- 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)
- tensors:用于求导的张量们。
- grad_tensors:多梯度权重,下面用例子理解。
- retain_graph:(布尔,可选)若为False,计算图计算完之后就会被释放,若为True,则会保留。
- 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小贴士
- 梯度不会自动清零,若不清零,则会叠加上原来的数据,需要手动清零:grad.zero_()。
- 依赖于叶子结点的结点,requires_grad默认为True。
- 叶子结点不可执行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框架学习四——计算图与动态图机制相关推荐
- pytorch——计算图与动态图机制
1.计算图 计算图是用来描述运算的有向无环图: 计算图有两个主要元素:结点(Node)和边(Edge): 结点表示数据,如向量.矩阵.张量,边表示运算,如加减乘除卷积等: 用计算图表示:y=(x+w) ...
- 若依框架学习(四)部门树状图
部门树状图的实现 点击用户管理,观察网络活动大概可以猜出treeselect应该是该方法,根据请求url:http://localhost/dev-api/system/dept/treeselect ...
- PyTorch框架学习十四——学习率调整策略
PyTorch框架学习十四--学习率调整策略 一._LRScheduler类 二.六种常见的学习率调整策略 1.StepLR 2.MultiStepLR 3.ExponentialLR 4.Cosin ...
- PyTorch框架学习十五——可视化工具TensorBoard
PyTorch框架学习十五--可视化工具TensorBoard 一.TensorBoard简介 二.TensorBoard安装及测试 三.TensorBoard的使用 1.add_scalar() 2 ...
- PyTorch框架学习十八——Layer Normalization、Instance Normalization、Group Normalization
PyTorch框架学习十八--Layer Normalization.Instance Normalization.Group Normalization 一.为什么要标准化? 二.BN.LN.IN. ...
- PyTorch框架学习十七——Batch Normalization
PyTorch框架学习十七--Batch Normalization 一.BN的概念 二.Internal Covariate Shift(ICS) 三.BN的一个应用案例 四.PyTorch中BN的 ...
- PyTorch框架学习十——基础网络层(卷积、转置卷积、池化、反池化、线性、激活函数)
PyTorch框架学习十--基础网络层(卷积.转置卷积.池化.反池化.线性.激活函数) 一.卷积层 二.转置卷积层 三.池化层 1.最大池化nn.MaxPool2d 2.平均池化nn.AvgPool2 ...
- PyTorch框架学习六——图像预处理transforms(二)
PyTorch框架学习六--图像预处理transforms(二) (续)二.transforms的具体方法 4.图像变换 (1)尺寸变换:transforms.Resize() (2)标准化:tran ...
- 【PyTorch 】静态图与动态图机制
[PyTorch 学习笔记] 1.4 静态图与动态图机制 - 知乎 PyTorch 的动态图机制 PyTorch 采用的是动态图机制 (Dynamic Computational Graph),而 T ...
最新文章
- 重构手法之简化函数调用【1】
- ICCV 2017 《Unsupervised Learning from Video to Detect Foreground Objects in Single Images》论文笔记
- hdu5461(2015沈阳网络赛L题)
- 关系型数据库、非关系型数据库
- SAP Spartacus名为Configuration的injection token
- IE下列表框不能给option绑定click事件的解决办法
- oracle 查看白名单,oracle配置访问白名单教程
- sqlserverv中处理字符串包含、截取
- C++ and Java template class and function 模板类和模板函数
- python软件下载3版本-Python3.9下载
- java2实用教程第五版耿祥义电子版_Java2实用教程(第5版)答案_耿祥义
- Terms of Service - Screen Capture
- 字节跳动 IconPark 免费图标库、阿里巴巴矢量图标库
- html a标签链接 点击下载文件
- 上海大学计算机考证时间表
- uboot利用uEnv.txt文件实现灵活功能(加载PL侧bit,修改uenvcmd,配置bootargs,配置bootm,配置bootz)
- dnw驱动更新,支持全系统(xp,win7,win8/win10)
- android(9)_数据存储和访问3_scard基本介绍
- 小猫爪:i.MX RT1050学习笔记3-CCM
- 解决:RuntimeError: CUDA out of memory. Tried to allocate 64.00 MiB (GPU 0; 4.00 GiB total capacity; 2