Сохранение скрытых слоёв обученной сети

Вопрос или проблема

Я использовал предобученную модель 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)

Если ваша цель состоит в том, чтобы загружать только часть модели, то вам нужно будет сохранять и загружать только веса. Это можно сделать, как описано в вашем втором варианте. Это дает вам больше гибкости, особенно если вы хотите изменить архитектуру модели.

Заключение

Следуя приведенным выше рекомендациям, вы должны без труда сохранять и загружать скрытые слои в вашей нейронной сети. Убедитесь, что вы сохраняете только необходимые компоненты и правильно загружаете их в соответствии с архитектурой вашей модели. Это не только улучшит производительность вашего кода, но и упростит повторное использование вашей модели в будущем. Если у вас есть дополнительные вопросы или требуется помощь, не стесняйтесь обращаться.

Оцените материал
Добавить комментарий

Капча загружается...