那些非叶子节点,是通过用户所定义的叶子节点的一系列运算生成的,也就是这些非叶子节点都是中间变量,一般情况下,用户不回去使用这些中间变量的导数,所以为了节省内存,它们在用完之后就被释放了。
在Pytorch的autograd机制中,当tensor的requires_grad值为True时,在backward()反向传播计算梯度时才会被计算。在所有的require_grad=True中,默认情况下,非叶子节点的梯度值在反向传播过程中使用完后就会被清除,不会被保留(即调用loss.backward() 会将计算图的隐藏变量梯度清除)。默认情况下,只有叶子节点的梯度值能够被保留下来。被保留下来的叶子节点的梯度值会存入tensor的grad属性中,在 optimizer.step()过程中会更新叶子节点的data属性值,从而实现参数的更新。
如果需要使得某一个节点成为叶子节点,只需使用detach()即可将它从创建它的计算图中分离开来。即detach()函数的作用就是把一个节点从计算图中剥离,使其成为叶子节点。
①所有requires_grad为False的张量,都约定俗成地归结为叶子张量。 就像我们训练模型的input,它们都是require_grad=False,因为他们不需要计算梯度(我们训练网络训练的是网络模型的权重,而不需要训练输入)。它们是一个计算图都是起始点。
②requires_grad为True的张量, 如果他们是由用户创建的,则它们是叶张量(leaf Tensor)。例如各种网络层,nn.Linear(), nn.Conv2d()等, 他们是用户创建的,而且其网络参数也需要训练,所以requires_grad=True这意味着它们不是运算的结果,因此gra_fn为None。
detach()
返回一个新的tensor,从当前计算图中分离下来的,但是仍指向原变量的存放位置,不同之处只是requires_grad为false,得到的这个tensor永远不需要计算其梯度,不具有grad。即使之后重新将它的requires_grad置为true,它也不会具有梯度grad。这样我们就会继续使用这个新的tensor进行计算,后面当我们进行反向传播时,到该调用detach()的tensor就会停止,不能再继续向前进行传播。
使用detach返回的tensor和原始的tensor共同一个内存,即一个修改另一个也会跟着改变。
detach_()
将一个tensor从创建它的图中分离,并把它设置成叶子tensor。其实就相当于变量之间的关系本来是x -> m -> y,这里的叶子tensor是x,但是这个时候对m进行了m.detach_()操作,其实就是进行了两个操作:
将m的grad_fn的值设置为None,这样m就不会再与前一个节点x关联,这里的关系就会变成x,m -> y,此时的m就变成了叶子结点。然后会将m的requires_grad设置为False,这样对y进行backward()时就不会求m的梯度。
detach()和detach_()很像,两个的区别就是detach_()是对本身的更改,detach()则是生成了一个新的tensor
比如x -> m -> y中如果对m进行detach(),后面如果反悔想还是对原来的计算图进行操作还是可以的。但是如果是进行了detach_(),那么原来的计算图也发生了变化,就不能反悔了
clone与原tensor不共享内存,detach与原tensor共享内存。
clone支持梯度回传,detach不支持梯度回传。
如果想要非叶节点也保留梯度的话,可以用retain_grad()。
optimizer.zero_grad()清除了优化器中所有 x x x的 x . g r a d x.grad x.grad,在每次loss.backward()之前,不要忘记使用,否则之前的梯度将会累积,这通常不是我们所期望的(也不排除也有人需要利用这个功能)。
损失函数loss定义了模型优劣的标准,loss越小,模型越好,常见的损失函数比如均方差MSE(Mean Square Error),MAE (Mean Absolute Error),交叉熵CE(Cross-entropy) 等。
loss.backward()故名思义,就是将损失loss 向输入侧进行反向传播,同时对于需要进行梯度计算的所有变量 x x x(requires_grad=True),计算梯度 d d x l o s s {\frac{d}{d x}}l o s s dxdloss ,并将其累积到梯度 x . g r a d x.grad x.grad 中备用,即:
x . g r a d = x . g r a d + d d x l o s s x.grad=x.grad + {\frac{d}{d x}}l o s s x.grad=x.grad+dxdloss
optimizer.step()是优化器对 x x x的值进行更新,以随机梯度下降SGD为例:学习率(learning rate, lr)来控制步幅,即: x = x − l r ∗ x . g r a d x = x - lr*x.grad x=x−lr∗x.grad,减号是由于要沿着梯度的反方向调整变量值以减少Cost。