#machine-learning #deep-learning #pytorch
#машинное обучение #глубокое обучение #pytorch
Вопрос:
Я 3-месячный новичок DL, который занимается небольшими проектами NLP с Pytorch.
Недавно я пытаюсь повторно отобразить сеть GAN, представленную в статье, используя мои собственные текстовые данные, для генерации некоторых конкретных видов вопросительных предложений.
Вот некоторые предпосылки… Если у вас нет времени или интереса к этому, просто, пожалуйста, прочитайте следующий вопрос в порядке.
Как говорится в этой статье, генератор сначала обучается обычным образом с обычными данными вопроса, чтобы результат, по крайней мере, выглядел как настоящий вопрос. Затем, используя результат вспомогательного классификатора (классификации выходных данных), генератор снова обучается, чтобы просто генерировать конкретные (несколько уникальных категорий) вопросы.
Однако, поскольку в документе не раскрывается его код, я должен выполнить весь код самостоятельно. У меня есть эти три обучающие мысли, но я не знаю их различий, не могли бы вы любезно рассказать мне об этом?
Если они имеют почти одинаковый эффект, не могли бы вы сказать мне, что более рекомендуется в грамматике Pytorch? Большое вам спасибо!
Предположим, что потеря дискриминатора для генератора равна loss_G_D, потеря классификатора для генератора равна loss_G_C, а loss_G_D и loss_G_C имеют одинаковую форму, т.Е. [batch_size, значение потери], тогда в чем разница?
1.
optimizer.zero_grad()
loss_G_D = loss_func1(discriminator(generated_data))
loss_G_C = loss_func2(classifier(generated_data))
loss = loss_G loss_C
loss.backward()
optimizer.step()
optimizer.zero_grad()
loss_G_D = loss_func1(discriminator(generated_data))
loss_G_D.backward()
loss_G_C = loss_func2(classifier(generated_data))
loss_G_C.backward()
optimizer.step()
optimizer.zero_grad()
loss_G_D = loss_func1(discriminator(generated_data))
loss_G_D.backward()
optimizer.step()
optimizer.zero_grad()
loss_G_C = loss_func2(classifier(generated_data))
loss_G_C.backward()
optimizer.step()
Дополнительная информация: Я заметил, что потеря классификации классификатора всегда очень велика по сравнению с потерей генератора, например, -300 против 3. Так что, может быть, третий вариант лучше?
Ответ №1:
Прежде всего:
loss.backward()
ошибка распространяется в обратном направлении и присваивает градиент для каждого параметра на этом пути requires_grad=True
.
optimizer.step()
обновляет параметры модели, используя их сохраненные градиенты
optimizer.zero_grad()
устанавливает градиенты равными 0, чтобы вы могли распространять свои потери и обновлять параметры модели для каждого пакета, не вмешиваясь в другие пакеты.
1
и 2
они очень похожи, но если ваша модель использует пакетную статистику или у вас есть адаптивный оптимизатор, они, вероятно, будут работать по-другому. Однако, например, если ваша модель не использует пакетную статистику и у вас есть простой старый оптимизатор SGD, они выдадут тот же результат, хотя 1
и быстрее, поскольку вы выполняете backprop только один раз.
3
это совершенно другой случай, поскольку вы обновляете параметры своей модели loss_G_D.backward()
optimizer.step()
перед обработкой и обратным распространением loss_G_C
.
Учитывая все это, вам решать, какой из них выбрать, в зависимости от вашего приложения.
Комментарии:
1. 1 и 2 должны быть идентичными, поскольку градиенты накапливаются независимо друг от друга, и между ними нет шага обновления?
2. @unlut Да. Поскольку дифференцирование является линейным оператором, обратное распространение суммы потерь эквивалентно обратному распространению их по отдельности и накоплению градиентов
3. Но вы говорите, что они не всегда одинаковы.
4. Спасибо за ответ! Я использую оптимизатор Adam, поэтому я думаю, может быть, между 1 и 2, 2 лучше? И, как я думаю… Поскольку они оптимизируют сеть с разных сторон, возможно … между 2 и 3, 3 является более разумным.
5. @unlut Я говорю, что они, вероятно, не будут одинаковыми, если оптимизатор адаптивный или у вас есть уровень batchnorm или что-то в этом роде. Но, например, если вы используете SGD без batchnorm или других типов пакетных слоев, это должно быть то же самое