Transformers 文档

模块化Transformers

Hugging Face's logo
加入 Hugging Face 社区

并获取增强的文档体验

开始使用

模块化Transformers

模块化 Transformers 降低了贡献模型的门槛,并通过允许导入和继承,显著减少了添加模型所需的代码。

Transformers 的核心设计特点之一是单模型、单文件策略。模型组件(例如注意力层)在许多文件中重复出现,并且当修复和更改应用于代码的特定部分时,任何独立的实现都容易出现分歧。

# Copied from 语句防止代码分歧,并通过我们的持续集成测试和本地命令强制执行。缺点是这种方法很繁琐,并且添加了大量代码行,其中大部分是样板代码。

动机

模块化 Transformers 通过在模型文件夹中添加一个模块化文件来解决这些问题。与传统的建模和处理文件不同,模块化文件可以从其他模型导入代码,并从其他类继承代码。

模块化 Transformers 并非旨在取代建模代码,如果您的模型不是基于现有模型,则需要手动添加 modeling.py 文件。同样,如果配置、分词或处理文件无法轻易地从类似文件继承,您可以直接添加该文件。

模块化文件包含模型、处理器和配置类代码,这些代码在单模型、单文件策略下通常会放在单独的文件中。

模型用户仍然导入和使用他们已经熟悉的单文件接口。通过这样做,我们希望在坚持我们的理念的同时,实现更简单的贡献。

创建 modeling.py 文件

linter 将模块化文件“展开”为 modeling.py 文件,以保留单模型、单文件目录结构(modeling、processor 等)。继承被扁平化为仅单层

运行以下命令以从模块化文件自动生成 modeling.py 文件。

python utils/modular_model_converter.py --files_to_parse src/transformers/models/<your_model>/modular_<your_model>.py

例如

  • 如果配置类从另一个类继承,但添加和删除一个参数,则如果添加了参数,则生成的文件直接引用它;如果删除了参数,则完全删除它。
  • 如果一个类从另一个类继承,例如 GemmaModel(LlamaModel),则会自动推断依赖项。所有子模块也会自动从超类中推断出来。
  • 如果在模块化文件中定义了一个新函数并在类内部使用,linter 也会自动推断这些函数。

您应该能够在一个模块化文件中编写所有内容(tokenizer、图像处理器、模型、配置等),并生成其对应的单文件。

运行以下命令以确保生成的内容与 modular_.py 匹配。

python utils/check_modular_conversion.py --files src/transformers/models/<your_model>/modular_<your_model>.py

下面的示例演示了如何使用模块化 Transformers 以更少的代码行添加模型。

BERT 和 RoBERTa

BERT 和 RoBERTa 这两个非常相似的模型,仅在嵌入层的实现方式上有所不同。

与其完全重新定义模型,不如考虑下面显示的 modular_roberta.py 文件,用于建模和配置类(本示例中未显示 tokenizer)。

from torch import nn
from ..bert.configuration_bert import BertConfig
from ..bert.modeling_bert import (
    BertModel,
    BertEmbeddings,
    BertForMaskedLM
)

# RoBERTa and BERT config is identical
class RobertaConfig(BertConfig):
  model_type = 'roberta'

# Redefine the embeddings to highlight the padding id difference, and redefine the position embeddings
class RobertaEmbeddings(BertEmbeddings):
    def __init__(self, config):
        super().__init__(config())

        self.padding_idx = config.pad_token_id
        self.position_embeddings = nn.Embedding(
            config.max_position_embeddings, config.hidden_size, padding_idx=self.padding_idx
        )

# RoBERTa and BERT model is identical except for the embedding layer, which is defined above, so no need for additional changes here
class RobertaModel(BertModel):
  def __init__(self, config):
    super().__init__(config)
    self.embeddings = RobertaEmbeddings(config)


# The model heads now only need to redefine the model inside to `RobertaModel`
class RobertaForMaskedLM(BertForMaskedLM):
  def __init__(self, config):
    super().__init__(config)
    self.model = RobertaModel(config)

如果您不使用定义的依赖项,您将收到以下错误。

ValueError: You defined `RobertaEmbeddings` in the modular_roberta.py, it should be used when you define `BertModel`, as it is one of it's direct dependencies. Make sure you use it in the `__init__` function.

实现模块化文件

