import torch
from torch.autograd import Function
from torch.autograd import Variable
A = Variable(torch.randn(10,10), requires_grad=True)
u, s, v = torch.svd(A) # raises TypeError
class my_function(Function): # forgot to define backward()
def forward(self, x):
return 2 * x
A = Variable(torch.randn(10,10))
B = my_function()(A)
C = torch.sum(B)
C.backward() # will raise NotImplementedError
1 回答
让我去吧 .
a)您正在使用自定义PyTorch操作,其中尚未实现渐变,例如
torch.svd()
. 在这种情况下,你会得到一个TypeError
:b)您已经实现了自己的操作,但没有定义
backward()
. 在这种情况下,您将获得NotImplementedError
:有意义的第二个定义是"mathematically non-differentiable" . 显然,在数学上不可微分的操作应该不具有实现的方法或者合理的子梯度 . 考虑例如
torch.abs()
,其backward()
方法在0处返回子梯度0:对于这些情况,您应该直接参考PyTorch文档并直接挖掘相应操作的
backward()
方法 .requires_grad
的使用是为了避免对子图的渐变进行不必要的计算 . 如果对需要渐变的操作有单个输入,则其输出也需要渐变 . 相反,只有当所有输入都不需要梯度时,输出也不需要它 . 从不在子图中执行向后计算,其中所有变量都不需要渐变 .因为,很可能有一些
Variables
(例如nn.Module()
的子类的参数),您的loss
变量也将自动需要渐变 . 但是,您应该注意到requires_grad
的工作原理(再次参见上文),无论如何,您只能更改图形的叶子变量requires_grad
._Loss
的子类,它是nn.Module
的子类 . See here.如果您想坚持这个约定,那么在定义自定义损失函数时应该继承_Loss
. 除了一致性之外,如果您没有将目标变量标记为volatile
或requires_grad = False
,则一个优点是您的子类将引发AssertionError
. 另一个优点是你可以在nn.Sequential()
中嵌套你的损失函数,因为它是nn.Module
我会因为这些原因推荐这种方法 .