Transformers 文档

自定义模型

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始

自定义模型

Transformers 模型被设计为可自定义的。模型的代码完全包含在 Transformers 仓库的 model 子文件夹中。每个文件夹包含一个 modeling.py 和一个 configuration.py 文件。复制这些文件以开始自定义模型。

如果您要创建全新的模型,从头开始可能会更容易。但是对于与 Transformers 中现有模型非常相似的模型,重用或子类化相同的配置和模型类会更快。

本指南将向您展示如何自定义 ResNet 模型,启用 AutoClass 支持,并在 Hub 上共享它。

配置

配置,由基础 PretrainedConfig 类给出,包含构建模型的所有必要信息。您可以在这里配置自定义 ResNet 模型的属性。不同的属性会产生不同的 ResNet 模型类型。

自定义配置的主要规则是

  1. 自定义配置必须子类化 PretrainedConfig。这确保了自定义模型具有 Transformers 模型的所有功能,例如 from_pretrained()save_pretrained()push_to_hub()
  2. PretrainedConfig __init__ 必须接受任何 kwargs,并且它们必须传递给超类 __init__PretrainedConfig 具有比自定义配置中设置的字段更多的字段,因此当您使用 from_pretrained() 加载配置时,这些字段需要被您的配置接受并传递给超类。

检查某些参数的有效性很有用。在下面的示例中,实现了一个检查以确保 block_typestem_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)

使用 save_pretrained() 将配置保存到自定义模型文件夹 custom-resnet 中的 JSON 文件中。

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 模型。

ResnetModel
ResnetModelForImageClassification

定义块类型和类之间的映射。其他所有内容都是通过将配置类传递给 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)

模型可以返回任何输出格式。当标签可用时,返回带有损失的字典(如 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

AutoClass API 是自动为给定模型加载正确架构的快捷方式。为加载自定义模型的用户启用此功能很方便。

确保在配置类中具有 model_type 属性(必须与现有模型类型不同),并在模型类中具有 config_class 属性。使用 register() 方法将自定义配置和模型添加到 AutoClass API。

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)

您的自定义模型代码现在与 AutoClass API 兼容。用户可以使用 AutoModelAutoModelForImageClassification 类加载模型。

上传

将自定义模型上传到 Hub,以便其他用户可以轻松加载和使用它。

确保模型目录结构正确,如下所示。该目录应包含

  • modeling.py:包含 ResnetModelResnetModelForImageClassification 的代码。此文件可以依赖于与同一目录中其他文件的相对导入。

复制 Transformers 模型文件时,请替换 modeling.py 文件顶部的所有相对导入,以改为从 Transformers 导入。

  • configuration.py:包含 ResnetConfig 的代码。
  • __init__.py:可以为空,此文件允许将 Python resnet_model 用作模块。
.
└── 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")

要将多个任务映射到模型,请直接编辑配置 JSON 文件中的 auto_map

"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 帐户。

huggingface-CLI
笔记本
huggingface-cli login

在模型上调用 push_to_hub() 以将模型上传到 Hub。

resnet50d.push_to_hub("custom-resnet50d")

预训练权重、配置、modeling.pyconfiguration.py 文件现在都应上传到 Hub,并位于您命名空间下的 repository 中。

由于自定义模型不使用与 Transformers 模型相同的建模代码,因此您需要在 from_pretrained() 中添加 trust_remode_code=True 才能加载它。有关更多信息,请参阅加载自定义模型部分。

< > 在 GitHub 上更新