Transformers documentation

モデル構造のルール

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

モデル構造のルール

Transformers は、すべての modeling_*.py、modular_*.py、および configuration_*.py ファイルに対して、一連の静的ルールを強制します。mlinter パッケージがチェッカーエンジンを提供し、リポジトリは有効なルールセットを utils/rules.toml に保持しています。このローカルの TOML ファイルにより、新しい transformers-mlinter のリリースを待たずに、ルールを素早く有効化、無効化、または調整できます。

完全なチェッカーの参照と使用の詳細については、mlinterのドキュメントを参照してください。

これらは、モデリングコードの追加または変更時に想定されるモデルの規約です。これによりコードベースの一貫性が保たれ、パイプライン並列性、デバイスマップ、重みの共有などの機能との互換性が確保されます。

チェッカーの実行

make typing はリポジトリのラッパーを通じて mlinter と ty タイプチェッカーを同時に実行するため、utils/rules.toml を読み込みます。以下のコマンドで同じラッパーを直接実行できます。

python utils/check_modeling_structure.py                 # check all modeling files
python utils/check_modeling_structure.py --changed-only  # check only files changed vs origin/main
python utils/check_modeling_structure.py --list-rules    # list all rules and their enabled status
python utils/check_modeling_structure.py --rule TRF001   # show built-in docs for a specific rule

--changed-only フラグは開発中の最速のオプションです。main ブランチに対する変更ファイルのみをチェックします。ラッパーではなく mlinter を直接呼び出す場合は、ローカルの上書きが適用されるよう --rules-toml utils/rules.toml を渡してください。

違反の修正

ルール違反が検出された場合、エラーは次のようになります。

src/transformers/models/acme/modeling_acme.py:18: TRF013: AcmeModel.__init__ does not call self.post_init().

ルールリファレンスでルール ID を検索して、修正方法を確認してください。TRF013 は、PreTrainedModel のサブクラスが self.post_init() を呼び出さない場合にトリガーされます。このメソッドは必須の最終処理を実行するため、呼び出しを省略すると実行時バグが発生します。

 class AcmeModel(AcmePreTrainedModel):
     def __init__(self, config):
         super().__init__(config)
         self.layers = nn.ModuleList(
             [AcmeDecoderLayer(config) for _ in range(config.num_hidden_layers)]
         )
+        self.post_init()

ルールリファレンス

以下の各ルールには、そのルールが強制する内容と、修正を示す diff が記載されています。python utils/check_modeling_structure.py --rule TRF001 を実行すると、リポジトリの現在のルールセットにおける任意のルールの組み込みドキュメントを確認できます。

TRF002

base_model_prefix が空でない空白を含まない文字列リテラルであることを確認します。無効なプレフィックスは、重みの読み込み時のキーのマッピングやベースモデルへのアクセスを破損させる可能性があります。

class AcmePreTrainedModel(PreTrainedModel):
-    base_model_prefix = ""
+    base_model_prefix = "model"

TRF003

forward 内の旧来の if not return_dict: return (x,) パターンを検出します。return_dict による手動の分岐は冗長で、誤りやすいです。@capture_output または @can_return_tuple を使用してください。

-def forward(self, x, return_dict=None):
-    if not return_dict:
-        return (x,)
-    return AcmeModelOutput(last_hidden_state=x)
+@can_return_tuple
+def forward(self, x):
+    return AcmeModelOutput(last_hidden_state=x)

TRF004

モデルクラスが tie_weights メソッドを定義していないことを確認します。tie_weights をオーバーライドすると、読み込み、device_map の計算、および保存が壊れます。結合された重みは _tied_weights_keys クラス属性で宣言してください。

-def tie_weights(self):
-    self.lm_head.weight = self.emb.weight
+class AcmeForCausalLM(AcmePreTrainedModel):
+    _tied_weights_keys = ["lm_head.weight"]

TRF005

存在する場合、_no_split_modules の形状を確認します。不正な値は、デバイスマップのパーティショニングやシャーディングを破損させる可能性があります。

-_no_split_modules = [SomeLayerClass, ""]
+_no_split_modules = ["AcmeDecoderLayer", "AcmeAttention"]

TRF006

forward シグネチャ内のキャッシュ引数が本体で実際に使用されていることを確認します。未使用のキャッシュ引数は、キャッシュ対応が不完全であり、API の動作が不整合であることを示唆します。

def forward(self, x, past_key_values=None, use_cache=False):
+    if use_cache:
+        ...
     return x

TRF007

init 内で self.post_init() の後の self 属性への代入をチェックします。post_init の後にモデルの構造を変更すると、その初期化および最終処理の処理がバイパスされます。

def __init__(self, config):
     ...
-    self.post_init()
-    self.proj = nn.Linear(...)
+    self.proj = nn.Linear(...)
+    self.post_init()

TRF008

モデルクラスに add_start_docstrings が適用されたとき、引数が空でないことを確認します。引数が空の場合、生成される API ドキュメントが不明瞭で低品質になります。

-@add_start_docstrings("")
+@add_start_docstrings("The Acme model.")
 class AcmeModel(AcmePreTrainedModel):
     ...

TRF009

モデルの配布実装ファイルから、別のモデルのパッケージへのインポートをフラグ付けします。対象となるファイルは、modeling*, configuration, processing_, imageprocessing, videoprocessing, featureextraction, tokenization_ および generation*.py です。カウントされる形式は3つあります。パッケージパス(from transformers.models.other.modeling_other import X)、相対パス(from ..other.configuration_other import X)、パブリックAPI(from transformers import OtherModel)です。最後の形式では、クラス名から所有ディレクトリを推測し、そのディレクトリが定義するクラスと照合して確認するため、解決できない名前はそのままにされます。スコープ外: `modular.py(building on another model is its purpose, and the converter flattens those imports away),convert_.py,init.pyand files underauto. Allowed targets: the model's own directory,autoandtimm_wrapper`。1つのモデル、1つの定義: モデルAの動作は、そのモデル自身のファイル内に存在し、モデルBの変更がモデルAを黙って変更してはなりません。これはmodelingだけでなく、すべてのファイル種別について言えます。サブ設定にはAutoConfigとCONFIG_MAPPINGを介してアクセスし、別のモデルのコードをベースに構築するにはmodularファイルを使用してください。

-from transformers.models.llama.modeling_llama import LlamaAttention
-from transformers import CLIPTextModelWithProjection
+# Keep implementation local to this model's own files.
+# To build on another model, write modular_acme.py; to reuse a snippet,
+# copy it with a # Copied from comment.

TRF010

configuration*.py および modular*.py 内の PreTrainedConfig/PretrainedConfig の直接サブクラスに @strict(accept_kwargs=True) が付与されていることを確認します。このデコレータがない場合、新しい config はリポジトリのランタイム型検証契約を満たさなくなり、dataclass ベースの config 標準から乖離してしまいます。

+@strict(accept_kwargs=True)
 class AcmeConfig(PreTrainedConfig):
     ...

TRF011

PreTrainedModel のサブクラスにおける forward() 内で、self.layers に対するループ変数や、self.<submodule>.<attr>(ここで <attr> が標準的な nn.Module の属性でない場合)へのアクセスは、torch.nn.Identity が持つはずのないフラグやサブモジュールの属性にアクセスすることになります。パイプライン並列化では、任意のサブモジュールが torch.nn.Identity に置き換えられる可能性があるため、そこからカスタム属性(例: decoder_layer.attention_type)を読み取ると、実行時に AttributeError が発生します。レイヤーごとのメタデータは self.config から読み取ってください。

def forward(self, ...):
-    for decoder_layer in self.layers:
+    for i, decoder_layer in enumerate(self.layers):
         hidden_states = decoder_layer(
             hidden_states,
-            attention_mask=causal_mask_mapping[decoder_layer.attention_type],
+            attention_mask=causal_mask_mapping[self.config.layer_types[i]],
         )

