我正在通过两个简单的PyTorch nn.Module模型实例model1
和model2
向前传递和反向传播张量数据X
。
如果不使用已废弃的Variable
API,我无法使这个过程正常工作。
所以这样做完全没问题:
y1 = model1(X) v = Variable(y1.data, requires_grad=training) # 重点是这一行! 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) # 这里会出错 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
已被废弃,还有什么其他实现方法可以工作?
回答:
经过一些调查,我找到了以下两种解决方案。本线程中其他地方提供的解决方案手动保留了计算图,没有选项释放它们,因此最初运行良好,但后来引起了内存溢出错误。
第一种解决方案是使用内置的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
也存储在被反向传播的计算图中。与之前的实现相比,这种实现增加了两个模型之间接口的透明度。