最简单的入门方法是浏览 Transformers,查找与您的模型相似的模型,以便从中继承。一些好的起点是 MistralQwen2CohereCohere 以及 Llama。请参考下表,了解您的模型可能正在使用的组件以及您可以从哪里继承。

组件 模型
专家混合 SwitchTransformers 或 Mixtral
交错(和/或部分)旋转嵌入 GLM, Phi
状态空间模型 Jamba, Bamba, Zamba, Mamba2
循环隐藏状态 Gemma2
每层滑动窗口注意力/全注意力模式 Gemma2, Cohere2
QKV 裁剪 Olmo
QK 归一化 Olmo2, Cohere
融合 QKV(不推荐) Phi3

本节将引导您了解如何使用模块化 Transformers 从 Olmo 实现 Olmo2(您可以参考原始的 modeling.py 文件)。

配置

模块化的 Olmo2Config 如下所示。

from ..olmo.configuration_olmo import OlmoConfig

class Olmo2Config(OlmoConfig):
    r"""
    This is the configuration class to store the configuration of a [Olmo2Model](/docs/transformers/main/en/model_doc/olmo2#transformers.Olmo2Model).
    """

    def __init__(
        self,
        vocab_size=50304,
        hidden_size=4096,
        intermediate_size=11008,
        num_hidden_layers=32,
        num_attention_heads=32,
        num_key_value_heads=None,
        hidden_act="silu",
        max_position_embeddings=2048,
        initializer_range=0.02,
        use_cache=True,
        pad_token_id=1,
        bos_token_id=None,
        eos_token_id=50279,
        tie_word_embeddings=False,
        rope_theta=10000.0,
        rope_scaling=None,
        attention_bias=False,
        attention_dropout=0.0,
        rms_norm_eps=1e-5,
        **kwargs,
    ):
        super().__init__(
            vocab_size=vocab_size,
            hidden_size=hidden_size,
            intermediate_size=intermediate_size,
            num_hidden_layers=num_hidden_layers,
            num_attention_heads=num_attention_heads,
            num_key_value_heads=num_key_value_heads,
            hidden_act=hidden_act,
            max_position_embeddings=max_position_embeddings,
            initializer_range=initializer_range,
            use_cache=use_cache,
            pad_token_id=pad_token_id,
            bos_token_id=bos_token_id,
            eos_token_id=eos_token_id,
            tie_word_embeddings=tie_word_embeddings,
            rope_theta=rope_theta,
            rope_scaling=rope_scaling,
            attention_bias=attention_bias,
            attention_dropout=attention_dropout,
            **kwargs,
        )

        self.rms_norm_eps = rms_norm_eps
        del self.clip_qkv

Olmo2Config 与原始 OlmoConfig 有三个不同之处。

  1. 大多数参数的默认值已更改。
  2. 有一个新参数 rms_norm_eps
  3. clip_qkv 参数不再使用。

对于新的默认值和参数,请使用新的默认值覆盖 __init__ 函数,并添加 rms_norm_eps。在 __init__ 的主体中,将 rms_norm_eps 赋值给 self。对于 clip_qkv 参数,请使用 del self.clip_qkv 删除在展开代码(linter 转换后)中对此属性的赋值。

请注意 super().__init__(...) 的使用方式。通常,它会调用父类的 __init__

但在模块化 Transformers 中,如果存在类似 super().my_function(...) 的调用,则 linter 会获取父类中 my_function 的主体,并在 super().my_function(...) 调用发生的位置展开它。del self.clip_qkv 语句删除对展开主体中 self.clip_qkv 的引用。

del self.super().my_function(..) 协同工作,并且应始终放在 super().my_function(...) 之后。您可以在调用 super() 之前添加任何内容,它将放在父类主体之前。

Norm

from ..llama.modeling_llama import LlamaRMSNorm

class Olmo2RMSNorm(LlamaRMSNorm):
    pass

LlamaRMSNorm 中无需修改任何内容。linter 将 LlamaRMSNorm 的确切内容展开到 Olmo2RMSNorm 中。文档字符串、类型提示和注释中对 Llama 的引用也更改为 Olmo2。

注意力

模块化的 Olmo2Attention 如下所示。

from ..llama.modeling_llama import eager_attention_forward
from ..olmo.modeling_olmo import OlmoAttention, apply_rotary_pos_emb