TRF012

Flags in-place ops (.normal(), .zero(), …) on module weights inside _init_weights. Parameters carry internal flags tracking whether they still need re-initialization; in-place ops bypass them. Use the init primitives.

+from transformers import initialization as init
+
 def _init_weights(self, module):
-    module.weight.normal_(mean=0.0, std=0.02)
+    init.normal_(module.weight, mean=0.0, std=0.02)

TRF013

init を定義するすべての PreTrainedModel のサブクラスが self.post_init() を呼び出していることを確認します。モジュラーファイルでは、super().init() もカウントされます。これは、親クラスの post_init が伝播されるためです。post_init は、重みの初期化や勾配チェックポイントのセットアップなど、重要な最終処理を行います。これをスキップすると、微妙なランタイムのバグが発生します。

class AcmeModel(AcmePreTrainedModel):
     def __init__(self, config):
         super().__init__(config)
         self.layers = nn.ModuleList(...)
+        self.post_init()

TRF014

ネイティブモデル統合ファイル内で使用または渡される(例: キーワード引数として)trust_remote_codeフラグ。trust_remote_codeはバイナリを含む任意のコードを読み込むため、ユーザー向けの強力な機能ではあるものの、リモートコードはtransformers内でレビューやメンテナンスができないため、ネイティブ統合が依存すべきものではありません。

class AcmeModel(AcmePreTrainedModel):
     def __init__(self, config):
         super().__init__(config)
-        self.model = AutoModel.from_pretrained(..., trust_remote_code=True)
+        self.model = AutoModel.from_pretrained(...)

TRF015

PreTrainedModel のサブクラスが空でない _tied_weights_keys を設定すると、対応する設定ファイル内の tie_word_embeddings フィールドがチェックされます。このフィールドがない場合、ユーザーは重みのタイイングを制御できません。モデルは条件なしに重みをタイイングするため、シリアライズのラウンドトリップや、タイイングされていないヘッドでのファインチューニングが壊れてしまいます。

# configuration_foo.py
 @strict(accept_kwargs=True)
 class FooConfig(PreTrainedConfig):
     hidden_size: int = 768
+    tie_word_embeddings: bool = True

TRF016

画像のprocessing.py または動画のprocessing.py クラスが、ブール型の do_* 属性 (do_resize, do_rescale, do_normalize, do_convert_rgb, …) を宣言し、かつ preprocess() または _preprocess() をオーバーライドしている場合、これらのフラグがオーバーライド内で依然として消費されていることを確認してください。具体的には、直接参照されているか、super().preprocess/_preprocess(…, **kwargs) 経由で委譲されているか、あるいは画像プロセッサに限り _preprocess_image_like_inputs/_prepare_image_like_inputs 経由で転送されているかのいずれかです。do_sample_frames は例外であり、ベースの preprocess() が _preprocess() が実行される前にこれを消費するためです。オーバーライド内で一度も参照されない do_X はデッドコードです。do_X=False を設定しても効果がなく、操作は実行され続け、呼び出しごとのオーバーライドがサイレントに破綻します。

class AcmeVideoProcessor(BaseVideoProcessor):
     do_resize = True
     do_normalize = True

     def _preprocess(
         self,
         videos,
+        do_resize: bool,
+        do_normalize: bool,
         size,
         image_mean,
         image_std,
         **kwargs,
     ):
         for video in videos:
-            video = self.resize(video, size=size)
-            video = self.normalize(video, image_mean, image_std)
+            if do_resize:
+                video = self.resize(video, size=size)
+            if do_normalize:
+                video = self.normalize(video, image_mean, image_std)

TRF017

@auto_docstringと@dataclassの両方を備えたクラスでは、@auto_docstringが先に適用されることを確認します。デコレータは下から上へ適用されるため、上位に配置された@dataclassは、まだ合成されたinitが存在しないクラスに対して@auto_docstringを先に実行します。その結果、サブクラスではなく、親クラスのinitのdocが変更されます。

-@dataclass
 @auto_docstring(
     custom_intro="""
     Output type of `AcmeForPreTraining`.
     """
 )
+@dataclass
 class AcmeForPreTrainingOutput(ModelOutput):
     ...

TRF018

_init_weights(self, module, ...) をオーバーライドしているすべての PreTrainedModel サブクラスが、super()._init_weights(...) 経由でチェーンアップしていることを確認します。モジュラーファイルでは、PreTrainedModel._init_weights(self, module)、PreTrainedModel._init_weights(module)、および raise AttributeError(...) も受け付けます。意図的な完全なオーバーライドを行う場合は、メソッドの上に # trf-ignore: TRF018 を記述して抑制します。ベースの _init_weights は、標準的なモジュールタイプ(Linear、Embedding、LayerNorm、RotaryEmbedding など)をカバーします。これをスキップすると、オーバーライドが漏らしたすべてのサブモジュールが初期化されず、テストはパスしたまま、後になって微妙な重み初期化のバグとして表面化します(https://github.com/huggingface/transformers/pull/45597 参照)。

from ... import initialization as init

 def _init_weights(self, module):
+    super()._init_weights(module)
     if isinstance(module, AcmeCustomLayer):
-        module.gate.data.zero_()
+        init.zeros_(module.gate)

TRF019

processing_*.py 内の *ProcessorKwargs TypedDict で、空でない _defaults をフラグ付けします。カットオフ日以前にリリースされたモデルは対象外となります。ハードコードされた _defaults は、プロセッサの設定を Python ソースコード内に散在させ、設定からのオーバーライドが煩雑になるだけでなく、コードの肥大化を招きます。一方、Hub 上の processor_config.json に配置すれば、チェックポイントとともに配布され、コード変更なしで更新できます。

class Gemma4ProcessorKwargs(ProcessingKwargs, total=False):
-    _defaults = {
-        "text_kwargs": {"padding": False},
-        "images_kwargs": {"return_tensors": "pt"},
-    }
     images_kwargs: Gemma4ImageProcessorKwargs

TRF020

kv_lora_rank(Multi-head Latent Attention)が設定されているモデルディレクトリでは、KV LoRA 拡張射影(kv_b_proj、または nn.Linear(config.kv_lora_rank, ...))を所有するアテンションクラスをチェックします。拡張処理は、forward() から呼び出される専用のメソッド(例:expand_kv)内に実装する必要があり、インラインでの記述は不可です。モジュラーファイルでは、インポートされたベースクラスから継承されたメソッドも対象となります。外部バックエンド(vLLM/SGLang)は、圧縮された KV キャッシュを直接利用するために拡張処理をオーバーライドします。forward() にインラインで記述されている場合、オーバーライドする対象が存在しないため、バックエンドは完全なキャッシュをマテリアライズする必要があり、MLA が実現するメモリ削減の恩恵を失います。

+    def expand_kv(self, k_nope, k_pe):
+        key_shape = (*k_nope.shape[:-1], -1, self.qk_nope_head_dim + self.v_head_dim)
+        k_nope = self.kv_b_proj(k_nope).view(key_shape).transpose(1, 2)
+        k_nope, value_states = torch.split(k_nope, [self.qk_nope_head_dim, self.v_head_dim], dim=-1)
+        k_pe = k_pe.expand(*k_nope.shape[:-1], -1)
+        key_states = torch.cat((k_nope, k_pe), dim=-1)
+        return key_states, value_states
+
     def forward(self, hidden_states, ...):
         ...
-        k_nope = self.kv_b_proj(k_pass).view(key_shape).transpose(1, 2)
-        k_nope, value_states = torch.split(k_nope, [self.qk_nope_head_dim, self.v_head_dim], dim=-1)
-        k_pe = k_rot.expand(*k_nope.shape[:-1], -1)
-        key_states = torch.cat((k_nope, k_pe), dim=-1)
+        key_states, value_states = self.expand_kv(k_pass, k_rot)

TRF021

