Pytorch: Как оптимизировать несколько переменных по отношению к множественным потерям? - PullRequest
0 голосов
/ 27 апреля 2020

Я хочу, чтобы у разных потерь были рассчитаны их градиенты по отношению к разным переменным, а затем все эти переменные объединятся.

Вот простой пример, демонстрирующий то, что я хочу:

import torch as T
x = T.randn(3, requires_grad = True)
y = T.randn(4, requires_grad = True)
z = T.randn(5, requires_grad = True)

x_opt = T.optim.Adadelta([x])
y_opt = T.optim.Adadelta([y])
z_opt = T.optim.Adadelta([z])

for i in range(n_iter):
  x_opt.zero_grad()
  y_opt.zero_grad()
  z_opt.zero_grad()

  shared_computation = foobar(x, y, z)

  x_loss = f(x, y, z, shared_computation)
  y_loss = g(x, y, z, shared_computation)
  z_loss = h(x, y, z, shared_computation)

  x_loss.backward_with_respect_to(x)
  y_loss.backward_with_respect_to(y)
  z_loss.backward_with_respect_to(z)

  x_opt.step()
  y_opt.step()
  z_opt.step()

Мой вопрос: как нам сделать эту backward_with_respect_to часть в PyTorch? Мне нужен только градиент x относительно x_loss и т. Д. c .. А затем я хочу, чтобы все оптимизаторы объединялись (основываясь на текущих значениях x, y и z) .

1 Ответ

0 голосов
/ 01 мая 2020

Я написал функцию для этого. Два ключевых компонента: (1) использование retain_graph=True для всех, кроме последнего вызова .backward() и (2) сохранение оценок после каждого вызова .backward() и восстановление их в конце перед .step() ing.

def multi_step(losses, optms):
  # optimizers each take a step, with `optms[i]`'s variables being 
  # optimized w.r.t. `losses[i]`.
  grads = [None]*len(losses)
  for i, (loss, optm) in enumerate(zip(losses, optms)):
    retain_graph = i != (len(losses)-1)
    optm.zero_grad()
    loss.backward(retain_graph=retain_graph)
    grads[i] = [ 
          [ 
            p.grad+0 for p in group['params'] 
          ] for group in optm.param_groups
        ]
  for optm, grad in zip(optms, grads):
    for p_group, g_group in zip(optm.param_groups, grad):
      for p, g in zip(p_group['params'], g_group):
        p.grad = g
    optm.step()

В примере кода, указанного в вопросе, multi_step будет использоваться следующим образом:

for i in range(n_iter):
  shared_computation = foobar(x, y, z)

  x_loss = f(x, y, z, shared_computation)
  y_loss = g(x, y, z, shared_computation)
  z_loss = h(x, y, z, shared_computation)

  multi_step([x_loss, y_loss, z_loss], [x_opt, y_opt, z_opt])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...