Как я могу обработать много потерь в pytorch? - PullRequest
0 голосов
/ 01 января 2019

enter image description here

Например, я хочу использовать некоторые дополнительные потери для повышения производительности моей модели.Какой код типа может реализовать его в pytorch?

#one
loss1.backward()
loss2.backward()
loss3.backward()
optimizer.step()
#two
loss1.backward()
optimizer.step() 
loss2.backward()
optimizer.step() 
loss3.backward()
optimizer.step()   
#three
loss = loss1+loss2+loss3
loss.backward()
optimizer.step()

Спасибо за ваш ответ!

Ответы [ 2 ]

0 голосов
/ 01 января 2019

Первая и третья попытки абсолютно одинаковы и правильны, в то время как второй подход совершенно неверен.

Причина в том, что в Pytorch градиенты нижнего слоя Не"перезаписаны" последующими backward() звонков, скорее они накапливаются или суммируются.Это делает первый и третий подход идентичными, хотя первый подход может быть предпочтительным, если у вас мало ГП / ОЗУ с малым объемом памяти, поскольку размер пакета 1024 с немедленным вызовом backward() + step() такой же, как с 8 пакетами размером 128 и 8 backward()звонки, с одним step() звонком в конце.

Чтобы проиллюстрировать идею, вот простой пример.Мы хотим, чтобы наш тензор x был ближайшим к [40,50,60] одновременно:

x = torch.tensor([1.0],requires_grad=True)
loss1 = criterion(40,x)
loss2 = criterion(50,x)
loss3 = criterion(60,x)

Теперь первый подход: (мы используем tensor.grad, чтобы получить градиент тока для нашего тензора x)

loss1.backward()
loss2.backward()
loss3.backward()

print(x.grad)

Это выводит: tensor([-294.]) (РЕДАКТИРОВАТЬ: поместите retain_graph=True в первых двух backward вызовах для более сложных вычислительных графов)

Третий подход:

loss = loss1+loss2+loss3
loss.backward()
print(x.grad)

Опять же вывод: tensor([-294.])

2-й подход отличается, потому что мы не вызываем opt.zero_grad после вызова step() метода.Это означает, что во всех 3 step вызовах используются градиенты первого backward вызова.Например, если 3 потери обеспечивают градиенты 5,1,4 для одного и того же веса, а не 10 (= 5 + 1 + 4), теперь ваш вес будет иметь 5*3+1*2+4*1=21 в качестве градиента.

Я согласен сзаключение, однако, используйте третий подход, если память не проблема.Для дальнейшего чтения: Ссылка 1 , Ссылка 2

0 голосов
/ 01 января 2019

- Комментарий к первому подходу удален, см. Другой ответ -

Ваш второй подход потребует от вас обратного распространения с retain_graph=True, что влечет за собой большие вычислительные затраты.Более того, это неправильно, так как вы обновили бы вес сети с первого шага оптимизатора, а затем ваш следующий вызов backward() вычислил бы градиенты до обновления, что означает, что вызов second step() вставит шум в вашобновления.Если, с другой стороны, вы выполнили еще один вызов forward() для обратного распространения через обновленные весовые коэффициенты, вы бы в итоге имели асинхронную оптимизацию, поскольку первые слои обновлялись бы один раз с первым step(), а затем еще раз для каждого последующегоstep() call (не по сути, но неэффективно и, вероятно, не совсем то, что вы хотели в первую очередь).

Короче говоря, путь - это последний подход.Сократите каждую потерю в скаляр, суммируйте потери и сделайте обратный расчет полученной потери.Примечание;убедитесь, что ваша схема сокращения имеет смысл (например, если вы используете сокращение = «сумма», а потери соответствуют классификации по нескольким меткам, помните, что число классов на цель отличается, поэтому относительный вес, вносимый каждой потерей, такжебыть другим)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...