モデリングの*.pyおよびmodular.pyにおいて、torch.tensor(<value>, ..., device=<non-cpu>)の呼び出しで、<value>がPythonのスカラーに解決されることが証明できる場合(数値リテラルおよびそれらの演算、torch.finfo/iinfoのフィールド、スカラーを返す組み込み関数やmath.の呼び出し、ちょうど1回だけバインドされるローカル変数、クラス本体で代入されるself.<attr>、およびcompanion configuration fileでint/float/boolとアノテーションされたconfigフィールド(attribute_mapに従う))をフラグ付けします。シーケンスである可能性のあるもの(eos_token_id: int | list[int] | None)や、解決できないものはそのままにします。init、_init_weights、post_initおよびpost_initは対象外です。これらはキャプチャ領域内で実行されることはありません。torch.tensor(<python scalar>, device=<accelerator>)はホスト上で値をマテリアライズしてからデバイスにコピーしますが、CUDAグラフのキャプチャではそのコピーが禁止されるため、モデルをキャプチャできません。torch.full((), <value>, dtype=…, device=…)は、キャプチャ可能なカーネルで同じ0次元テンソルをデバイス上で埋め、同期を伴いません。

def get_placeholder_mask(self, input_ids, inputs_embeds):
     special_image_mask = (
         inputs_embeds
         == self.get_input_embeddings()(
-            torch.tensor(self.config.image_token_id, dtype=torch.long, device=inputs_embeds.device)
+            torch.full((), self.config.image_token_id, dtype=torch.long, device=inputs_embeds.device)
         )
     ).all(-1)

TRF022

_no_split_modules リスト内のすべての文字列が、modeling*.py または modular*.py 内で定義されているクラス、そのファイルにインポートされているクラス、または同じモデルディレクトリのシスターモジュールで定義されているクラスを指していることを確認します。値の形状のみをチェックする TRF005 を補完するものです。device_map は実行時にこれらの文字列を module.__class__.__name__ と照合するため、古い名前のままの文字列やスペルミスのある文字列はどのモジュールにも一致せず、無言で無視されます。その結果、本来一緒に保つべきモジュールがデバイス間で分割されてしまう可能性があります。他のモデルのクラスを指すエントリは修正するのではなく削除してください。post_init はすでに子サブモデルから _no_split_modules を収集しています。

class VideoLlavaPreTrainedModel(PreTrainedModel):
-    _no_split_modules = ["VideoLlavaVisionAttention"]

TRF023

In configuration*.py and modular.py, flags `Configfields named after an upstream paper's abbreviation instead of the canonical name: d_model/n_embd -> hidden_size, d_ff/d_inner/ffn_dim/ffn_hidden_size/expansion_ratio -> intermediate_size, d_head -> head_dim, n_head/n_heads -> num_attention_heads, n_layer/n_layers/num_blocks -> num_hidden_layers. Fields are read from the class body and from __init__/__post_init__ assignments and defaults. Ambiguous but idiomatic names (num_heads, num_layers, embed_dim, mlp_ratio) are not flagged, and models added before cutoff_date keep theirs. Everything that reads a model's shape -- device_map planning, tensor/pipeline parallel plans, quantization, PEFT, attention-backend selection,attribute_mapconsumers -- looks up the canonical names, so a config spelling the same quantityd_model` silently opts out of all of them. Map the checkpoint’s own spelling in the conversion script.

@strict(accept_kwargs=True)
 class AcmeConfig(PreTrainedConfig):
-    d_model: int = 1024
-    d_ff: int = 4096
-    n_heads: int = 16
-    n_layers: int = 24
+    hidden_size: int = 1024
+    intermediate_size: int = 4096
+    num_attention_heads: int = 16
+    num_hidden_layers: int = 24

TRF024

modeling*.py および modular.py において、torch.nn のコンストラクタ(Linear、Embedding、LayerNorm、RMSNorm、GroupNorm、BatchNorm、InstanceNorm、Convd、ConvTranspose*d、Bilinear、MultiheadAttention)の次元引数に、8 より大きい整数リテラルが位置引数またはキーワード引数(in_features、out_features、in_channels、out_channels、num_embeddings、embedding_dim、embed_dim、normalized_shape、num_channels、hidden_size)として指定されている場合にフラグを立てます。オペレータの形状を指定する引数(kernel_size、stride、padding、num_groups)は無視されます。8 以下のリテラルは、スカラーヘッド、二値分類器、RGB チャネル数をクリーンに保ちます。cutoff_date 以前に追加されたモデルは対象外です。幅がハードコードされていると、モジュールが特定のチェックポイントサイズに固定されてしまいます。同じアーキテクチャを別のスケールでロードすると形状の不一致が発生し、from_pretrained はどの値が誤っているのかを特定できません。これは config のフィールドがその値を指していないためです。また、真のソースが分裂するため、config を編集しても構築されるモデルは変更されなくなります。

class AcmeAtomEmbedding(nn.Module):
     def __init__(self, config):
         super().__init__()
-        self.proj = nn.Linear(768, 3072, bias=False)
-        self.norm = nn.LayerNorm(3072)
+        self.proj = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
+        self.norm = nn.LayerNorm(config.intermediate_size)

TRF025

modeling*.py と modular.py において、PreTrainedModel を継承しないクラス(layers、attention モジュール、エンコーダーなどの通常の nn.Module ブロック)内で、マスクファクトリ(maskingutils のエントリポイントである create_causal_mask、create_bidirectional_mask、create_sliding_window_causal_mask、create_chunked_causal_mask、create_masks_for_generate、および create_mask ヘルパー)への呼び出しを検出します。マスクの構築はシーケンス長の二乗に比例する計算量であり、レイヤーごとに異なるものではないため、レイヤー内で構築するとレイヤーごとにそのコストが発生し、各レイヤーが独自のマスクを保持することになります。その結果、attention バックエンドに単一の準備済みマスクを渡すことができなくなります。モデル内で一度だけ構築し、下位に渡してください。

class AcmeLayer(nn.Module):
     def forward(self, hidden_states, attention_mask=None, **kwargs):
-        attention_mask = create_causal_mask(
-            config=self.config, input_embeds=hidden_states, attention_mask=attention_mask, ...
-        )
         return self.self_attn(hidden_states, attention_mask, **kwargs)

 class AcmeModel(AcmePreTrainedModel):
     def forward(self, input_ids=None, attention_mask=None, **kwargs):
+        causal_mask = create_causal_mask(
+            config=self.config, input_embeds=inputs_embeds, attention_mask=attention_mask, ...
+        )
         for layer in self.layers:
-            hidden_states = layer(hidden_states, attention_mask, **kwargs)
+            hidden_states = layer(hidden_states, causal_mask, **kwargs)

TRF026

modeling*.py と modular*.py において、init と forward のみを定義し、init 内で self.<attr> をちょうど 1 つだけ代入し、forward の本体がそれに対して return self.<attr>(...) である(先頭の docstring は無視される)非 PreTrainedModel クラスをフラグ付けします。forward 内で他のメソッド、追加の属性、return 前の文、または super() 呼び出しがある場合、そのクラスは独自の処理を行っているものとみなされます。ラッパーは、重み名、_no_split_modules、並列化プラン、およびすべての変換マッピングに 1 レベル追加しますが、何も計算しません。そのため、読者はそれを知るためにさらに 1 つクラスを開く必要があります。PreTrainedModel のサブクラスは例外です。forward が委譲のみであっても、from_pretrained や auto クラスのために存在するためです。

-class AcmeAtomTransformer(nn.Module):
-    def __init__(self, config):
-        super().__init__()
-        self.encoder = AcmeEncoder(config)
-
-    def forward(self, hidden_states, **kwargs):
-        return self.encoder(hidden_states, **kwargs)
-
 class AcmeModel(AcmePreTrainedModel):
     def __init__(self, config):
         super().__init__(config)
