У меня есть CNN с многочисленными сверточными слоями. К каждому из этих сверточных слоев я прикрепил классификатор для проверки выходных данных промежуточных слоев. После того, как потери были произведены для каждого из этих классификаторов, я хочу обновить веса для классификатора, не касаясь весов для сверточных слоев. Этот код:
for i in range(len(loss_per_layer)):
loss_per_layer[i].backward(retain_graph=True)
self.classifiers[i].weight.data -= self.learning_rate * self.alpha[i] * self.classifiers[i].weight.grad.data
self.classifiers[i].bias.data -= self.learning_rate * self.alpha[i] * self.classifiers[i].bias.grad.data
позволяет мне сделать это, если классификатор состоит из единственного nn.Linear слоя. Однако мои классификаторы имеют форму:
self.classifiers.append(nn.Sequential(
nn.Linear(int(feature_map * input_shape[1] * input_shape[2]), 100),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(100, self.num_classes),
nn.Sigmoid(),
))
Как я могу обновить веса последовательного блока, не касаясь остальной сети? Я недавно перешел с keras на pytorch и поэтому не уверен, как именно использовать функцию optimizer.step () в этой ситуации, но у меня есть подозрение, что это можно сделать с ее помощью.
Обратите внимание, мне нужно общее решение для последовательного блока любой формы, так как оно изменится в будущих итерациях модели.
Любая помощь горячо приветствуется.
Вы можете реализовать свою модель, как показано ниже:
При объявлении оптимизатора передавайте только те параметры, которые вы хотите обновить.
Теперь, когда ты будешь делать
будут обновлены только параметры классификатора.
РЕДАКТИРОВАТЬ: после комментария OP я добавляю ниже для более общих вариантов использования.
Более общий сценарий
Спасибо. Будет ли это работать, если: у меня два сверточных слоя, я присоединяю второй сверточный слой к первому. Затем я прикрепляю классификатор к первому сверточному слою, а классификатор — ко второму сверточному слою. Затем я хочу обновить каждый классификатор с учетом градиента потерь, исходящих от этого классификатора. Думаю, тогда мне нужно сделать отдельный оптимизатор для каждого классификатора, верно? — person Kroshtan; 26.01.2021
Я понимаю, что вы имеете в виду, я обновляю ответ, чтобы отразить более общий сценарий. Надеюсь, это поможет. — person Kroshtan; 26.01.2021
Спасибо, похоже, алгоритмически это помогает. Однако теперь я получаю сообщение об ошибке: одна из переменных, необходимых для вычисления градиента, была изменена операцией на месте. Мне кажется, что я установил inplace = False везде, где это возможно. Может ли это иметь какое-то отношение к обновлению нескольких выходных слоев? — person Kroshtan; 28.01.2021
@Kroshtan Это не должно быть из-за этого … скорее всего. Я вижу, где это могло бы создать проблему, если бы вы могли поделиться кодом? — person Kroshtan; 28.01.2021
Если вы используете встроенный — или настраиваемый — _1 _, то вам не нужно выполнять обновление параметров вручную. Вы можете просто заморозить слои, которые не хотите обновлять (отключив их флаг
requires_grad
). Вызов.backward()
по поводу вашей потери, тогдаoptimizer.step()
только обновит классификатор.В зависимости от архитектуры вашей
torch.nn.Module
модели вы можете сделать что-то вроде этого:Где
model.feature_extractor
будет заголовком вашей модели, содержащей сверточные слои (т.е. экстрактор признаков). Таким образом можно зацикливаться на любом модуле, и.parameters()
будет перебирать все параметры дочерних параметров этого модуля для деактивацииrequires_grad
.