Автоматическое обновление пользовательских параметров слоя при обратном распространении в pytorch - PullRequest
0 голосов
/ 25 ноября 2018

У меня есть пользовательский слой 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])

Это, в свою очередь, не позволяет шагу optim автоматически обновлять внутренние параметры, а также избавляет меня от необходимости обновлять их вручную.Кто-нибудь знает, как я могу решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

То, что вы сделали, т.е. 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, он регистрируется как параметр.

0 голосов
/ 25 ноября 2018

Хорошо!Мне пришлось переключить вызовы переменных параметров в пользовательском слое на объект nn.ParameterList (т.е. return x*self.my_registered_parameter[0] вместо x * self.my_parameter).В этом примере это означало изменение вызова параметра пользовательского слоя в методе forward на

  def forward(self, x):
    return x*self.my_registered_parameter[0]

. Здесь было бы неплохо, если бы передавалось по ссылке !

Теперь оптимизатор обновляет все параметры, как и ожидалось!

...