-        self.atom_transformer = AcmeAtomTransformer(config)
+        self.encoder = AcmeEncoder(config)

TRF027

modeling*.py、modular.py、configuration_.py 内の assert 文を検出します。python -O は assert を除去するため、assert として記述された shape や config のチェックは、最適化された実行時に静かに消えてしまいます。また、assert は素の AssertionError を返すだけですが、ValueError なら問題のある値を特定し、対処法を伝えることができます。

def forward(self, hidden_states):
-    assert hidden_states.dim() == 3
+    if hidden_states.dim() != 3:
+        raise ValueError(f"Expected a 3D tensor, got shape {tuple(hidden_states.shape)}.")

TRF028

modeling*.py、modular.py、configuration_.py、processing*.py、image_processing.py、videoprocessing.py の先頭 25 行を、Licensed under the <name> License の行に続き、You may obtain a copy of the License at から limitations under the License. までの標準的な免責条項のすべての節が含まれているかを確認します。行は事前にフラット化され小文字化されるため、改行やコメントのスタイルは関係ありません。ライセンス名と著作権表示の行はチェック対象外です。これらはモデルごとに異なるためです。ヘッダーなしで配布されたファイルは出所が曖昧になり、後から追加するとすでにリリース済みのファイルを修正することになります。Apache License の一致のみをチェックすると、実際に発生する欠陥を見逃してしまいます。具体的には、段落が途中で切れている、URL の後にヘッダーが止まっている、不適切な検索置換で壊れている、といったケースです。

+# Copyright 2026 The HuggingFace Team. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# ...
 """PyTorch Acme model."""

TRF029

modeling*.py と modular*.py では、__init__ が config とともに、名前から明確に config のフィールドであると判別できる引数(hidden_size、num_attention_heads、intermediate_size、head_dim、num_hidden_layers、embed_dim、dropout、eps、patch_size、rope_theta など)を受け取っている場合にフラグを立てます。デフォルト値が None の任意引数は対象外です。これはオーバーライドであり、第二の真実の源ではないためです。また、これにより一つの MLP クラスが MoE モデルの dense 幅と expert 幅の両方を扱えます。一方、hidden_size: int = 1024 のようなハードコードされたデフォルト値は対象外ではありません。呼び出し側が何も渡さない場合、config よりもこのデフォルト値が優先されるためです。kosmos2 は許可リストに登録されています。そのドキュメントページはディレクトリ名から導出できないため、cutoff による既存の適用除外(grandfathering)はできません。同じ数値に真実の源が二つ存在し、呼び出し側がどちらを優先するかを選ぶことになるため、config を編集しても構築されるモデルは変更されなくなります。また、アーキテクチャに関する知識が本来属さないすべての呼び出し箇所に押し出されることにもなります。

class AcmeAttention(nn.Module):
-    def __init__(self, config, embed_dim, num_heads, dropout):
+    def __init__(self, config, layer_idx=None):
         super().__init__()
-        self.embed_dim = embed_dim
-        self.num_heads = num_heads
+        self.embed_dim = config.hidden_size
+        self.num_heads = config.num_attention_heads

 class AcmeMLP(nn.Module):
     # an optional override is fine: omitting it reads the config
     def __init__(self, config, intermediate_size=None):
         super().__init__()
         self.intermediate_size = intermediate_size or config.intermediate_size

TRF030

modeling*.py と modular*.py では、config または self.config を起点とする 3 段階以上の属性チェーンを検出します。config.hidden_size(1 ホップ)や config.text_config.hidden_size(2 ホップ、通常のサブ設定へのアクセス)は問題ありません。違反は 1 行につき 1 件として報告されます。config.diffusion_config.atom_encoder_config.hidden_size のようなチェーンを辿るモジュールは、自身のスライスではなく設定階層全体に結合してしまうため、再利用やテスト、異なるサブ設定への差し替えができません。関連するサブ設定を渡すことで、チェーンは 1 ホップに短縮されます。

class AcmeAtomEncoder(nn.Module):
     def __init__(self, config):
         super().__init__()
-        self.norm = AcmeLayerNorm(config.diffusion_config.atom_encoder_config.hidden_size)
+        self.norm = AcmeLayerNorm(config.hidden_size)

TRF031

modeling*.py と modular*.py では、ベースクラスに Output で終わるものが含まれていないトップレベルの @dataclass がフラグされます。ただし、必須フィールドが 2 つ以上ある場合は例外です。これらは内部的な引数バンドルであり、ModelOutput は実行時にこれを拒否します。通常の出力データクラスはタプルのようにインデックス指定できず、return_dict=False を経っても保持されず、@auto_docstring からは見えないため、そのフィールドは生成される API ドキュメントに反映されません。ModelOutput を使用すれば、これら 3 つの利点をすべて自動的に得られます。

@auto_docstring
 @dataclass
-class AcmeStructureOutput:
+class AcmeStructureOutput(ModelOutput):
     positions: torch.Tensor
     confidence: Optional[torch.Tensor] = None

TRF032

modeling*.py と modular*.py において、絶対値が 1e3 以上の負の数値リテラルを引数として fill, masked_fill, full, full_like, new_full が呼び出されている箇所。ハードコードされた -1e9 は float16 では -inf にオーバーフローし、float32 の最小値とは程遠いため、同じマスクでも dtype によって挙動が異なり、softmax 後に NaN が生じる可能性があります。torch.finfo(dtype).min は、実際に実行されている dtype で表現可能な最小値です。

-attention_scores = attention_scores.masked_fill(~mask, -1e9)
+attention_scores = attention_scores.masked_fill(~mask, torch.finfo(attention_scores.dtype).min)

TRF033

modeling*.py と modular*.py では、set_ で始まるメソッドをフラグとして扱います。ただし、PreTrainedModel の契約メソッドである set_input_embeddings、set_output_embeddings、set_decoder、set_encoder、set_attn_implementation、set_default_language は除外されます。セッターは動作を呼び出し順序に依存させるため、その値は config に存在せず、保存されず、from_pretrained によって復元されず、device-map や並列化の計画にも表示されません。ユーザーはこれを呼び出す必要があることを認識しなければならず、呼び忘れた場合も静かに無視されます。

class AcmeTriangleAttention(nn.Module):
-    def set_chunk_size(self, chunk_size):
-        self.chunk_size = chunk_size
+    def __init__(self, config):
+        super().__init__()
+        self.chunk_size = config.chunk_size

TRF034

In modeling*.py and modular.py, flags a locally-defined `Layer/Blockclass instantiated in annn.ModuleList(…)that does not reachGradientCheckpointingLayerthrough its base chain; modular files follow relative imports into sibling models, and unresolved chains are inconclusive. Out of scope: a model that never setssupports_gradient_checkpointing = True, which raises fromgradient_checkpointing_enable()instead of skipping a layer; a layer holdingnn.BatchNorm/nn.InstanceNorm*, whose statistics would be recomputed twice; and a stack that is not the model's token mixer, shown by an attention, modulation, mixer or SSM module assigned asself.x = Y(…).gradient_checkpointing_enable()` wraps a layer only if it is a GradientCheckpointingLayer. A plain nn.Module on the trunk is skipped silently, so training looks checkpointed while still allocating full activations, and the OOM surfaces far from the cause. Elsewhere — a conv backbone, a decode head — the trade is the author’s call, so the rule stays out.

-class AcmeDecoderLayer(nn.Module):
+class AcmeDecoderLayer(GradientCheckpointingLayer):
     def __init__(self, config, layer_idx):
         super().__init__()

TRF035

