我有一个定义为的pytorch自定义层:
class MyCustomLayer(nn.Module):
def __init__(self):
super(MyCustomLayer, self).__init__()
self.my_parameter = torch.rand(1, requires_grad = True)
# the following allows the previously defined parameter to be recognized as a network parameter when instantiating the model
self.my_registered_parameter = nn.ParameterList([nn.Parameter(self.my_parameter)])
def forward(self, x):
return x*self.my_parameter
然后我定义使用自定义层的网络:
class MyNet(nn.Module):
def __init__(self):
super(MyNet, self).__init__()
self.layer1 = MyCustomLayer()
def forward(self, x):
x = self.layer1(x)
return x
现在让我们实例化MyNet并观察问题:
# instantiate MyNet and run it over one input value
model = MyNet()
x = torch.tensor(torch.rand(1))
output = model(x)
criterion = nn.MSELoss()
loss = criterion(1, output)
loss.backward()
遍历模型参数将显示None
用于自定义图层参数:
for p in model.parameters():
print (p.grad)
None
在直接访问该参数时显示正确的grad
值:
print(model.layer1.my_parameter.grad)
tensor([-1.4370])
反过来,这阻止了优化步骤自动更新内部参数,并使我省去了手动更新这些参数的麻烦。谁知道我该如何解决这个问题?
答案 0 :(得分:1)
好的!
我必须将自定义层中的参数变量调用切换到nn.ParameterList
对象(即return x*self.my_registered_parameter[0]
而不是x * self.my_parameter)。在此示例中,这意味着将正向方法中的自定义层的参数调用更改为:
def forward(self, x):
return x*self.my_registered_parameter[0]
这是通过引用通过的好地方!
现在optim会按预期更新所有参数!
答案 1 :(得分:1)
您所做的操作,即return x*self.my_registered_parameter[0]
之所以有效,是因为您使用注册的参数来计算梯度。
调用nn.Parameter
时它将返回一个新对象,因此用于该操作的self.my_parameter
与注册的对象不相同。
您可以通过将my_parameter
声明为nn.Parameter
self.my_parameter = nn.Parameter(torch.rand(1, requires_grad = True))
self.my_registered_parameter= nn.ParameterList([self.some_parameter])
,或者根本不需要创建my_registered_parameter
变量。当您将self.my_parameter
声明为nn.Parameter
时,它将被注册为参数。