如何摆脱中的变量APIPyTorch.autograd?

2024-06-25 06:30:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我通过两个简单的nn.模块PyTorch模型实例,model1model2。你知道吗

如果不使用depreciated ^{} API,我就无法让这个过程正常工作。你知道吗

这样就可以了:

    y1 = model1(X)
    v = Variable(y1.data, requires_grad=training)         # Its all about this line!
    y2 = model2(v)
    criterion = nn.NLLLoss()
    loss = criterion(y2, y)
    loss.backward()
    y1.backward(v.grad)
    self.step()

但这将引发一个错误:

    y1 = model1(X)
    y2 = model2(y1)
    criterion = nn.NLLLoss()
    loss = criterion(y2, y)
    loss.backward()
    y1.backward(y1.grad) # it breaks here
    self.step()
>>> RuntimeError: grad can be implicitly created only for scalar outputs

我只是找不到第一个实现中的v和第二个实现中的y1之间的相关区别。在这两种情况下,requires_grad都设置为True。我唯一能找到的就是y1.grad_fn=<ThnnConv2DBackward>v.grad_fn=<ThnnConv2DBackward>

我错过了什么?什么(张量属性?)我不知道,如果Variable被贬低,还有什么其他的实现可以工作?


Tags: selfstepnnvariablefnmodel1requirescriterion
2条回答

经过一番调查,我得出了以下两种解决办法。 此线程中其他地方提供的解决方案手动保留计算图,没有释放它们的选项,因此最初运行良好,但稍后会导致OOM错误。你知道吗

第一种解决方案是使用内置的torch.nn.Sequential将模型绑定在一起:

model = torch.nn.Sequential(Model1(), Model2())

就这么简单。它看起来很干净,行为和普通模特一模一样。你知道吗

另一种方法是简单地手动将它们捆绑在一起:

        model1 = Model1()
        model2 = Model2()
        y1 = model1(X)
        y2 = model2(y1)
        loss = criterion(y2, y)
        loss.backward()

我担心这只会反向传播model2结果是没有根据的,因为model1也存储在反向传播的计算图中。 与以前的实现相比,这种实现增强了两个模型之间接口的透明性。你知道吗

你知道吗 [更新] 在第二个示例中,您没有正确地将y1.grad传递到y1.backward。在第一次backward之后,所有中间梯度都将被销毁,您需要一个特殊的钩子来提取该梯度。在您的例子中,您传递的是None值。下面是一个小例子来重现您的案例:

代码:

import torch
import torch.nn as nn


torch.manual_seed(42)


class Model1(nn.Module):

    def __init__(self):
        super().__init__()

    def forward(self, x):
        return x.pow(3)


class Model2(nn.Module):

    def __init__(self):
        super().__init__()

    def forward(self, x):
        return x / 2


model1 = Model1()
model2 = Model2()
criterion = nn.MSELoss()

X = torch.randn(1, 5, requires_grad=True)
y = torch.randn(1, 5)

y1 = model1(X)
y2 = model2(y1)

loss = criterion(y2, y)
# We are going to backprop 2 times, so we need to 
# retain_graph=True while first backward
loss.backward(retain_graph=True)

try:
    y1.backward(y1.grad)
except RuntimeError as err:
    print(err)
    print('y1.grad: ', y1.grad)

输出:

grad can be implicitly created only for scalar outputs
y1.grad:  None

因此,您需要正确提取它们:

代码:

def extract(V):
    """Gradient extractor.
    """
    def hook(grad):
        V.grad = grad
    return hook


model1 = Model1()
model2 = Model2()
criterion = nn.MSELoss()

X = torch.randn(1, 5, requires_grad=True)
y = torch.randn(1, 5)

y1 = model1(X)
y2 = model2(y1)

loss = criterion(y2, y)
y1.register_hook(extract(y1))
loss.backward(retain_graph=True)

print('y1.grad', y1.grad)

y1.backward(y1.grad)

输出:

y1.grad:  tensor([[-0.1763, -0.2114, -0.0266, -0.3293,  0.0534]])

相关问题 更多 >