# noqa コメント(コード付き・なし)を、modeling*.py、modular.py、configuration_.py で検出します。modular ファイルでは F401、F821、F822 は許容されます。modular ファイルは生成ソースであり、意図的に使用するすべての名前を定義しないため、ruff の未定義名系ルールが正しいコードに対して発火します。具体的には、コンバーターが埋め込む __all__ のエントリ、親モデルに存在するクラス、再エクスポートのために保持されるインポートなどが該当します。これらのコードのみを指定した # noqa はスキップされます。それ以外のコードを指定した場合は、残りのコードについて報告されます。単体の # noqa は常に報告されます。modular ファイルでは、メッセージで書き換えではなくコードの指定を求めます。モデルファイルはリポジトリの lint ルールに従う通常のコードであり、抑制コメントがあるということは根本的な問題が残されたままであることを意味します。また、単体の # noqa はその行の将来のすべての違反も隠蔽してしまいます。コードを修正してください。

-from ...modeling_utils import PreTrainedModel  # noqa: F401
+from ...modeling_utils import PreTrainedModel

TRF036

modeling*.py と modular*.py において、nn.Sequential(...) の構築をすべてフラグ付けします。Sequential は子要素を位置で名前付けするため、重みは mlp.0.weight や mlp.2.weight のように配置されます。その結果、変換マッピング、_tied_weights_keys、およびすべての並列化プランがインデックスを参照することになり、レイヤーを挿入するとそれ以降のすべてが名前変更されてしまいます。また、forward が隠蔽されるため、ステップ間の dtype キャストや残差がどこで発生しているのか見えなくなります。

-        self.mlp = nn.Sequential(
-            nn.Linear(config.hidden_size, config.intermediate_size),
-            nn.GELU(),
-            nn.Linear(config.intermediate_size, config.hidden_size),
-        )
+        self.fc1 = nn.Linear(config.hidden_size, config.intermediate_size)
+        self.act = ACT2FN[config.hidden_act]
+        self.fc2 = nn.Linear(config.intermediate_size, config.hidden_size)

TRF037

modeling*.py と modular*.py において、einsum の呼び出しをフラグ付けし、式がリテラルである場合にその式を報告します。デフォルトでは無効です。einsum は収縮を表現する最も明快な方法であることが時々あるため、これは強制規約ではなくオプトイン方式です。einsum の式は、読者がデコードする必要がある記法で形状をエンコードしており、動的に構築された式はどの収縮が実行されるのかを隠蔽してしまいます。明示的な matmul/transpose 操作に展開してください。

-        pair_bias = torch.einsum("bqhc,bkhc->bhqk", query_states, key_states)
+        pair_bias = query_states.permute(0, 2, 1, 3) @ key_states.permute(0, 2, 3, 1)

TRF038

すべての modeling*.py、processing.py、imageprocessing.py、videoprocessing.py、featureextraction.py および tokenization*.py ファイルに、対応する tests/models/<model>/test.py(modelingacme.py -> tests/models/acme/test_modeling_acme.py)が存在することを確認します。除外対象: configuration.py(companion の testmodeling.py 内の ConfigTester でカバーされる)、および tokenization_utils.py(ヘルパーであり、その tokenizer を通じてカバーされる)。tokenization<name>_fast.py は、対応する slow 版のテストファイルにマッピングされます。モジュール型の*.py は一度に複数のファミリーを定義できるため、クラスは名前のサフィックスによってルーティングされます — XxxModel/XxxPreTrainedModel/XxxFor<Task> は modeling、XxxImageProcessor(Fast) は image processing、XxxProcessor は processing、XxxVideoProcessor は video processing、XxxFeatureExtractor は feature extraction、XxxTokenizer(Fast) は tokenization、XxxConfig はスキップ — 欠落するテストファイルごとに1件の違反が報告されます。 # trf-ignore: TRF038 はサポートされていません。レビューで除外が視覚的に確認できるように allowlist_models を使用してください。テストファイルのないソースファイルは回帰テストのカバーがありません: 壊れた forward pass、誤った変換マッピング、特殊トークンを落としてしまう tokenizer がマージされ、永久に壊れたまま放置される可能性があります。ランダムな重みを持つダミーの config、または手書きの小さな語彙があれば、いずれも検証できます。

src/transformers/models/acme/modeling_acme.py
+tests/models/acme/test_modeling_acme.py
 src/transformers/models/acme/tokenization_acme.py
+tests/models/acme/test_tokenization_acme.py

TRF039

if is_*_available(): import ... ブロック(is_vision_available() and is_torch_available() のような組み合わせを含む)を検出し、その名前がファイル内の他のどこにも参照されていない場合(文字列型の型ヒントや all の内部を含む)に、その import をフラグ付けします。ruff の未使用 import チェックではこれらを除去できません。import は到達可能であるため、ブロック単体で見れば問題ないように見えるからです。リファクタリングの結果、PIL.Image や torch などが不要になった場合、ガード付きの import は不要な重荷として残り、ファイルの実際の依存関係に関する誤解を招くシグナルとなります。

if is_vision_available():
-    from PIL import Image

TRF040

modeling*.py と modular*.py では、@capture_outputs と @can_return_tuple の両方で装飾されたメソッドのフラグを処理します。TRF003 は forward() 内の手動による return_dict 分岐をカバーしており、本項目はその補完です。両方のデコレーターが return_dict を取り除くため、最も外側のデコレーターだけが真の値を確認できます。@capture_outputs はすでに to_tuple 変換を処理しているため、@can_return_tuple は冗長です。

-@can_return_tuple
 @merge_with_config_defaults
 @capture_outputs
 @auto_docstring
 def forward(self, x):
     return AcmeModelOutput(last_hidden_state=x)

TRF041

In modeling*.py and modular.py, flags every if/elif and conditional expression whose condition reads a `config.orself.config.attribute without a# CODEPATH:comment, accepted on the branch line or in the contiguous comment block directly above it. Any config attribute counts, not just boolean flags. Exempt by structure:X if X is not None else fallback, where the tested field is itself one of the results --getattr(config, x, default)spelled long, which cannot fork the graph; and a guard, anifwith noelsewhose body only raises or only warns/logs, since one side aborts and nothing diverges past it. Merely mentioning None does not qualify:config.visionconfig is not Nonestill owes a note. Exempt by field: framework plumbing that gates no checkpoint divergence --problem_typeselecting a loss,hidden_actlooking up an activation,num_labels,use_cache,is_decoder, the special token ids, thesummaryhead settings; the full list isDEFAULT_EXEMPT_ATTRIBUTESinmlinter/trf041.py, extended per project byignored_attributes = […]on the rule table. A model exempts one of its own fields file-wide with a module-level# trf-ignore: TRF041 config.scale_embedding, config.auxiliary_lossat column 0 (self.config.x,config.xandxare the same field). It must name at least one field -- a bare# trf-ignore: TRF041keeps its per-line meaning -- and a condition is skipped only when every field it reads is exempt. A config-gated branch is a second architecture in the same file, and the code cannot say whether both halves are still reachable -- which is how dead experimental branches survive for releases. The rule does not forbid the branch: like Rust's// SAFETY:`, it asks for the checkpoints taking each side to be written down next to it. A branch nobody can name one for is a branch to delete.

+        # CODEPATH: ESMC-6B ships pre-normalised embeddings, the 300M/600M checkpoints do not.
         if config.use_embedding_norm:
             hidden_states = self.embedding_norm(hidden_states)

-        if config.msa_encoder_enabled:
-            hidden_states = self.msa_encoder(hidden_states)
+        # no released checkpoint sets msa_encoder_enabled -> branch removed

TRF042

