本文作者:Allen 

pytorch loss梯度截断 pytorch 梯度累积_反向传播

在该系列的上一篇,我们介绍了使用Pytorch的重要知识点:计算图和自动求导。

本篇我们继续学习计算图和自动求导。

首先,我们在上一节的计算图上增加复杂度,例如变成这样的计算图:

pytorch loss梯度截断 pytorch 梯度累积_深度学习_02

图中为了绘制方便,把张量w和x绘制在一个框中了。

其对应的计算图代码如下:

import torchw = torch.tensor([1.],requires_grad=True)x = torch.tensor([2.],requires_grad=True)a = torch.add(w,x)b = torch.add(w,2)y = torch.mul(a,b)y.backward()#梯度反向传播print(w.grad)#w的梯度
需要注意的一点是,要使得某个变量支持求导,需要在赋值时使它的元素为浮点数值,如果例如上面代码中的 w 和 x 张量,如果我们定义时赋值的元素不是浮点数而是整数,如下代码:
#不用浮点数import torchw = torch.tensor([1],requires_grad=True)x = torch.tensor([2],requires_grad=True)a = torch.add(w,x)b = torch.add(w,2)y = torch.mul(a,b)y.backward()#梯度反向传播print(w.grad)#w的梯度

运行后会发现:

pytorch loss梯度截断 pytorch 梯度累积_深度学习_03

抛出的异常大概意思是:只有元素类型是浮点数的张量才能支持梯度计算。

所以这点大家要注意!

我们接着来聊聊一个新的概念,叫做叶子节点。

在pytorch的tensor类中,有个叫做 is_leaf 的属性,可以称之为叶子节点,如果计算图中某个节点的 is_leaf 属性取值为 True,则为叶子节点。如果取值是False,则不是叶子节点。

一般将用户自己创建的变量叫做叶子节点,而由叶子节点计算得到的变量叫做非叶子节点,调用非叶子节点的backward方法,就会沿着非叶子节点一直回溯到叶子节点结束。

我们还是执行一次反向传播:

import torchw = torch.tensor([1.],requires_grad=True)x = torch.tensor([2.],requires_grad=True)a = torch.add(w,x)b = torch.add(w,2)y = torch.mul(a,b)y.backward()#梯度反向传播

然后查看各个节点是否叶子节点:

#查看叶子节点print(w.is_leaf,x.is_leaf,a.is_leaf,b.is_leaf,y.is_leaf)

pytorch loss梯度截断 pytorch 梯度累积_子节点_04

我们发现,其中只有我们赋值的 w 和 x 是叶子节点,而 a、b、y 是由 w 和 x 计算得到的。

我们查看一次 backward 后,每个节点的梯度值:

#查看梯度print(w.grad,x.grad,a.grad,b.grad,y.grad)#只有叶子结点梯度存在于内存中

pytorch loss梯度截断 pytorch 梯度累积_pytorch loss梯度截断_05

发现只有叶子节点的梯度值不为None,这是因为非叶子节点的梯度值并没有被保存在内存中。

所以叶子节点是该节点是否能保存梯度的前提。