Вопрос или проблема
Я использовал предобученную модель VGG-19 для создания классификатора изображений в рамках MOOC. Я реализовал классификатор следующим образом:
classifier = nn.Sequential(nn.Linear(25088, 512),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(512,350),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(350,250),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(250,102),
nn.LogSoftmax(dim=1))
model.classifier = classifier
На следующем этапе меня попросили сохранить обученную модель, чтобы ее можно было использовать позже. Мое понимание сохранения такой модели заключалось в том, что мне нужно создать словарь с размером входа (данным предобученной моделью), размером выхода (данным моей конкретной задачей), состоянием модели и скрытыми слоями (данными моим собственным кодом). Я попытался сделать это следующим образом:
checkpoint = {'input_size':25088,
'output_size':102,
'hidden_layers':[each for each in model.classifier],
'state_dict':model.state_dict(),
'optimizer':optimizer.state_dict(),
'epochs':epochs,
'class_to_index':cat_to_name}
Затем я попытался загрузить это следующим образом:
def load_checkpoint(path):
checkpoint = torch.load(path)
model = nn.Sequential(checkpoint['input_size'],
checkpoint['output_size'],
checkpoint['hidden_layers'])
model.load_state_dict(checkpoint['state_dict'])
epochs = checkpoint['epochs']
model.class_to_idx = checkpoint['class_to_index']
return model, epochs
test_model, _ = load_checkpoint('trained_model.pth')
print(test_model)
Однако это вызывает ошибку:
TypeError: int is not a Module subclass
Что я сделал не так? Насколько я могу судить, checkpoint[‘hidden_layers’] не содержит целых чисел:
print(checkpoint['hidden_layers'])
Возвращает:
[Linear(in_features=25088, out_features=512, bias=True), ReLU(), Dropout(p=0.2), Linear(in_features=512, out_features=350, bias=True), ReLU(), Dropout(p=0.2), Linear(in_features=350, out_features=250, bias=True), ReLU(), Dropout(p=0.2), Linear(in_features=250, out_features=102, bias=True), LogSoftmax()]
Что я и ожидал.
Спасибо за внимание! Любые мысли или комментарии будут очень приветствоваться!
Есть несколько ошибок. Вот как вам нужно изменить свой код. Я не уверен, из чего состоит ваш класс модели, но надеюсь, что это класс с функцией .classifier, которая состоит из сети.
def load_checkpoint(model, path):
checkpoint = torch.load(path)
model.classifier.load_state_dict(checkpoint['state_dict'])
epochs = checkpoint['epochs']
model.class_to_idx = checkpoint['class_to_index']
return model, epochs
classifier = nn.Sequential(nn.Linear(25088, 512),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(512,350),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(350,250),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(250,102),
nn.LogSoftmax(dim=1))
model.classifier = classifier
test_model, _ = load_checkpoint(model, 'trained_model.pth')
print(test_model)
Точно так же вам нужно загрузить оптимизатор, планировщик и другие атрибуты, если вы хотите переобучить сеть.
Если ваша цель состоит в том, чтобы загрузить только часть сети, а не всю сеть. Что-то вроде этого:
classifier = nn.Sequential(nn.Linear(25088, 512),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(512,350),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(350,250))
model.classifier = classifier
weights = torch.load("weight.pth")
state_dict = model.classifier.state_dict()
for name, param in model.classifier.named_parameters():
if name in state_dict.keys():
state_dict[name] = weights["state_dict"][name]
model.classifier.load_state_dict(state_dict)
Тем самым вы можете загрузить только ту часть сети, которая необходима.
Ответ или решение
Для сохранения и загрузки скрытых слоев обученной нейронной сети, такой как VGG-19, необходимо учитывать несколько ключевых аспектов. В вашем коде, вы уже сделали большой объем работы, однако возникла ошибка, связанная с неправильной конструкцией при загрузке модели. Позвольте мне рассмотреть этот вопрос в деталях.
1. Сохранение модели
Ваш код сохранения модели выглядит правильно, за исключением того, что в качестве скрытых слоев вы добавляете их элементы в список. Это нормально, но при загрузке необходимо учитывать, что nn.Sequential
ожидает модуль, а не список. Вам не нужно передавать скрытые слои как отдельный список в nn.Sequential
.
Ваш код для создания контрольного пункта выглядит следующим образом:
checkpoint = {
'input_size': 25088,
'output_size': 102,
'hidden_layers': [each for each in model.classifier],
'state_dict': model.state_dict(),
'optimizer': optimizer.state_dict(),
'epochs': epochs,
'class_to_index': cat_to_name
}
2. Загрузка модели
Ошибка, которую вы видите (TypeError: int is not a Module subclass
), указывает на то, что вы пытаетесь передать целое число в nn.Sequential
, что неправильно. Вместо этого вы должны использовать сами объекты класса, а не их размеры.
Исправленная версия функции load_checkpoint
будет выглядеть так:
def load_checkpoint(model, path):
checkpoint = torch.load(path)
model.classifier.load_state_dict(checkpoint['state_dict']) # Загружаем только состояние классификатора
epochs = checkpoint['epochs']
model.class_to_idx = checkpoint['class_to_index'] # Загружаем индекс классов
return model, epochs
3. Создание модели
При создании вашей модели необходимо убедиться, что вы добавляете к ней классификатор правильно. Код создания классификатора можно оставить без изменений, но вы должны убедиться, что инициализируете model
как объект класса, который включает в себя ваш классификатор.
classifier = nn.Sequential(
nn.Linear(25088, 512),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(512, 350),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(350, 250),
nn.ReLU(),
nn.Dropout(p=0.2),
nn.Linear(250, 102),
nn.LogSoftmax(dim=1)
)
model.classifier = classifier
4. Полная загрузка
Теперь, когда вы хотите загрузить модель, вызовите вашу функцию следующим образом:
test_model, _ = load_checkpoint(model, 'trained_model.pth')
print(test_model)
Если ваша цель состоит в том, чтобы загружать только часть модели, то вам нужно будет сохранять и загружать только веса. Это можно сделать, как описано в вашем втором варианте. Это дает вам больше гибкости, особенно если вы хотите изменить архитектуру модели.
Заключение
Следуя приведенным выше рекомендациям, вы должны без труда сохранять и загружать скрытые слои в вашей нейронной сети. Убедитесь, что вы сохраняете только необходимые компоненты и правильно загружаете их в соответствии с архитектурой вашей модели. Это не только улучшит производительность вашего кода, но и упростит повторное использование вашей модели в будущем. Если у вас есть дополнительные вопросы или требуется помощь, не стесняйтесь обращаться.