Transformers documentation
Настройка моделей
Настройка моделей
Модели Transformers спроектированы так, чтобы их можно было настраивать. Код модели полностью содержится в подпапке model репозитория Transformers. Каждая папка содержит файлы modeling.py и configuration.py. Скопируйте эти файлы, чтобы начать настраивать модель.
Если вы создаёте совершенно новую модель, проще начать с нуля. Однако для моделей, очень похожих на существующие в Transformers, быстрее переиспользовать или создать подкласс того же класса конфигурации и модели.
В этом руководстве показано, как настроить модель ResNet, включить поддержку AutoClass и опубликовать её на Hub.
Конфигурация
Конфигурация, задаваемая базовым классом PreTrainedConfig, содержит всю необходимую информацию для построения модели. Именно здесь вы настраиваете атрибуты пользовательской модели ResNet. Различные атрибуты определяют разные типы моделей ResNet.
Основные правила настройки конфигурации:
- A custom configuration must subclass PreTrainedConfig. This ensures a custom model has all the functionality of a Transformers’ model such as from_pretrained(), save_pretrained(), and push_to_hub().
- Метод
__init__класса PreTrainedConfig должен принимать любыеkwargs, и их необходимо передавать в метод__init__родительского класса. У PreTrainedConfig больше полей, чем тех, которые вы задаёте в своей конфигурации, поэтому при загрузке конфигурации с помощью from_pretrained() эти поля должны приниматься вашей конфигурацией и передаваться в родительский класс.
Полезно проверять корректность некоторых параметров. В примере ниже реализована проверка, гарантирующая, что
block_typeиstem_typeпринимают одно из предопределённых значений.Добавьте
model_typeв класс конфигурации, чтобы включить поддержку AutoClass.
from transformers import PreTrainedConfig
from typing import List
class ResnetConfig(PreTrainedConfig):
model_type = "resnet"
def __init__(
self,
block_type="bottleneck",
layers: list[int] = [3, 4, 6, 3],
num_classes: int = 1000,
input_channels: int = 3,
cardinality: int = 1,
base_width: int = 64,
stem_width: int = 64,
stem_type: str = "",
avg_down: bool = False,
**kwargs,
):
if block_type not in ["basic", "bottleneck"]:
raise ValueError(f"`block_type` must be 'basic' or bottleneck', got {block_type}.")
if stem_type not in ["", "deep", "deep-tiered"]:
raise ValueError(f"`stem_type` must be '', 'deep' or 'deep-tiered', got {stem_type}.")
self.block_type = block_type
self.layers = layers
self.num_classes = num_classes
self.input_channels = input_channels
self.cardinality = cardinality
self.base_width = base_width
self.stem_width = stem_width
self.stem_type = stem_type
self.avg_down = avg_down
super().__init__(**kwargs)Сохраните конфигурацию в файл JSON в вашей папке с кастомной моделью, custom-resnet, с помощью save_pretrained().
resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True)
resnet50d_config.save_pretrained("custom-resnet")Модель
С помощью пользовательской конфигурации ResNet теперь можно создавать и настраивать модель. Модель является подклассом базового класса PreTrainedModel. Как и в случае с PreTrainedConfig, наследование от PreTrainedModel и инициализация суперкласса с конфигурацией расширяет функциональность Transformers, такую как сохранение и загрузка, для пользовательской модели.
Модели Transformers следуют конвенции, согласно которой метод __init__ принимает объект config. Это позволяет передавать весь объект config в подслои модели, а не разбивать объект config на несколько аргументов, которые передаются в подслои по отдельности.
Написание моделей таким образом приводит к более простому коду с единым источником истины для всех гиперпараметров. Это также упрощает переиспользование кода из других моделей Transformers.
Вы создадите две модели ResNet: базовую модель ResNet, которая выводит скрытые состояния, и модель ResNet с головой для классификации изображений.
Определите соответствие между типами блоков и классами. Всё остальное создаётся путём передачи класса конфигурации в класс модели ResNet.
Добавьте
config_classв класс модели, чтобы включить поддержку AutoClass.
from transformers import PreTrainedModel
from timm.models.resnet import BasicBlock, Bottleneck, ResNet
from .configuration_resnet import ResnetConfig
BLOCK_MAPPING = {"basic": BasicBlock, "bottleneck": Bottleneck}
class ResnetModel(PreTrainedModel):
config_class = ResnetConfig
def __init__(self, config):
super().__init__(config)
block_layer = BLOCK_MAPPING[config.block_type]
self.model = ResNet(
block_layer,
config.layers,
num_classes=config.num_classes,
in_chans=config.input_channels,
cardinality=config.cardinality,
base_width=config.base_width,
stem_width=config.stem_width,
stem_type=config.stem_type,
avg_down=config.avg_down,
)
def forward(self, tensor):
return self.model.forward_features(tensor)Метод forward необходимо переписать, чтобы вычислять потерю для каждого логита, если метки доступны. В противном случае класс модели ResNet остаётся прежним.
Добавьте
config_classв класс модели, чтобы включить поддержку AutoClass.
import torch
class ResnetModelForImageClassification(PreTrainedModel):
config_class = ResnetConfig
def __init__(self, config):
super().__init__(config)
block_layer = BLOCK_MAPPING[config.block_type]
self.model = ResNet(
block_layer,
config.layers,
num_classes=config.num_classes,
in_chans=config.input_channels,
cardinality=config.cardinality,
base_width=config.base_width,
stem_width=config.stem_width,
stem_type=config.stem_type,
avg_down=config.avg_down,
)
def forward(self, tensor, labels=None):
logits = self.model(tensor)
if labels is not None:
loss = torch.nn.functional.cross_entropy(logits, labels)
return {"loss": loss, "logits": logits}
return {"logits": logits}Модель может возвращать любой формат вывода. Возврат словаря (как в ResnetModelForImageClassification) с потерями при наличии меток делает пользовательскую модель совместимой с Trainer. Для других форматов вывода потребуется собственный цикл обучения или другая библиотека для обучения.
Создайте экземпляр пользовательского класса модели с конфигурацией.
resnet50d = ResnetModelForImageClassification(resnet50d_config)
На этом этапе вы можете загрузить предобученные веса в модель или обучить её с нуля. В этом руководстве вы загрузите предобученные веса.
Загрузите предобученные веса из библиотеки timm, а затем перенесите их в пользовательскую модель с помощью load_state_dict.
import timm
pretrained_model = timm.create_model("resnet50d", pretrained=True)
resnet50d.model.load_state_dict(pretrained_model.state_dict())AutoClass
API AutoClass — это удобный способ автоматически загружать правильную архитектуру для заданной модели. Это упрощает работу пользователям, которые загружают вашу кастомную модель.
Убедитесь, что в классе конфигурации есть атрибут model_type (он должен отличаться от существующих типов моделей), а в классе модели — атрибут config_class. Используйте метод register(), чтобы добавить пользовательскую конфигурацию и модель в API AutoClass.
Первый аргумент AutoConfig.register() должен совпадать с атрибутом
model_typeв пользовательском классе конфигурации, а первый аргументAutoModel.register()должен совпадать сconfig_classпользовательского класса модели.
from transformers import AutoConfig, AutoModel, AutoModelForImageClassification
AutoConfig.register("resnet", ResnetConfig)
AutoModel.register(ResnetConfig, ResnetModel)
AutoModelForImageClassification.register(ResnetConfig, ResnetModelForImageClassification)Код вашей пользовательской модели теперь совместим с API AutoClass. Пользователи могут загрузить модель с помощью классов AutoModel или AutoModelForImageClassification.
Загрузка
Загрузите собственную модель в Hub, чтобы другие пользователи могли легко её загрузить и использовать.
Убедитесь, что каталог модели структурирован правильно, как показано ниже. Каталог должен содержать:
modeling.py: содержит код дляResnetModelиResnetModelForImageClassification. Этот файл может использовать относительные импорты из других файлов, если они находятся в той же директории.
При копировании файла модели Transformers замените все относительные импорты в начале файла
modeling.pyна импорты из Transformers.
configuration.py: содержит код дляResnetConfig.__init__.py: может быть пустым, этот файл позволяет использоватьresnet_modelв Python как модуль.
.
└── resnet_model
├── __init__.py
├── configuration_resnet.py
└── modeling_resnet.pyЧтобы поделиться моделью, импортируйте модель и конфигурацию ResNet.
from resnet_model.configuration_resnet import ResnetConfig
from resnet_model.modeling_resnet import ResnetModel, ResnetModelForImageClassificationСкопируйте код из файлов модели и конфигурации. Чтобы убедиться, что объекты AutoClass сохраняются с помощью save_pretrained(), вызовите метод register_for_auto_class(). Это изменяет JSON-файл конфигурации, добавляя в него объекты AutoClass и соответствующее отображение.
Для модели выберите подходящий класс AutoModelFor в зависимости от задачи.
ResnetConfig.register_for_auto_class()
ResnetModel.register_for_auto_class("AutoModel")
ResnetModelForImageClassification.register_for_auto_class("AutoModelForImageClassification")Чтобы сопоставить с моделью более одной задачи, отредактируйте auto_map непосредственно в конфигурационном файле JSON.
"auto_map": {
"AutoConfig": "<your-repo-name>--<config-name>",
"AutoModel": "<your-repo-name>--<config-name>",
"AutoModelFor<Task>": "<your-repo-name>--<config-name>",
},Создайте конфигурацию и модель и загрузите в неё предобученные веса.
resnet50d_config = ResnetConfig(block_type="bottleneck", stem_width=32, stem_type="deep", avg_down=True)
resnet50d = ResnetModelForImageClassification(resnet50d_config)
pretrained_model = timm.create_model("resnet50d", pretrained=True)
resnet50d.model.load_state_dict(pretrained_model.state_dict())Модель готова к публикации на Hub. Войдите в свой аккаунт Hugging Face из командной строки или ноутбука.
hf auth login
from huggingface_hub import notebook_login
notebook_login()Вызовите push_to_hub() для модели, чтобы загрузить её на Hub.
resnet50d.push_to_hub("custom-resnet50d")Предварительно обученные веса, конфигурация, файлы modeling.py и configuration.py должны быть загружены на Hub в репозиторий в вашем пространстве имён.
Поскольку пользовательская модель не использует тот же код моделирования, что и модели Transformers, для её загрузки необходимо добавить trust_remote_code=True в from_pretrained(). Подробнее см. в разделе о загрузке пользовательских моделей.