Pytorch, `backward` RuntimeError: Попытка вернуться по графику второй раз, но буферы уже освобождены

Я реализую DDPG с PyTorch (0.4) и застрял, возвращая потерю. Итак, сначала мой код, выполняющий обновление:

def update_nets(self, transitions):
    """
    Performs one update step
    :param transitions: list of sampled transitions
    """
    # get batches
    batch = transition(*zip(*transitions))
    states = torch.stack(batch.state)
    actions = torch.stack(batch.action)
    next_states = torch.stack(batch.next_state)
    rewards = torch.stack(batch.reward)

    # zero gradients
    self._critic.zero_grad()

    # compute critic's loss
    y = rewards.view(-1, 1) + self._gamma * \
        self.critic_target(next_states, self.actor_target(next_states))

    loss_critic = F.mse_loss(y, self._critic(states, actions),
                             size_average=True)

    # backpropagte it
    loss_critic.backward()
    self._optim_critic.step()

    # zero gradients
    self._actor.zero_grad()

    # compute actor's loss
    loss_actor = ((-1.) * self._critic(states, self._actor(states))).mean()

    # backpropagate it
    loss_actor.backward()
    self._optim_actor.step()

    # do soft updates
    self.perform_soft_update(self.actor_target, self._actor)
    self.perform_soft_update(self.critic_target, self._critic)

Где self._actor, self._crtic, self.actor_target и self.critic_target - это сети.

Если я запустил это, я получу следующую ошибку на второй итерации:

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

at 

line 221, in update_nets
    loss_critic.backward()
line 93, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
line 89, in backward
    allow_unreachable=True)  # allow_unreachable flag

и я не знаю, чем это вызвано.

До сих пор я знал, что вызов loss_critic.backward() вызывает ошибку. Я уже отлаживал loss_critic - он получил допустимое значение. Если я заменю вычисление потерь простым

loss_critic = torch.tensor(1., device=self._device, dtype=torch.float, requires_grad=True)

Тензор, содержащий значение 1, работает нормально. Кроме того, я уже проверил, что не сохраняю некоторые результаты, которые могут вызвать ошибку. Кроме того, обновление актера с помощью loss_actor не вызывает никаких проблем.

Кто-нибудь знает, что здесь не так?

Спасибо!

Обновить

Я заменил

    # zero gradients
    self._critic.zero_grad()

а также

    # zero gradients
    self._actor.zero_grad()

с участием

    # zero gradients
    self._critic.zero_grad()
    self._actor.zero_grad()
    self.critic_target.zero_grad()
    self.actor_target.zero_grad()

(оба вызова), но он все еще не работает с той же ошибкой. Кроме того, код, выполняющий обновление в конце одной итерации

def perform_soft_update(self, target, trained):
    """
    Preforms the soft update
    :param target: Net to be updated
    :param trained: Trained net - used for update
    """
    for param_target, param_trained in \
            zip(target.parameters(), trained.parameters()):
        param_target.data.copy_(
            param_target.data * (
                    1.0 - self._tau) + param_trained * self._tau
        )

person bene    schedule 15.07.2018    source источник
comment
Отвечает ли это на ваш вопрос? Pytorch - RuntimeError: попытка вернуться назад график второй раз, но буферы уже освобождены   -  person Chris Stryczynski    schedule 05.12.2020


Ответы (2)


Я нашел решение. Я сохранил тензоры в моем replay_buffer для целей обучения, которые я использовал на каждой итерации, в результате чего получился фрагмент кода:

    # get batches
    batch = transition(*zip(*transitions))
    states = torch.stack(batch.state)
    actions = torch.stack(batch.action)
    next_states = torch.stack(batch.next_state)
    rewards = torch.stack(batch.reward)

Эта экономия тензоров является причиной проблемы. Поэтому я изменил свой код, чтобы сохранять только данные (tensor.data.numpy().tolist()) и помещать их в тензор только тогда, когда они мне нужны.

Более подробно: в DDPG я оцениваю политику на каждой итерации и делаю один шаг обучения с пакетом. Теперь я сохраняю оценку в буфере воспроизведения через:

action = self.action(state)
...
self.replay_buffer.push(state.data.numpy().tolist(), action.data.numpy().tolist(), ...)

И использовал это так:

batch = transition(*zip(*transitions))
states = self.to_tensor(batch.state)
actions = self.to_tensor(batch.action)
next_states = self.to_tensor(batch.next_state)
rewards = self.to_tensor(batch.reward)
person bene    schedule 19.07.2018
comment
Вы знаете, почему сохранение тензоров не сработало, но сработало сохранение базовых данных? Надеюсь узнать ответ. - person czxttkl; 07.02.2019
comment
Причина, по которой сохранение тензоров не работает, маршрутизируется в функции autograd / prop / ... тензоров. Я не знаю подробностей, но я читал, что вы всегда должны сохранять данные, а не тензор (практическое правило) ... - person bene; 10.02.2019
comment
Уточнение: конечно, вы должны использовать тензоры, например, вычислите свои потери (избегайте ненужного преобразования данных, особенно процессора-графического процессора ..). Но если вы хотите сохранить данные, чтобы использовать их позже, вы должны сохранить нужные данные, а не тензор отверстий. - person bene; 10.02.2019
comment
Причина ошибки (я думаю) в том, что когда вы вызываете backwards(), вычисляется град из каждого тензора. Если у вас есть сохраненный тензор, в котором уже сохранен градиент, вычисление завершится неудачно (поэтому необходимо вызвать _2 _) ... - person bene; 10.02.2019

Не звонили zero_grad() на self.actor_target и self.critic_target? Или это называется в self.perform_soft_update()?

person Escaton    schedule 16.07.2018
comment
Я этого не делал (потому что думал, что это не нужно), поэтому я добавил его (обновлю вопрос), но он все еще не работает с той же ошибкой - person bene; 16.07.2018