# Olmo2 attention is identical to OLMo attention except:
# - Norm is applied to attention queries and keys.
# - No qkv clipping.
class Olmo2Attention(OlmoAttention):
    def __init__(self, config: Olmo2Config, layer_idx: Optional[int] = None):
        super().__init__(config, layer_idx=layer_idx)
        self.q_norm = Olmo2RMSNorm(config.num_attention_heads * self.head_dim, config.rms_norm_eps)
        self.k_norm = Olmo2RMSNorm(config.num_key_value_heads * self.head_dim, config.rms_norm_eps)

    def forward(
        self,
        hidden_states: torch.Tensor,
        position_embeddings: Tuple[torch.Tensor, torch.Tensor],
        attention_mask: Optional[torch.Tensor],
        past_key_value: Optional[Cache] = None,
        cache_position: Optional[torch.LongTensor] = None,
        **kwargs,
    ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
        input_shape = hidden_states.shape[:-1]
        hidden_shape = (*input_shape, -1, self.head_dim)

        query_states = self.q_norm(self.q_proj(hidden_states))
        key_states = self.k_norm(self.k_proj(hidden_states))
        value_states = self.v_proj(hidden_states)

        query_states = query_states.view(hidden_shape).transpose(1, 2)
        key_states = key_states.view(hidden_shape).transpose(1, 2)
        value_states = value_states.view(hidden_shape).transpose(1, 2)

        cos, sin = position_embeddings
        query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)

        if past_key_value is not None:
            # sin and cos are specific to RoPE models; cache_position needed for the static cache
            cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
            key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)

        attention_interface: Callable = eager_attention_forward
        if self.config._attn_implementation != "eager":
            if self.config._attn_implementation == "sdpa" and kwargs.get("output_attentions", False):
                logger.warning_once(
                    "`torch.nn.functional.scaled_dot_product_attention` does not support `output_attentions=True`. Falling back to "
                    'eager attention. This warning can be removed using the argument `attn_implementation="eager"` when loading the model.'
                )
            else:
                attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]

        attn_output, attn_weights = attention_interface(
            self,
            query_states,
            key_states,
            value_states,
            attention_mask,
            dropout=0.0 if not self.training else self.attention_dropout,
            scaling=self.scaling,
            **kwargs,
        )

        attn_output = attn_output.reshape(*input_shape, -1).contiguous()
        attn_output = self.o_proj(attn_output)
        return attn_output, attn_weights

super().__init__(...) 复制父类定义,并从 Olmo2RMSNorm 添加 2 个新层。需要覆盖前向传递以使用这两个新层。在使用 q_projk_proj 投影之前,添加了带有 norm 层的传递。为了更方便,eager_attention_forward 函数直接从 Llama 导入,apply_rotary_pos_emb 从 Olmo 导入。

linter 通过从源文件复制其定义,自动将这些导入的函数添加到最终的 modeling_olmo2.py 文件中。rotate_halfrepeat_kv 函数也被添加,因为它们在 apply_rotary_pos_embeager_attention_forward 内部使用。

必须重新定义 Attention 类,因为没有任何现有模型具有包含 RMSNorm 层的 Attention 层。

解码器层

模块化的 DecoderLayer 如下所示。

from ..olmo.modeling_olmo import OlmoDecoderLayer

# The OLMo2 layers are identical to those of the OLMo model except:
# - RMSNorm is used instead of standard layer norm.
# - Norm is applied after attention/feedforward rather than before.
class Olmo2DecoderLayer(OlmoDecoderLayer):
    def __init__(self, config: Olmo2Config, layer_idx: int):
        super().__init__(config, layer_idx=layer_idx)
        self.post_attention_layernorm = Olmo2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
        self.post_feedforward_layernorm = Olmo2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
        self.self_attn = Olmo2Attention(config=config, layer_idx=layer_idx)
        del self.input_layernorm

    def forward(
        self,
        hidden_states: torch.Tensor,
        attention_mask: Optional[torch.Tensor] = None,
        position_ids: Optional[torch.LongTensor] = None,
        past_key_value: Optional[Cache] = None,
        output_attentions: Optional[bool] = False,
        use_cache: Optional[bool] = False,
        cache_position: Optional[torch.LongTensor] = None,
        position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,  # necessary, but kept here for BC
        **kwargs,
    ) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
        residual = hidden_states

        # Self Attention
        hidden_states, self_attn_weights = self.self_attn(
            hidden_states=hidden_states,
            attention_mask=attention_mask,
            position_ids=position_ids,
            past_key_value=past_key_value,
            output_attentions=output_attentions,
            use_cache=use_cache,
            cache_position=cache_position,
            position_embeddings=position_embeddings,
            **kwargs,
        )
        hidden_states = self.post_attention_layernorm(hidden_states)
        hidden_states = residual + hidden_states

        # Fully Connected
        residual = hidden_states
        hidden_states = self.mlp(hidden_states)
        hidden_states = self.post_feedforward_layernorm(hidden_states)
        hidden_states = residual + hidden_states

        outputs = (hidden_states,)
        if output_attentions:
            outputs += (self_attn_weights,)

        return outputs

