проблема с удержанием графа с GRU в Pytorch 1.6

#python-3.x #machine-learning #deep-learning #pytorch #torch

#python-3.x #машинное обучение #глубокое обучение #pytorch #факел

Вопрос:

Я знаю, что при использовании loss.backward() нам нужно указать retain_graph=True , есть ли несколько сетей и несколько функций потерь для оптимизации каждой сети отдельно. Но даже с указанием (или без) этого параметра я получаю ошибки. Ниже приведен MWE для воспроизведения проблемы (в PyTorch 1.6).

 import torch
from torch import nn
from torch import optim
torch.autograd.set_detect_anomaly(True)


class GRU1(nn.Module):
    def __init__(self):
        super(GRU1, self).__init__()
        self.brnn = nn.GRU(input_size=2, bidirectional=True, num_layers=1, hidden_size=100)

    def forward(self, x):
        return self.brnn(x)


class GRU2(nn.Module):
    def __init__(self):
        super(GRU2, self).__init__()
        self.brnn = nn.GRU(input_size=200, bidirectional=True, num_layers=1, hidden_size=1)

    def forward(self, x):
        return self.brnn(x)

gru1 = GRU1()
gru2 = GRU2()
gru1_opt = optim.Adam(gru1.parameters())
gru2_opt = optim.Adam(gru2.parameters())
criterion = nn.MSELoss()


for i in range(100):
    gru1_opt.zero_grad()
    gru2_opt.zero_grad()
    vector = torch.randn((15, 100, 2))
    gru1_output, _ = gru1(vector)  # (15, 100, 200)
    loss_gru1 = criterion(gru1_output, torch.randn((15, 100, 200)))
    loss_gru1.backward(retain_graph=True)
    gru1_opt.step()
    gru1_output, _ = gru1(vector)  # (15, 100, 200)
    gru2_output, _ = gru2(gru1_output)  # (15, 100, 2)
    loss_gru2 = criterion(gru2_output, torch.randn((15, 100, 2)))
    loss_gru2.backward(retain_graph=True)
    gru2_opt.step()
    print(f"GRU1 loss: {loss_gru1.item()}, GRU2 loss: {loss_gru2.item()}")
  

С retain_graph установленным значением True я получаю ошибку

 RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [100, 300]], which is output 0 of TBackward, is at version 2; expected version 1 instead. Hint: the backtrace further above shows the operation that failed to compute its gradient. The variable in question was changed in there or anywhere later. Good luck!
  

Ошибка без параметра

 RuntimeError: Trying to backward through the graph a second time, but the saved intermediate results have already been freed. Specify retain_graph=True when calling backward the first time.
  

что и ожидалось.

Пожалуйста, укажите, что нужно изменить в приведенном выше коде, чтобы он начал обучение. Любая помощь приветствуется.

Комментарии:

1. Вы пытались поместить оба optimizer.step() в конец? По сути, сначала выполните оба шага назад retain_graph=True , а в конце вы можете step использовать оба оптимизатора. Кроме того, даже для минимального проверяемого примера, возможно, было бы лучше объявить оптимизаторы и модели вне цикла (для корректности и во избежание путаницы).

2. @akshayk07 это сработало бы, но это превосходит цель. То, что я пытаюсь сделать, это обновить параметры сети, а затем получить «лучшую оценку» один раз step() , вызывается в первый раз. И да, спасибо, что указали на это, я внес изменения в MWE

3. @akshayk07 Мне очень жаль. Я пропустил строку. Теперь это имеет смысл? Итак, что я пытаюсь сделать, это обновить сеть 1 на первом проходе и использовать обновленный вывод для улучшения сети 2 на втором проходе

4. Я думаю, вы можете detach() после использования gru1 во второй раз, так как ваш 2-й оптимизатор обновляет только gru2 , т.Е. Нужны gru2 только градиенты.

5. @akshayk07 это сработало, не могли бы вы записать это в качестве ответа, чтобы я отметил, что это принято

Ответ №1:

В таком случае можно отсоединить график вычислений, чтобы исключить параметры, которые не нужно оптимизировать. В этом случае график вычислений должен быть отсоединен после второго прямого прохода с gru1 помощью, т.е.

 ....
gru1_opt.step()
gru1_output, _ = gru1(vector)
gru1_output = gru1_output.detach()
....
  

Таким образом, вы не будете «пытаться вернуться назад по графику во второй раз», как упоминалось в ошибке.