tests/models//testtokenization.py において、ファイルが TokenizerTesterMixin を継承する収集対象のテストクラスを定義していることを確認します。ランナーが収集するクラスのみが対象となります。ベースが TestCase の場合、またはベースが別のモデルのテストクラスである場合の *Test という命名規則に従う場合です。そのため、ヘルパーのみを含むファイルはスキップされ、スイートをミックスインするヘルパーは、実際のテストクラスに対するルールを満たしません。継承は、同じファイル内のベースクラス、および名前によってインポートされた別のモデルのトークナイザーテストまで追跡されます。解決できないベースはカウントされません。スイートを実行しない最初のテストクラスに対して報告されます。auto はホワイトリストに登録されています。test_tokenization_auto.py はトークナイザーではなく、AutoTokenizer の解決をテストするためです。TokenizerTesterMixin は、encode/decode のラウンドトリップ、パディングと切り詰め、特殊トークンの処理、追加トークンの永続化、および save/load の同等性が実際にチェックされる場所です。手書きの少数のトークン ID リストのみをアサートするテストは、トークナイザーがそれらのすべてで壊れているにもかかわらず合格し、レビューではテスト済みのように見えます。

-class AcmeTokenizationTest(unittest.TestCase):
+class AcmeTokenizationTest(TokenizerTesterMixin, unittest.TestCase):
+    tokenizer_class = AcmeTokenizer
+    test_slow_tokenizer = True

TRF043

クラス名が Attention で終わるクラスの forward シグネチャ内で宣言された position_ids パラメータをフラグ付けします。position_ids は下流の flash-attention による padding なし学習で消費されるため、kwargs を通して伝播する必要があります。シグネチャ内で名前を指定すると、attention インターフェースが読み取る前に消費されてしまいます。llama の標準では position_embeddings とkwargs を渡します。

class AcmeAttention(nn.Module):
     def forward(
         self,
         hidden_states,
         position_embeddings,
         attention_mask=None,
-        position_ids=None,
         **kwargs: Unpack[TransformersKwargs],
     ):

TRF044

modeling.py および modular_.py 内の任意の関数において、引数名が cacheposition であるものを検出します。v5 以降、すべてのモデルから cache_position が削除されました。これを再導入すると(通常は v5 以前のソースからコピーしたものであり)、不要な引数がすべてのレイヤーに渡されることになります。キャッシュの更新は past_key_values.update(key_states, value_states, self.layer_idx) であり、position の伝播は行われません。

def forward(
     self,
     hidden_states,
     past_key_values=None,
-    cache_position=None,
     **kwargs,
 ):
-    key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx, cache_position)
+    key_states, value_states = past_key_values.update(key_states, value_states, self.layer_idx)

TRF045

forward シグネチャ内のレガシー出力パラメータである attentions、output_hidden_states、return_dict を、modeling.py および modular_.py でフラグ付けします。カットオフ日以前に貢献されたモデルは対象外です。出力の制御はデコレータスタックが担います。@captureoutputs が config に対して出力*フラグを解決し、_can_record_outputs 経由でテンソルを記録し、@can_return_tuple が return_dict を処理します。シグネチャにこれらを宣言すると、デコレータと乖離する手動のフラグ伝達を再び導入することになります。

+@capture_outputs
 def forward(
     self,
     input_ids,
-    output_attentions=None,
-    output_hidden_states=None,
-    return_dict=None,
     **kwargs: Unpack[TransformersKwargs],
 ):

TRF046

modeling*.py および modular*.py の forward メソッド内で、self の属性へのフラグ割り当てを行います。forward 中に書き込まれる状態は、バッチ処理、torch.compile、およびモジュールの推論を妨げます。保持される状態は明示的に渡されます(cache オブジェクト、generate ループ)。config または静的な形状にのみ依存する値は init に属します。

def forward(self, hidden_states):
-    self.sequence_length = hidden_states.shape[1]
-    embeddings = self.compute_embeddings(self.sequence_length)
+    embeddings = self.compute_embeddings(hidden_states.shape[1])

TRF047

preprocess、preprocess、call および post_process* メソッド内の self 属性へのフラグ代入を、image_processing.py と videoprocessing.py で行います。呼び出し間で状態を保持するプロセッサは、preprocess を複数回実行してから postprocess をバッチ処理する方式を壊します。2 回目の preprocess が、1 回目の postprocess が必要とする状態を上書きしてしまうためです。値を返すか、メソッドチェーンを通じて値を渡してください。

def _preprocess(self, images, **kwargs):
-    self.original_sizes = [image.shape[-2:] for image in images]
+    original_sizes = [image.shape[-2:] for image in images]
     ...
+    return BatchFeature(data={"pixel_values": pixel_values, "original_sizes": original_sizes})

TRF048

クラスレベルの _tied_weights_keys 宣言で、フラグの list/tuple/set リテラルを使用しています。v5 では _tied_weights_keys が dict に変更され、各被束縛対象パラメータをそのソースにマッピングする形になりました。list 形式ではどのパラメータがソースであるかが示されないため、束縛、device_map の計算、および保存が静かに誤動作します。

class AcmeForCausalLM(AcmePreTrainedModel):
-    _tied_weights_keys = ["lm_head.weight"]
+    _tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}

TRF049

modeling*.py and modular.py: nn.init. / init.* primitives and in-place initializers on own parameters (self.weight.data.normal_()) in init methods. Models instantiate on the meta device, so tensor values written in init are discarded before loading: a parameter initialized only there holds random content when fine-tuning from scratch or after a meta-device reload. Allocate with torch.empty in init, initialize in _init_weights.

class AcmeEmbeddings(nn.Module):
     def __init__(self, config):
         super().__init__()
         self.position_embedding = nn.Parameter(torch.empty(config.num_positions, config.hidden_size))
-        nn.init.trunc_normal_(self.position_embedding, std=config.initializer_range)

 class AcmePreTrainedModel(PreTrainedModel):
     def _init_weights(self, module):
         super()._init_weights(module)
+        if isinstance(module, AcmeEmbeddings):
+            init.trunc_normal_(module.position_embedding, std=self.config.initializer_range)

TRF050

クラス名が Attention で終わるクラスの init における *RotaryEmbedding クラスへの呼び出しをフラグ付けします。Model は単一の rotary_emb を所有し、inv_freq を一度だけ構築し、cos/sin を position_embeddings として下流に渡します。アテンション層ごとに 1 つの rotary モジュールを配置すると、バッファが重複し、層ごとに周波数が再計算され、アテンションが position_embeddings を受け取るという契約から逸脱します。

class AcmeAttention(nn.Module):
     def __init__(self, config, layer_idx):
         super().__init__()
-        self.rotary_emb = AcmeRotaryEmbedding(config)

 class AcmeModel(AcmePreTrainedModel):
     def __init__(self, config):
         super().__init__(config)
+        self.rotary_emb = AcmeRotaryEmbedding(config)

TRF051

モデルの attn_implementation 属性 との比較は、.py および modular_.py 内で行います。バックエンドのディスパッチは ALL_ATTENTION_FUNCTIONS.get_interface に属し、バックエンドに依存するテンソルの整形(パディング、リシェイプ)は integrations/ 配下の共有ラッパーに属します。インラインの分岐はモデル本体をカーネル依存の状態にし、新しいバックエンドが登録された際に動作が壊れます。

-if self.config._attn_implementation == "flash_attention_2":
-    attn_output = flash_path(query_states, key_states, value_states)
-else:
-    attn_output = eager_path(query_states, key_states, value_states)
+attention_interface = ALL_ATTENTION_FUNCTIONS.get_interface(self.config._attn_implementation, eager_attention_forward)
+attn_output, attn_weights = attention_interface(self, query_states, key_states, value_states, ...)

TRF052

modeling.pyおよびmodular_.py内の、ATTENTION_CLASSESで終わる名前へのモジュールレベルの代入にフラグを立てます。辞書から選択されるバックエンドごとのアテンションクラスは、インターフェース導入前の慣用表現です。これにより、ほぼ同一のクラスが互いに乖離し、ALL_ATTENTION_FUNCTIONSに登録されたハブのアテンションカーネルがそれらに到達しなくなります。インターフェース経由でディスパッチする単一のアテンションクラスが辞書を置き換えます。レガシーの親クラスからこれを伝播させないでください。