norm 类型在 __init__ 中切换,方法是在调用 super().__init__(...) 后覆盖 self.post_attention_layernorm。删除 self.input_layernorm 属性,并将其替换为 self.post_feedforward_layernorm,因为它在 Olmo2 中是在之后应用的。覆盖 forward 方法以反映此更改。

如果您仅将 self.post_feedforward_layernormself.input_layernormLayerNorm 切换到 RMSNorm,而没有同时更改 self.input_layernorm 的名称和逻辑,那么您就不必重写 forward 方法。

模型

模块化的 Olmo2Model 类如下所示。

from ..olmo.modeling_olmo import OlmoModel

# The OLMo2 model is identical to the OLMo model, except RMSNorm is used instead of
# standard layer norm for the output norm.
class Olmo2Model(OlmoModel):
    def __init__(self, config: Olmo2Config):
        super().__init__(config)
        self.norm = Olmo2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
        self.layers = nn.ModuleList(
            [Olmo2DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
        )

您只需要更改 self.norm 属性的类型,以使用 RMSNorm 而不是 LayerNorm。此更改不会影响 forward 方法中的逻辑(层名称和用法与父类相同),因此您无需覆盖它。linter 会自动展开它。

模型头

模块化的因果建模头如下所示。

from ..olmo.modeling_olmo import OlmoForCausalLM

class Olmo2ForCausalLM(OlmoForCausalLM):
    pass

逻辑与 OlmoForCausalLM 相同,这意味着您无需在此处进行任何更改。

其他类

linter 生成的 modeling_olmo2.py 还包含一些在 modular_olmo2.py 中未显式定义的类(Olmo2MLPOlmo2RotaryEmbeddingOlmo2PreTrainedModel)。

作为继承类的依赖项但未显式定义的类会自动添加为依赖项跟踪的一部分。这类似于在没有直接导入的情况下将某些函数添加到 Attention 类的方式。

例如,OlmoDecoderLayer 具有一个属性定义为 self.mlp = OlmoMLP(config)。这个类从未在 Olmo2MLP 中显式重新定义,因此 linter 自动创建了一个类似于 OlmoMLPOlmo2MLP 类。如果它是显式写入 modular_olmo2.py 的,则它与下面的代码相同。

from ..olmo.modeling_olmo import OlmoMLP

class Olmo2MLP(OlmoMLP):
    pass

但是,有必要重写 Olmo2RMSNorm,因为需要在 AttentionDecoderLayer 类中重新定义层归一化。同样,这就是您不需要创建 Olmo2PreTrainedModelOlmo2RotaryEmbedding 类的原因。

未重写的类是从继承模块首次使用它们的文件中复制的。这意味着如果您希望 Olmo2MLPMistralMLP 继承,则需要更明确,如下所示。

# switch to mistral definition
from ..mistral.modeling_mistral import MistralMLP

class Olmo2MLP(MistralMLP):
    pass

移除属性

您可以使用 del 在使用 super().__init__() 后删除父类中定义的属性。但是,如果该属性也在其他地方使用,如下所示,则此方法不起作用。它仅抑制赋值。self.attribute = config.attribute 行被删除,但 if 语句仍然存在并引用该属性。

class DummyModel(nn.Module):

  def __init__(self, config: DummyConfig):
    super().__init__()
    self.attribute = config.attribute
    if self.attribute:
      # do more stuff with `self.attribute` here
      ...

class MyNewDummyModel(DummyModel):

  def __init__(self, config: MyNewDummyConfig):
    super().__init__(config)
    del self.attribute

显式 super() 调用

如果您仍然想从 DummyModel 继承,但不希望删除 self.attribute,请明确您要调用哪个类的 super()。下面的示例演示了如何调用 nn.Modulesuper()(右侧显示展开的代码)

class MyNewDummyModel(DummyModel, nn.Module):        |     class MyNewDummyModel(nn.Module):
                                                     |
  def __init__(self, config: MyNewDummyConfig):      |       def __init__(self, config: MyNewDummyConfig):
    nn.Module.__init__(config)                       |         super().__init__()
    self.foo = config.foo                            |         self.foo = config.foo
    ...                                              |         ...

删除未使用的函数

通过使用 raise AttributeError("") 语句覆盖属性来删除属性,以模拟您在 Python 中删除父函数时想要的行为。下面的示例删除了展开代码中的方法。

class GemmaTokenizer(LlamaTokenizer):
    ...

    def get_spm_processor(self):
        raise AttributeError("Not needed for Gemma")

    def unk_token_length(self):
        raise AttributeError("Not needed for Gemma")

定义新函数

默认情况下,如果您从一个类继承并覆盖一个在父方法中具有一个或多个装饰器的方法,则装饰器也会添加到展开的代码中,前提是您自己没有添加任何装饰器。否则,将使用重新定义的装饰器。

例如,如果您有一个如下所示的父类并覆盖它,则父装饰器将被保留。

class DummyModel(nn.Module):
  ...

  @decorator(...)
  def forward(...)
    # do stuff here

模块化代码显示在左侧,而展开的代码显示在右侧。

class NewModel(DummyModel):       |   class NewModel(nn.Module):
  ...                             |     ...
                                  |
  def forward(...):               |     @decorator(...)
    ...                           |     def forward(...):
                                  |       ...

但是,如果您添加一个新的装饰器,则会使用您的新装饰器。

class NewModel(DummyModel):       |   class NewModel(nn.Module):
  ...                             |     ...
                                  |
  @my_new_decorator(...)          |     @my_new_decorator(...)
  def forward(...):               |     def forward(...):
    ...                           |       ...

super_kwargs

在前向方法非常长且您想要切换装饰器的情况下,您无需重新定义所有内容并复制/粘贴该函数。您可以使用 super().forward(...) 来展开父类主体。当函数签名中有很多参数时,请在覆盖的签名中使用特殊的 **super_kwargs 语法。

此语法指示 linter 在此处展开所有父签名参数。下面显示了 AutoModelForCausalLM 模型中的示例签名,其中包含大量参数。

class LlamaForCausalLM(nn.Module):
  ...

  @add_start_docstrings_to_model_forward(LLAMA_INPUTS_DOCSTRING)
  @replace_return_docstrings(output_type=CausalLMOutputWithPast, config_class=_CONFIG_FOR_DOC)
  def forward(
      self,
      input_ids: torch.LongTensor = None,
      attention_mask: Optional[torch.Tensor] = None,
      position_ids: Optional[torch.LongTensor] = None,
      past_key_values: Optional[Union[Cache, List[torch.FloatTensor]]] = None,
      inputs_embeds: Optional[torch.FloatTensor] = None,
      labels: Optional[torch.LongTensor] = None,
      use_cache: Optional[bool] = None,
      output_attentions: Optional[bool] = None,
      output_hidden_states: Optional[bool] = None,
      return_dict: Optional[bool] = None,
      cache_position: Optional[torch.LongTensor] = None,
      num_logits_to_keep: int = 0,
      **kwargs: Unpack[KwargsForCausalLM],
  ) -> Union[Tuple, CausalLMOutputWithPast]:
    ...

无需重写和复制/粘贴所有这些参数,请使用 super().forward(**super_kwargs) 语句(模块化代码显示在左侧,展开的代码显示在右侧)。

class NewModelForCausalLM(LlamaForCausalLM):    |    class LlamaForCausalLM(nn.Module):
  ...                                           |      ...
                                                |
  @my_new_decorator                             |     @my_new_decorator
  def forward(self, **super_kwargs):            |     def forward(
    super().forward(**super_kwargs)             |         self,
                                                |         input_ids: torch.LongTensor = None,
                                                |         attention_mask: Optional[torch.Tensor] = None,
                                                |         position_ids: Optional[torch.LongTensor] = None,
                                                |         past_key_values: Optional[Union[Cache, List[torch.FloatTensor]]] = |None,
                                                |         inputs_embeds: Optional[torch.FloatTensor] = None,
                                                |         labels: Optional[torch.LongTensor] = None,
                                                |         use_cache: Optional[bool] = None,
                                                |         output_attentions: Optional[bool] = None,
                                                |         output_hidden_states: Optional[bool] = None,
                                                |         return_dict: Optional[bool] = None,
                                                |         cache_position: Optional[torch.LongTensor] = None,
                                                |         num_logits_to_keep: int = 0,
                                                |         **kwargs: Unpack[KwargsForCausalLM],
                                                |     ) -> Union[Tuple, CausalLMOutputWithPast]:
                                                |       ...

这使得切换装饰器变得非常容易,并明确了您想要应用的唯一更改是装饰器。

尽管如此,不应使用 **super_kwargs 来避免在重新定义方法时不够明确。如果您覆盖一个方法,您应该像通常一样显式地编写签名。**super_kwargs 语法是切换装饰器和其他一些特殊情况的快捷方式。

文档字符串变量

如果一个对象在模块化文件和它继承的建模文件中都有定义,则模块化定义优先,除非赋值包含 DOCSTRING 模式。这些变量通常在建模文件中的 MODEL_START_DOCSTRINGMODEL_INPUT_DOCSTRING 中使用。它们是大量的文档字符串块,linter 会在所有地方重写名称。因此,包含 DOCSTRING 变量的赋值可以使用源文件中找到的定义,而无需复制整个文档字符串,只需在模块化文件中将变量设置为 None 即可。

如果您需要在某处引用变量,但又不想用总是相同的文档字符串使模块化文件变得混乱,这将非常有用。下面的示例代码允许您在 Starcoder2 中自动使用与 Mistral 相同的文档字符串。

STARCODER2_INPUTS_DOCSTRING = None  # will be automatically redefined

class Starcoder2Model(MistralModel):
    ...

    @add_start_docstrings_to_model_forward(STARCODER2_INPUTS_DOCSTRING)
    def forward(...)
        ...

将变量设置为除 None 之外的任何值都将覆盖文档字符串,以便您可以在需要时自定义文档字符串。

特殊命名

当从类继承时,linter 会自动重命名所有内容。为了保持一致性,从同一文件中的不同类继承时,应始终使用相同的类名前缀。

不建议使用下面的示例。它违反了库中的标准,例如应该使用 LlamaMLP 而不是 MyModelIncredibleMLP,并且因为 linter 不知道如何重命名潜在的更高阶依赖项(MyModelIncredible 或仅 MyModel)。

class MyModelIncredibleMLP(LlamaMLP):
    ...

class MyModelDecoderLayer(LlamaDecoderLayer):
    ...

但是,如果没有 隐式依赖项,则可以在本地重命名单个类。但请确保您仍然使用新的命名模式显式地重新定义对该类的其他所有引用。例如,LlamaMLP 的所有引用都应重命名为 MyModelIncredibleMLP,否则 linter 可能会添加一个新的且不需要的 MyModelMLP 类。

如果检测到不明确的情况,linter 会发出警告。它解释了正在发生的事情以及默认使用哪个前缀来获取依赖项。这些警告和重命名模式的复杂性通常仅在定义多模态模型时出现。例如,在多模态模型中的类名中添加 Text 以明确它指的是哪个模态。

We detected multiple prefix names when inheriting from transformers.models.llama.modeling_llama: ('Emu3Text', 'Emu3'). We will only use the most used 'Emu3' prefix when grabbing args and dependencies. Make sure to subclass the intermediate classes with the prefix you want (if different from 'Emu3') or use a single prefix in all the modular (best).

如果存在带有前缀的自动依赖项,但您想要另一个前缀,请使用 pass 类在本地显式重命名类,如下所示。

class Emu3TextMLP(LlamaMLP):
    pass

配置文档字符串

当继承 Config 类或添加和删除属性时,您可能只想在文档字符串中重新定义新属性。但是,linter 尚不支持此功能。您需要直接在类定义的模块化文件中直接添加整个文档字符串。

< > 在 GitHub 上更新