# モデル構造のルール

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

> [!TIP]
> 完全なチェッカーの参照と使用の詳細については、[mlinterのドキュメント](https://huggingface.github.io/transformers-mlinter/)を参照してください。

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

## チェッカーの実行

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

```bash
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().
```

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

```diff
 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` を実行してください。

### TRF001

PreTrainedModelのconfig_classがConfigと命名されていることを確認します。不一致があると、読み込み、autoクラス、開発者の期待が壊れる可能性があります。

```diff
class AcmePreTrainedModel(PreTrainedModel):
-    config_class = WileConfig
+    config_class = AcmeConfig
```

### TRF002

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

```diff
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 を使用してください。

```diff
-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 クラス属性で宣言してください。

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

### TRF005

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

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

### TRF006

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

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

### TRF007

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

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

### TRF008

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

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

### TRF009

モデルの配布実装ファイル（modeling_*、configuration_*、processing_*、image_processing_*、video_processing_*、feature_extraction_*、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`、`convert_*.py`、`__init__.py`、および`auto`配下のファイル。許可されるターゲット：モデル自身のディレクトリ、`auto`、`timm_wrapper`。1つのモデル、1つの定義：モデルAの挙動はモデルA自身のファイルに存在し、モデルBの変更がモデルAを黙って変更してはなりません。これはmodelingだけでなく、すべてのファイル種別について言えます。サブ設定へのアクセスはAutoConfigとCONFIG_MAPPINGを通じて行い、別のモデルのコードを基盤として構築するにはmodularファイルを使用してください。

```diff
-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標準から乖離してしまいます。

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

### TRF011

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

```diff
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.

```diff
+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 は重要な最終処理（重みの初期化、勾配チェックポイントの設定など）を行います。これをスキップすると、微妙なランタイムのバグが発生します。

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

### TRF014

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

```diff
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 フィールドがチェックされます。このフィールドがない場合、ユーザーは重みのタイイングを制御できません。モデルは条件なしに重みをタイイングするため、シリアライズのラウンドトリップや、タイイングされていないヘッドでのファインチューニングが壊れてしまいます。

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

### TRF016

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

```diff
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

On classes carrying both @auto_docstring and @dataclass, checks @auto_docstring comes first. Decorators apply bottom-up, so @dataclass on top runs @auto_docstring first, on a class with no synthesized __init__ yet: it then modifies the parent's __init__.__doc__ instead of the subclass's.

```diff
-@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 参照）。

```diff
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` に配置すれば、チェックポイントとともに配布され、コード変更なしで更新できます。

```diff
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 が存在する理由であるメモリ削減の恩恵を失います。

```diff
+    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

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

```diff
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

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

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

### TRF023

configuration_*.pyおよびmodular_*.pyでは、`*Config`のフィールドが正規名ではなく、上流論文の略称で命名されている場合にフラグが立てられます: 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。フィールドはクラス本体および__init__/__post_init__内の代入とデフォルト値から読み取られます。曖昧ではあるが慣用的な名前 (num_heads, num_layers, embed_dim, mlp_ratio) はフラグが立てられず、cutoff_date以前に追加されたモデルは既存の名前を維持します。モデルの形状を読み取るすべての処理 -- device_mapの計画、テンソル/パイプライン並列計画、量子化、PEFT、アテンションバックエンドの選択、`attribute_map`の消費者 -- は正規名を参照するため、設定が同じ量を`d_model`と表記すると、これらすべてから黙って除外されてしまいます。変換スクリプト内で、チェックポイント自身の表記をマッピングしてください。

```diff
@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*、Conv*d、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 以前に追加されたモデルは対象外です。幅がハードコードされていると、モジュールが 1 つのチェックポイントサイズに固定されます。同じアーキテクチャを別のスケールでロードすると形状の不一致が発生し、`from_pretrained` はどの値が誤っているかを特定できません。これは config のフィールドがその値を指していないためです。また、真のソースが分裂するため、config を編集しても構築されるモデルは変更されなくなります。

```diff
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ブロック）内で、マスクファクトリへの呼び出し（masking_utilsのエントリポイントであるcreate_causal_mask、create_bidirectional_mask、create_sliding_window_causal_mask、create_chunked_causal_mask、create_masks_for_generate、およびcreate_*_maskヘルパー関数）が行われています。マスクの構築はシーケンス長の二乗に比例する計算量であり、レイヤーごとに変化しないため、レイヤー内で構築するとレイヤーごとにそのコストが発生し、各レイヤーが独自のマスクを保持することになります。これにより、attentionバックエンドに単一の準備済みマスクを渡すことができなくなります。モデル内で一度だけ構築し、下位レイヤーに渡してください。

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

```diff
-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 なら問題のある値を特定し、対処法を伝えることができます。

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

```diff
+# 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 において、`config` とともに、名前から明確に config のフィールドであると判別できる引数（hidden_size、num_attention_heads、intermediate_size、head_dim、num_hidden_layers、embed_dim、dropout、eps、patch_size、rope_theta など）を受け取る `__init__` を検出します。デフォルト値が `None` の任意引数は対象外です。これはオーバーライドであり、第二の信頼源ではないため、1 つの MLP クラスが MoE モデルの dense 幅と expert 幅の両方を処理するための方法です。一方、`hidden_size: int = 1024` のようなハードコードされたデフォルト値は対象外ではありません。呼び出し側が何も渡さない場合、config よりも優先されるためです。kosmos2 は許可リストに追加されています。そのドキュメントページはディレクトリ名から導出できないため、cutoff による既存の適用除外（grandfathering）はできません。同じ数値に信頼源が 2 つ存在し、呼び出し側が勝者を選ぶことになるため、config を編集しても構築されるモデルは変更されなくなります。また、アーキテクチャに関する知識が本来属さないすべての呼び出し箇所に押し出されることにもなります。

```diff
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 ホップに縮小されます。

```diff
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 つの利点をすべて自動的に得られます。

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

### TRF032

In modeling_*.py and modular_*.py, flags masked_fill, masked_fill_, full, full_like and new_full called with a negated numeric literal of magnitude 1e3 or more. A hardcoded -1e9 overflows to -inf in float16 and is nowhere near the smallest value in float32, so the same mask behaves differently per dtype and can produce NaNs after softmax. `torch.finfo(dtype).min` is the smallest representable value in whatever dtype is actually running.

```diff
-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 や並列化の計画にも表示されません。ユーザーはこれを呼び出す必要があることを認識しなければならず、呼び忘れた場合もエラーは発生しません。

```diff
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

modeling_*.py と modular_*.py において、ベースチェーンを介して `GradientCheckpointingLayer` に到達しない、`nn.ModuleList(...)` でインスタンス化されるローカル定義の `*Layer`/`*Block` クラスをフラグ付けします。modular ファイルはシスターモデルへの相対インポートに従い、解決できないチェーンは不確定と扱います。対象外: `supports_gradient_checkpointing = True` を設定しないモデル（`gradient_checkpointing_enable()` から例外を送出し、レイヤーをスキップしない場合）、統計量が2回再計算される `nn.BatchNorm*`/`nn.InstanceNorm*` を保持するレイヤー、および `self.x = Y(...)` として割り当てられたアテンション、モジュレーション、ミキサー、または SSM モジュールによってモデルのトークンミキサーではないことが示されるスタック。`gradient_checkpointing_enable()` は、レイヤーが GradientCheckpointingLayer の場合のみラップします。トランク上のプレーンな nn.Module は無言でスキップされるため、チェックポイント化されているように見えてもフルアクティベーションが割り当てられ続け、OOM が原因から離れた場所で表面化します。他の場所（conv バックボーン、デコードヘッドなど）では、トレードオフは著者の判断に委ねられるため、このルールは適用されません。

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

### TRF035

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

```diff
-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 キャストや残差がどこで発生しているのか見えなくなります。

```diff
-        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 操作に展開してください。

```diff
-        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、image_processing_*.py、video_processing_*.py、feature_extraction_*.py および tokenization_*.py ファイルに、対応する tests/models//test_*.py（modeling_acme.py -> tests/models/acme/test_modeling_acme.py）が存在することを確認します。除外対象: configuration_*.py（対応する test_modeling_*.py 内の ConfigTester でカバーされるため）、および tokenization_utils*.py（そのトークナイザを通じてカバーされるヘルパーのため）。tokenization__fast.py は、対応するスロー版のテストファイルにマッピングされます。modular_*.py は一度に複数のファミリーを定義できるため、そのクラスは名前のサフィックスによってルーティングされます -- XxxModel/XxxPreTrainedModel/XxxFor は 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、誤った変換マッピング、または特殊トークンを落としてしまうトークナイザがマージされ、永久に壊れたままになる可能性があります。ランダムな重みを持つダミーの config、または手書きの小さな語彙があれば、これらすべてをテストするのに十分です。

```diff
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 がデッドウェイトとして残存し、ファイルの実際の依存関係に関する誤解を招くシグナルとなります。

```diff
if is_vision_available():
-    from PIL import Image
```

### TRF040

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

```diff
-@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.*` or `self.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, an `if` with no `else` whose body only raises or only warns/logs, since one side aborts and nothing diverges past it. Merely mentioning None does not qualify: `config.vision_config is not None` still owes a note. Exempt by field: framework plumbing that gates no checkpoint divergence -- `problem_type` selecting a loss, `hidden_act` looking up an activation, `num_labels`, `use_cache`, `is_decoder`, the special token ids, the `summary_*` head settings; the full list is `DEFAULT_EXEMPT_ATTRIBUTES` in `mlinter/trf041.py`, extended per project by `ignored_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_loss` at column 0 (`self.config.x`, `config.x` and `x` are the same field). It must name at least one field -- a bare `# trf-ignore: TRF041` keeps 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.

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

```diff
-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-freeトレーニングで消費されるため、**kwargsを介して伝播する必要があります。シグネチャ内で名前を指定すると、attentionインターフェースが読み取る前に吸収されてしまいます。llamaの標準では、position_embeddingsと**kwargsを渡します。

```diff
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 内の任意の関数において、cache_position という名前のパラメータを検出します。cache_position は v5 で全モデルから削除されました。これを再導入すると（通常は v5 以前のソースからコピーされたものですが）、不要な引数がすべてのレイヤーに渡されるようになります。キャッシュの更新は past_key_values.update(key_states, value_states, self.layer_idx) であり、位置情報の伝達は行われません。

```diff
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

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

```diff
+@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__ に属します。

```diff
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

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

```diff
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 の計算、および保存が静かに誤動作します。

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

### TRF049

Flags init calls in __init__ methods in modeling_*.py and modular_*.py: nn.init.* / init.* primitives and in-place initializers on own parameters (self.weight.data.normal_()). 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.

```diff
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 を受け取るという契約から逸脱します。

```diff
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

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

```diff
-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 に登録されたハブのアテンションカーネルがこれらに到達しないという問題があります。インターフェース経由でディスパッチする単一のアテンションクラスが辞書の代わりに機能します。レガシーの親クラスからこれを継承・伝播させないでください。

```diff
-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:]のようなスライスによってshift_logits/shift_labels（およびshifted_バリアント）を構築するフラグの代入が検出されます。すでにシフト済みのラベルを受け取る（shift_labels = kwargs.pop("shift_labels", labels)）ことは正しいイディオムであり、フラグは立てられません。self.loss_functionはラベルを自身でシフトするため、modelingコードで事前にシフトすると、二重にシフトされたターゲットで学習が行われるか、独自の損失パスを強制することになります。Decoder-onlyモデルは生のラベルを渡し、損失関数にシフトさせます。Encoder-decoderモデルはその逆のケースです。これらのラベルは、先頭に追加されたdecoder開始トークンによってすでにシフトされているため、損失関数が再度シフトしないようにshift_labels=labelsを渡します。

