Правильная загрузка предварительно обученных весов в Pytorch

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

Следовательно, я загружаю свой набор данных, выполняю типичное преобразование, аналогичное ImageNet, затем загружаю модель, отключаю градацию на всех ее слоях, удаляю последний слой и добавляю обучаемый, используя количество классов моего набора данных. Мой код мог бы выглядеть следующим образом:

#retrained_vit_weights = torchvision.models.ViT_B_16_Weights.DEFAULT # requires torchvision >= 0.13, "DEFAULT" means best available
#pretrained_vit = torchvision.models.vit_b_16(weights=pretrained_vit_weights).to(device)
pretrained_vit = torch.hub.load('facebookresearch/deit:main', 'deit_tiny_patch16_224', pretrained=True).to(device)

for parameter in pretrained_vit.parameters():
    parameter.requires_grad = False

pretrained_vit.heads = nn.Linear(in_features=192, out_features=len(class_names)).to(device)
optimizer(torch.optim.Adam(params=pretrained_vit.parameters(), ... )
loss_fn = torch.nn.CrossEntropyLoss()

esults = engine.train(model=pretrained_vit, ..., ... )

Когда я использую torchvision.models.ViT_B_16_Weights.DEFAULT, код работает плавно, и я могу без проблем запустить свой код. Однако, когда я вместо этого использую deit_tiny_patch16_224 и устанавливаю requires_grade = False, я получаю следующую ошибку:

Variable._execution_engine.run_backward(  # Calls into the C++ engine to run the backward pass
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

Когда для переменной установлено значение True, код работает гладко, но обучение действительно плохое, поскольку у меня было очень мало изображений. Как мне правильно установить параметры deit_tiny_patch16_224 на parameter.requires_grad = False?

Есть ли проблема с тем, как я загружаю предварительно подготовленные веса?

Вы используете nn.Module.requires_grad_?

Ivan 12.04.2024 16:53

Да, я так думаю. Поскольку я просматриваю все параметры модели и отключаю градиенты, я предполагаю, что это действительно nn.Module.requires_grad_

Jose Ramon 12.04.2024 17:40
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
163
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы посмотрите описание модели, распечатав его, вы увидите полностью связанный слой классификатора в качестве ключевого имени "head", а не "heads". На моей стороне работает следующий код:

for parameter in pretrained_vit.parameters():
    parameter.requires_grad = False
pretrained_vit.head = nn.Linear(in_features=192, out_features=10)
pretrained_vit(torch.rand(1,3,224,224)).mean().backward()

Я рекомендую использовать nn.Module.requires_grad_ вместо того, чтобы самостоятельно устанавливать атрибут для каждого параметра тензора. Имейте в виду, что с вашим текущим кодом вся модель будет заморожена, включая слой классификатора, поэтому вы можете захотеть разморозить этот слой:

pretrained_vit.requires_grad_(False)
pretrained_vit.head = nn.Linear(in_features=192, out_features=10)
pretrained_vit.head.requires_grad_(True)

О, я думаю, у двух моделей были разные названия, и это помогло. Спасибо за помощь :). Что касается вашего второго пункта, какая именно разница, если я установлю все, кроме последнего слоя, через цикл? Разве не то же самое и с вашим предложением?

Jose Ramon 12.04.2024 18:31

Вместо того, чтобы назначать атрибут requires_grad всех ваших тензоров False, вы можете просто вызвать requires_grad_ родительского nn.Module, это просто удобнее и понятнее, но ваш способ тоже работает (пока вы не затрагиваете последний слой).

Ivan 14.04.2024 23:34

Другие вопросы по теме