创建一个只是标识的 nnModule

Create a nnModule that's just the identity

我正在尝试调试不同 nnModules 之间相当复杂的交互。能够仅用身份网络替换其中一个以进行调试对我来说非常有帮助。例如:

net_a = NetworkA()
net_b = NetworkB()
net_c = NetworkC()

input = Autograd.Variable(torch.rand(10,2))

out = net_a(input)
out = net_b(out)
out = net_c(out)

我希望能够将第二行更改为 net_b = IdentityNet(),而不必通过并重新连接我所有的 As 到 Cs。但是,当我创建一个完全空的 nnModule 时,优化器会抛出 ValueError: optimizer got an empty parameter list.

有什么解决方法吗?

一个最小的非工作示例:

import torch.optim as optim

class IdentityModule(nnModule):
    def forward(self, inputs):
        return inputs

identity = IdentityModule()
opt = optim.Adam(identity, lr=0.001)
out = identity(any_tensor)
error = torch.mean(out)
error.backward()
opt.step()

您在这里遇到的问题是合乎逻辑的。看看你这样做意味着什么:

error.backward()
opt.step()

.backward() 将递归计算从输出到传入网络的任何输入的梯度。就计算图而言,有两种值得注意的输入:您传入的输入,以及模拟网络行为的 nn.Parameters。然后当您执行 opt.step() 时,PyTorch 将查找它可以更新以更改网络输出的任何输入,即 nn.Parameters().

但是,您的伪代码 没有一个 nn.Parameter!,因为身份模块不包含一个。所以当你调用这些函数时,opt.step() 没有目标,解释错误信息。

这不会扩展到您之前描述的情况。如果您将一个没有参数的模块链接到一个更大的链中,其中一些模块确实有参数,那么计算图中就会有参数要训练。

不过,您需要确保优化器确实获得了初始化时传递的所有这些参数。一个简单的技巧是打印这些:

net_a = SomeNetwork()
net_b = IdentityNetwork()  # has no parameters
net_c = SomeNetwork()

print(list(net_a.parameters()))  # will contain whatever parameters in net_a
print(list(net_b.parameters()))  # will be []
print(list(net_c.parameters()))  # will contain whatever parameters in net_c
# to train all of them, you can do one of two things:
# 1. create new module. This works, since `.parameters()` collects params recursively from all submodules. 
class NewNet(nn.Module):
    def __init__(self):
        nn.Module.__init__(self)
        self.net_a = net_a
        self.net_b = identity
        self.net_c = net_c

    def forward(self, input):
        return self.net_c(self.net_b(self.net_a(input)))
all_parameters = list(NewNet().parameters())
print(all_parameters)  # will contain a list of all parameters of net_a and net_c

# 2. simply merge the lists
all_parameters = list(net_a.parameters()) + list(net_b.parameters()) + list(net_c.parameters())
print(all_parameters)  # will contain a list of all parameters of net_a and net_c


opt = optim.SGD(all_parameters)

你也可以just do:

net_b = torch.nn.Sequential()

编辑:在 PyTorch 1.7 中,[nn.Identity](https://pytorch.org/docs/stable/generated/torch.nn.Identity.html#torch.nn.Identity) 出现了。医生在[这里]。

最新版本的 pytorch 有一个身份模块 nn.Identity

net_b = nn.Identity()