```diff
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

Flags `config = SomeConfig` as a class attribute on PreTrainedModel subclasses in modeling_*.py and modular_*.py. `PreTrainedModel.__init_subclass__` は `inspect.get_annotations(cls)` を介して、`config` の **アノテーション** から `config_class` を導出します。代入を行うと、この呼び出しが報告しない余分なクラス属性が作成され、サブクラスは親クラスの `config_class` を黙って保持したままになります。アノテーションのみを記述すると、実行時の値を持たず、属性も作成されず、正しく検出されます。

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

### TRF056

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

```diff
-        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>`、backbones）、`PreTrainedConfig` のサブクラス、`ModelOutput` のサブクラス、image processors、`ProcessorMixin` のサブクラス、およびそれらの公開メソッドである `forward`、`get_image_features`、`get_video_features`、`get_audio_features`、`get_text_features`、`preprocess`、`__call__` をチェックします。`modular_*.py` は、そこから生成されたファイルに対してチェックされます。このファイルがない場合、クラスにはイントロダクションやパラメータのドキュメントが、メソッドには引数のドキュメント、`Returns` セクション、使用例が一切付与されません。これらはすべて、`auto_docstring.py` から自動生成されるのではなく、モデルごとに手作業で記述する必要があります。

```diff
+@auto_docstring
 @dataclass
 class AcmeModelOutputWithPast(ModelOutput):
     logits: torch.FloatTensor | 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 文字列など、計算された名前（ループ内でレイヤーごとに 1 つのバッファを作成する場合など）は、属性代入の同等表現が存在しないため、対象外となります。torch>=2.5 では、`nn.Buffer` は `nn.Parameter` と同様に、通常の属性代入によってバッファを登録します。メソッド呼び出しによって作成されたバッファは、`__init__` を実行した際の副作用としてのみ存在するため、その 1 つを調整したい modular ファイルは、`__init__` 全体を再定義する必要があります。属性として代入されることで、単独で継承およびオーバーライドが可能になります。

```diff
-        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番目に勾配変換を適用します。シグネチャが異なる場合、誤ったテンソルに適用されるか、適用がスキップされる可能性があります。

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

## 違反の抑制

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

### インライン抑制

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

```py
# 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](https://github.com/huggingface/transformers-mlinter/blob/main/mlinter/rules.toml)内の該当するルールの`allowlist_models`リストに、そのモデルのディレクトリ名を追加してください。

```toml
[rules.TRF004]
allowlist_models = ["existing_model", "your_model_name"]
```