-ACME_ATTENTION_CLASSES = {
-    "eager": AcmeAttention,
-    "flash_attention_2": AcmeFlashAttention2,
-    "sdpa": AcmeSdpaAttention,
-}
+class AcmeAttention(nn.Module):
+    def forward(self, ...):
+        attention_interface = ALL_ATTENTION_FUNCTIONS.get_interface(self.config._attn_implementation, eager_attention_forward)

TRF053

modeling*.py および modular*.py において、labels[…, 1:] のようなスライス処理によって shiftlogits/shift_labels (および shifted 版) を構築するフラグの代入は検出対象となります。すでにシフト済みのラベルを受け取る (shift_labels = kwargs.pop(“shift_labels”, labels)) ことは正しい慣用表現であり、検出されません。self.loss_function はラベルを自身でシフトするため、modeling コード内で事前にシフトすると、二重にシフトされたターゲットで学習が行われるか、独自に損失関数のパスを用意するよう強制されます。Decoder-only モデルは生のラベルを渡し、損失関数側でシフトさせるのが正しいです。Encoder-decoder モデルはその逆のケースです。これらのラベルは、先頭に付加された decoder の開始トークンによってすでにシフトされているため、損失関数が再度シフトしないよう shift_labels=labels を渡します。

if labels is not None:
-    shift_logits = logits[..., :-1, :].contiguous()
-    shift_labels = labels[..., 1:].contiguous()
-    loss = nn.functional.cross_entropy(shift_logits.view(-1, self.config.vocab_size), shift_labels.view(-1))
+    # decoder-only: labels are unshifted, the loss shifts them
+    loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size)
+    # encoder-decoder: labels are already shifted, hand them over as shift_labels
+    loss = self.loss_function(logits=logits, labels=labels, shift_labels=labels, vocab_size=self.config.vocab_size)

TRF055

config_class フラグ、config = SomeConfig の代入、config アノテーションのない <Model>PreTrainedModel、および config 引数がアノテーションされていないか別の config を指定している __init__。サブ config から構築されるクラス(AcmeTextModel(config.text_config))は、そのサブ config を宣言する必要があります。modular_*.py ファイルは、そのファイルが生成するファイルを通じてチェックされます。PreTrainedModel は config アノテーションから config_class を導出します。代入や手書きの config_class は、親のものを保持するか、そこから乖離します。また、不一致のある __init__ は、1 つの config からモデルを構築しながら、別のものを宣言してしまいます。

class Gemma4VisionModel(Gemma4PreTrainedModel):
     """The Gemma 4 Vision Encoder."""
-    config = Gemma4VisionConfig
+    config: Gemma4VisionConfig

-    def __init__(self, config):
+    def __init__(self, config: Gemma4VisionConfig):

TRF056

modeling*.py と modular*.py において、forward 内の .item() および .tolist() の呼び出しにフラグを立てます。split(...) の分割サイズ引数に .tolist() を渡す場合は対象外です。torch.split は Python の int を必要とするためです。どちらの呼び出しもテンソルをホストに読み戻すため、dynamo はトレースできず、グラフが分断されます。

-        for grid, item in zip(grid_thw.tolist(), split_items):
-            _, height, width = grid
-            merged.append(self.patch_merger(item, size=(height, width)))
+        for grid, item in zip(grid_thw, split_items):
+            merged.append(self.patch_merger(item, size=(grid[1], grid[2])))

TRF057

@auto_docstring を、公開されている PreTrainedModel のサブクラス(<Model>PreTrainedModel、<Model>Model、<Model>For<Task>、backbone)、PreTrainedConfig のサブクラス、ModelOutput のサブクラス、image processor、video processor、ProcessorMixin のサブクラス、およびそれらの公開メソッド forward、get_image_features、get_video_features、get_audio_features、get_text_features、preprocess、__call__ に適用します。modular_*.py は、そこから生成されたファイルに対してチェックされます。これがない場合、クラスとそのメソッドは、パラメータ、戻り値、例のドキュメントなしでリリースされるため、各モデルについて手作業で記述する必要があります。

+@auto_docstring
 @dataclass
 class AcmeModelOutputWithPast(ModelOutput):
     logits: torch.Tensor | None = None

+@auto_docstring
 class AcmeForConditionalGeneration(AcmePreTrainedModel):
+    @auto_docstring
     def forward(self, input_ids, pixel_values=None, **kwargs):
         ...

TRF058

modeling*.py と modular*.py では、バッファ名が文字列リテラルである register_buffer("<name>", ...) の呼び出しを、どのレシーバー(self や layer.mamba のような他のモジュール)であってもフラグ付けします。変数や f-string などの計算された名前(ループ内でレイヤーごとに 1 つのバッファを作成する場合など)は、属性代入の同等表現が存在しないため、対象外となります。torch>=2.5 では、nn.Buffer は nn.Parameter と同様に、通常の属性代入によってバッファを登録します。メソッド呼び出しによって作成されたバッファは、__init__ を実行した際の副作用としてのみ存在するため、その 1 つを調整したい modular ファイルでは、__init__ 全体を再定義する必要があります。属性として代入されることで、単独で継承およびオーバーライドが可能になります。

-        self.register_buffer("inv_freq", inv_freq, persistent=False)
-        self.register_buffer(
-            "position_ids", torch.arange(config.max_position_embeddings).expand((1, -1)), persistent=False
-        )
+        self.inv_freq = nn.Buffer(inv_freq, persistent=False)
+        self.position_ids = nn.Buffer(torch.arange(config.max_position_embeddings).expand((1, -1)), persistent=False)

TRF059

テンソル並列プランでmoe_tp_expertsが割り当てられているモデルディレクトリでは、ルーティングされた*Expertsクラスが、hidden states、top-k indices、top-k routing weights をそれぞれforwardの最初の3つの位置引数として受け取ることを確認します。selected_expertsやrouting_weightsなどのエイリアスも受け付けます。MoeExpertsParallelは位置引数の3番目に勾配変換を適用します。シグネチャが異なる場合、誤ったテンソルに適用されるか、適用がスキップされる可能性があります。

class AcmeExperts(nn.Module):
-    def forward(self, hidden_states):
+    def forward(self, hidden_states, top_k_index, top_k_weights):
         ...

TRF060

from transformers... import X および import transformers... が src/transformers/models/ 配下で検出されると、相対インポート形式(from ...modeling_utils import X)が提案されます。convert_*.py スクリプトはスキップされます。パッケージ内の絶対インポートは、遅延読み込みのトップレベル transformers/__init__.py を経由するため、循環インポートを引き起こす可能性があり、また transformers の別のインストール済みコピーに解決される可能性があります。

-from transformers.modeling_utils import PreTrainedModel
-from transformers.models.acme.configuration_acme import AcmeConfig
-from transformers import initialization as init
+from ...modeling_utils import PreTrainedModel
+from .configuration_acme import AcmeConfig
+from ... import initialization as init

TRF061

In modular_*.py, flags a class whose base is defined earlier in the same file. Bases imported from another model, <Model>PreTrainedModel サブクラスおよび後方互換性エイリアスはフラグが立てられません。コンバーターは他のモデルからインポートされたベースをインライン化しますが、同じファイル内のベースは保持するため、生成された modeling ファイルでは継承関係が維持され、そのクラスを1つずつ読み取ることができなくなります。

from ..llama.modeling_llama import LlamaDecoderLayer


 class AcmeDecoderLayer(LlamaDecoderLayer):
     pass


-class AcmeSparseDecoderLayer(AcmeDecoderLayer):
+class AcmeSparseDecoderLayer(LlamaDecoderLayer):
     def __init__(self, config, layer_idx):
         super().__init__(config, layer_idx)
         self.mlp = AcmeSparseMoeBlock(config)

TRF062

