我知道从梯度计算backward
中排除计算元素的两种方法
方法1:使用with torch.no_grad()
with torch.no_grad():
y = reward + gamma * torch.max(net.forward(x))
loss = criterion(net.forward(torch.from_numpy(o)), y)
loss.backward();
方法2:使用.detach()
y = reward + gamma * torch.max(net.forward(x))
loss = criterion(net.forward(torch.from_numpy(o)), y.detach())
loss.backward();
这两者之间有区别吗?两者都有好处/缺点吗?
答案 0 :(得分:6)
detach()
一个没有detach()
的示例:
from torchviz import make_dot
x=torch.ones(2, requires_grad=True)
y=2*x
z=3+x
r=(y+z).sum()
make_dot(r)
绿色r
的最终结果是AD计算图的根,蓝色是叶子张量。
另一个带有detach()
的示例:
from torchviz import make_dot
x=torch.ones(2, requires_grad=True)
y=2*x
z=3+x.detach()
r=(y+z).sum()
make_dot(r)
这与:
from torchviz import make_dot
x=torch.ones(2, requires_grad=True)
y=2*x
z=3+x.data
r=(y+z).sum()
make_dot(r)
但是,x.data
是旧方法(符号),而x.detach()
是新方法。
与x.detach()
print(x)
print(x.detach())
出局:
tensor([1., 1.], requires_grad=True)
tensor([1., 1.])
因此, x.detach()
是删除requires_grad
的一种方法,您得到的是一个新的分离的张量(与AD计算图分离)。
torch.no_grad
实际上是一个类。
x=torch.ones(2, requires_grad=True)
with torch.no_grad():
y = x * 2
print(y.requires_grad)
出局:
False
来自help(torch.no_grad)
:
在您确定时,禁用梯度计算对于推断很有用 |您将不会调用:meth:
Tensor.backward()
。它将减少内存 |否则将具有requires_grad=True
的计算的消耗。 |
|在这种模式下,每次计算的结果将具有 |requires_grad=False
,即使输入中有requires_grad=True
。
答案 1 :(得分:2)
tensor.detach()
创建一个张量,该张量与不需要grad的张量共享存储。它将输出与计算图分离。因此,不会沿该变量向后传播梯度。
包装器with torch.no_grad()
暂时将所有requires_grad
标志设置为false。 torch.no_grad
说,任何操作都不能建立图形。
区别在于,仅引用一个给定变量对其进行调用。另一个影响with
语句中发生的所有操作。另外,torch.no_grad
将使用较少的内存,因为它从一开始就知道不需要渐变,因此不需要保留中间结果。
进一步了解它们之间的区别以及here中的示例。
答案 2 :(得分:1)
一个简单而深刻的解释是,with torch.no_grad()
的使用就像一个循环,其中写入的所有内容都将requires_grad
自变量设置为False
,尽管是暂时的。因此,如果您需要停止某些变量或函数的梯度的反向传播,则无需指定任何其他内容。
但是,顾名思义,torch.detach()
只是从梯度计算图中分离变量。但这在必须为有限数量的变量或函数(例如)提供本规范时使用。通常,在神经网络训练中,在某个时期结束后显示损失和准确性输出时,因为那一刻,它仅消耗资源,因为在显示结果期间其梯度无关紧要。