_init_weights 内で呼び出される、torch.nn.init のインプレース初期化関数(nn.init.normal_(...) など、どのようにインポートされた場合でも)にフラグが付けられます。値を計算するだけのヘルパー関数(calculate_gain など)にはフラグは付けられません。Transformers の init 関数は、チェックポイントから既に読み込まれたテンソルをスキップします。torch.nn.init は from_pretrained 中に適用されるパッチに依存していますが、名前によってインポートされた関数はこのパッチを回避するため、読み込まれた重みが静かに再初期化される可能性があります。

from torch import nn
+
+from ... import initialization as init


 def _init_weights(self, module):
     super()._init_weights(module)
     if isinstance(module, AcmeLayerScale):
-        nn.init.constant_(module.lambda1, self.config.layer_scale_init_value)
+        init.constant_(module.lambda1, self.config.layer_scale_init_value)

TRF063

モデルファイルがインポート時に実行するすべての相対インポートを追跡し、インポート先のファイルがインポート元ファイルが宣言していないバックエンドを必要とする場合にフラグを立てます。宣言されていないバックエンドとは、ベースの要件、__all__ オブジェクトの中で最も弱い@requires、またはis_<backend>_available() ガードを指します。modular_*.py ファイルは、そのファイルが生成するファイルを通じてチェックされます。遅延モジュールは、宣言されたバックエンドがインストールされた時点でファイルをインポートします。そのファイルがより多くのバックエンドを必要とするシスターファイルをインポートする場合、from transformers import * はその環境でクラッシュします。例えば、ビジュアル専用のプロセッサが torchvision の画像プロセッサをインポートすると、Pillow はインストールされているが torch がインストールされていない環境でインストールが壊れます。

if is_vision_available():
-    from .image_processing_acme import AcmeImageProcessorKwargs
+    from .image_processing_pil_acme import AcmeImageProcessorKwargs
 
 @requires(backends=("vision",))
 class AcmeProcessor(ProcessorMixin):

TRF064

*.py と modular*.py の処理において、_defaults、text_kwargs、images_kwargs、videos_kwargs、または audio_kwargs を割り当てたり再アノテーションしたりする ProcessingKwargs のサブクラスを検出します。ProcessingKwargs._defaults は非推奨です。デフォルト値はプロセッサのクラス属性であり、他の属性と同様に継承・上書きされます。モダリティフィールドはデフォルトの型を維持します。利用可能な引数は、サブプロセッサが実行時に読み込まれた時点で初めて判明するためです。

class AcmeProcessorKwargs(ProcessingKwargs, total=False):
-    images_kwargs: AcmeImagesKwargs
-    _defaults = {
-        "text_kwargs": {"padding": False},
-        "images_kwargs": {"num_crops": 4},
-    }
+    num_crops: int


 class AcmeProcessor(ProcessorMixin):
     valid_processor_kwargs = AcmeProcessorKwargs
+    text_kwargs = {"padding": False}
+    num_crops: int = 4

TRF065

In processing*.py, flags any class extending ImagesKwargs, TextKwargs, AudioKwargs or VideosKwargs, directly or through another model’s subclass. In modular.py, which also holds sub-processors, a subclass is allowed when named <Model>ImageProcessorKwargs, <Model>VideoProcessorKwargs, <Model>VideoProcessorInitKwargs or <Model>AudioProcessorKwargs. Modality kwargs belong in the sub-processor files (`imageprocessing.py,videoprocessing.py`, …). In processing_.py they stay untyped, since sub-processors are loaded dynamically.

-class AcmeImagesKwargs(ImagesKwargs, total=False):
-    num_crops: int
-
-
 class AcmeProcessorKwargs(ProcessingKwargs, total=False):
-    images_kwargs: AcmeImagesKwargs
+    num_crops: int

TRF066

@requires 内で、ファイルの暗黙の要件や、メソッドの場合はその外側のクラスの明示的な要件を繰り返しているバックエンドをフラグ付けします。また、requires_backends(...) が @requires デコレータとして記述可能である場合や、@requires が @classmethod または @staticmethod の上に配置されている場合もフラグ付けします。カットオフにより、古いモデルは誤配置されたデコレータを除くすべての対象から除外されます。バックエンド要件の繰り返しは、メソッドが実際に追加する依存関係がどれであるかを不明瞭にします。関数の先頭で行われる無条件のチェックは、依存関係メタデータを公開し、関数が呼び出されたときにチェックを実行する @requires(backends=...) に属します。requires_backends は条件付き要件のために保持してください。@requires は通常の関数をラップするため、@classmethod または @staticmethod の上に置くと、代わりにディスクリプタをラップし、すべての呼び出しで TypeError が発生します。それらの下側に配置する必要があります。

# image_processing_pil_acme.py already requires vision.
-@requires(backends=("vision", "torch"))
+@requires(backends=("torch",))
 class AcmeImageProcessorPil(PilBackend):
-    @requires(backends=("torch",))
     def post_process(self, outputs):
         return outputs

+    @requires(backends=("scipy",))
     def refine(self, outputs):
-        requires_backends(self, ["scipy"])
         return outputs

TRF067

modeling*.pyおよびmodular*.pyでは、関数がその後.hidden_states[...]をインデックスで読み取るだけであるにもかかわらず、すべての隠れ状態を有効にする呼び出し(output_hidden_states=True、または**kwargsで設定)にフラグを立てます。タプル全体を使用するコード(イテレーション、スライシング、スタッキング、または返却)と@filter_output_hidden_statesのバックボーンは対象外です。呼び出しが返却するまで各レイヤーの隠れ状態は生存し続けるため、ピークメモリは深さに比例して増加します。output_hidden_statesはインデックスまたはインデックスのリストも受け入れ、それらのみをキャプチャします。**kwargsをフォワードするメソッドに@select_hidden_statesをデコレーターとして適用するか、インデックスを直接渡してください。

+from ...utils.output_capturing import select_hidden_states
 ...
+    @select_hidden_states("vision_feature_layer")
     def get_image_features(self, pixel_values, vision_feature_layer=None, **kwargs):
-        kwargs["output_hidden_states"] = True
         image_outputs = self.vision_tower(pixel_values, return_dict=True, **kwargs)
         selected_image_feature = image_outputs.hidden_states[vision_feature_layer]
 ...
-        outputs = self.img_processor(img_embeds, output_hidden_states=True)
+        outputs = self.img_processor(img_embeds, output_hidden_states=self.layer_idx)
         return outputs.hidden_states[self.layer_idx]

TRF068

_no_split_modules の各エントリを、モデリングファイルが定義またはインポートしているクラスと照合します。modular_*.py ファイルは、ディスク上に生成されるファイルを通じてチェックされるため、リンティングの前に再生成してください。accelerate は、これらの名前をサブモジュールのクラス名と照合します。クラスではない名前は決して一致しないため、そのレイヤーはデバイス間で分割できます。これは通常、_no_split_modules を継承するモジュラーファイルから生じます。コンバーターはクラスではなくプレフィックスの名前を変更するためです。

class Qwen4ExpModel(Qwen3_5MoeModel):
-    # inherits ["Qwen3_5MoeDecoderLayer"] -> converted to "Qwen4ExpDecoderLayer", which does not exist
+    _no_split_modules = ["Qwen4ExpTextDecoderLayer"]

違反の抑制

ルール違反を抑制する必要がある場合は、以下の2つのオプションのいずれかを使用してください。

インライン抑制

違反している行に# trf-ignore: RULE_IDコメントを追加してください。抑制が正当化される理由をレビュー担当者が理解できるよう、説明を含めてください。

# trf-ignore: TRF011 — mask is derived from self.config, not the layer
hidden_states = layer(hidden_states, attention_mask=mask_from_config)

コード内で修正すべき違反を無視するためにtrf-ignoreを使用しないでください。

allowlist_models

すぐに修正できないレガシーコードを持つモデルについては、mlinter rules.toml内の該当するルールのallowlist_modelsリストに、そのモデルのディレクトリ名を追加してください。

[rules.TRF004]
allowlist_models = ["existing_model", "your_model_name"]
Update on GitHub