Transformers documentation

Quy tắc cấu trúc mô hình

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.2).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Quy tắc cấu trúc mô hình

Transformers áp dụng một tập hợp các quy tắc tĩnh lên mọi tệp modeling_*.py, modular_*.py và configuration_*.py. Gói mlinter cung cấp bộ máy kiểm tra, và kho lưu trữ giữ tập hợp quy tắc đang hoạt động của nó trong utils/rules.toml. Tệp TOML cục bộ đó cho phép chúng tôi bật, tắt hoặc tinh chỉnh các quy tắc một cách nhanh chóng mà không cần chờ một bản phát hành transformers-mlinter mới.

Xem tài liệu mlinter để biết tham chiếu đầy đủ về trình kiểm tra và chi tiết sử dụng.

Đây là các quy ước mô hình dự kiến khi thêm hoặc thay đổi mã mô hình hóa. Chúng giúp giữ cho mã nguồn nhất quán và đảm bảo khả năng tương thích với các tính năng như pipeline parallelism, device maps và weight tying.

Chạy trình kiểm tra

make typing chạy mlinter cùng với trình kiểm tra kiểu ty thông qua wrapper của repo, do đó nó sẽ nhận utils/rules.toml. Chạy trực tiếp cùng một wrapper đó bằng các lệnh sau.

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

Cờ --changed-only là tùy chọn nhanh nhất trong quá trình phát triển. Nó chỉ kiểm tra các tệp bạn đã sửa đổi so với nhánh chính. Nếu bạn gọi trực tiếp mlinter thay vì wrapper, hãy truyền --rules-toml utils/rules.toml để áp dụng các ghi đè cục bộ.

Sửa một vi phạm

Khi phát hiện vi phạm quy tắc, lỗi sẽ có dạng như sau:

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

Sử dụng ID quy tắc để tra cứu cách khắc phục trong tham chiếu quy tắc. TRF013 được kích hoạt khi một lớp con của PreTrainedModel không gọi self.post_init(). Phương thức này thực hiện các bước hoàn tất thiết yếu, và việc bỏ qua nó sẽ gây ra lỗi thời gian chạy.

 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()

Tham khảo các quy tắc

Mỗi quy tắc bên dưới liệt kê những gì nó thực thi và một diff hiển thị cách sửa. Chạy python utils/check_modeling_structure.py --rule TRF001 để xem tài liệu tích hợp sẵn cho bất kỳ quy tắc nào với bộ quy tắc hiện tại của repo.

TRF001

Kiểm tra xem config_class của <Model>PreTrainedModel có được đặt tên là <Model>Config hay không. Sự không khớp có thể làm hỏng quá trình tải, các lớp tự động và kỳ vọng của nhà phát triển.

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

TRF002

Kiểm tra xem base_model_prefix có phải là một chuỗi literal không rỗng và không chứa khoảng trắng hay không. Các tiền tố không hợp lệ có thể làm hỏng ánh xạ khóa khi nạp trọng số và việc truy cập mô hình cơ sở.

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

TRF003

Đánh dấu mẫu if not return_dict: return (x,) cũ trong forward. Việc phân nhánh return_dict thủ công là dài dòng và dễ gây sai sót. Hãy để @capture_output hoặc @can_return_tuple xử lý.

-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

Kiểm tra rằng không có lớp model nào định nghĩa phương thức tie_weights. Ghi đè tie_weights sẽ làm hỏng việc tải, tính toán device_map và lưu trữ. Khai báo các trọng số liên kết trong thuộc tính lớp _tied_weights_keys.

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

TRF005

Kiểm tra hình dạng của _no_split_modules khi có mặt. Các giá trị không đúng định dạng có thể làm hỏng việc phân vùng và chia nhỏ thiết bị.

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

TRF006

Kiểm tra rằng các đối số cache trong chữ ký forward được sử dụng trong thân hàm. Một đối số cache không được sử dụng cho thấy hỗ trợ cache chưa hoàn chỉnh và hành vi API không nhất quán.

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

TRF007

Kiểm tra các gán thuộc tính cho self sau self.post_init() trong init. Việc thay đổi cấu trúc mô hình sau post_init sẽ bỏ qua các công việc khởi tạo và hoàn tất của nó.

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

TRF008

Kiểm tra rằng add_start_docstrings trên một lớp model nhận được một đối số không rỗng. Một đối số rỗng sẽ tạo ra tài liệu API được sinh ra không rõ ràng và chất lượng thấp.

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

TRF009

Flags imports into another model’s package from a model’s shipped implementation files: modeling*, configuration, processing_, imageprocessing, videoprocessing, featureextraction, tokenization_ and generation*.py. Three forms count: package path (from transformers.models.other.modeling_other import X), relative path (from ..other.configuration_other import X) and public API (from transformers import OtherModel) — for the last the owning directory is inferred from the class name and confirmed against the classes it defines, so an unresolvable name is left alone. Out of scope: `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`. One model, one definition: model A’s behavior lives in its own files, and a change to model B must not silently change model A — for every file kind, not just modeling. Reach sub-configs through AutoConfig and CONFIG_MAPPING, and use a modular file to build on another model’s code.

-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

Kiểm tra rằng các lớp con trực tiếp của PreTrainedConfig/PretrainedConfig trong configuration*.py và modular*.py có @strict(accept_kwargs=True). Nếu thiếu, một config mới sẽ bỏ qua thỏa thuận kiểm tra kiểu dữ liệu thời gian chạy của repo và lệch khỏi tiêu chuẩn config dựa trên dataclass.

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

TRF011

Trong forward() của các lớp con của PreTrainedModel, các truy cập thuộc tính của submodule mà torch.nn.Identity không có: trên các biến vòng lặp của self.layers, và self.<submodule>.<attr> trong đó <attr> không phải là thuộc tính chuẩn của nn.Module. Song song hóa pipeline có thể thay thế bất kỳ submodule nào bằng torch.nn.Identity, do đó việc đọc một thuộc tính tùy chỉnh (ví dụ: decoder_layer.attention_type) từ nó sẽ gây ra AttributeError khi chạy. Hãy đọc metadata cho từng lớp từ 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

Các thao tác in-place (ví dụ: .normal(), .zero(), …) trên trọng số của module bên trong _init_weights. Các tham số mang theo các cờ nội bộ để theo dõi xem chúng có cần khởi tạo lại hay không; các thao tác in-place sẽ bỏ qua các cờ này. Hãy sử dụng các nguyên thủy init.

+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

Kiểm tra rằng mọi lớp con của PreTrainedModel có định nghĩa init đều gọi self.post_init(). Trong các file modular, việc gọi super().init() được tính, vì nó truyền tiếp post_init của lớp cha. post_init thực hiện các bước hoàn thiện quan trọng (khởi tạo trọng số, thiết lập gradient checkpointing, …); bỏ qua nó sẽ gây ra các lỗi runtime tinh vi.

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

TRF014

Các cờ trust_remote_code được sử dụng hoặc truyền vào (ví dụ dưới dạng kwarg) trong các tệp tích hợp model native. trust_remote_code tải mã tùy ý, bao gồm cả binary — đây là tính năng mạnh mẽ dành cho người dùng, không phải thứ mà một tích hợp native có thể phụ thuộc, vì mã từ xa không thể được xem xét hoặc bảo trì trong 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

Khi một lớp con của PreTrainedModel đặt _tied_weights_keys khác rỗng, hệ thống sẽ kiểm tra trường tie_word_embeddings trong tệp cấu hình đồng hành. Nếu không có trường này, người dùng không thể kiểm soát việc ràng buộc trọng số: mô hình sẽ ràng buộc một cách vô điều kiện, làm hỏng các vòng lặp tuần tự hóa và quá trình tinh chỉnh với các đầu không bị ràng buộc.

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

TRF016

Khi một lớp imageprocessing.py hoặc videoprocessing.py khai báo các thuộc tính boolean do_* (do_resize, do_rescale, do_normalize, do_convert_rgb, …) và ghi đè preprocess() hoặc _preprocess(), hãy kiểm tra xem mỗi cờ có còn được sử dụng ở đó không: được tham chiếu trực tiếp, được ủy quyền qua super().preprocess/_preprocess(…, **kwargs), hoặc — chỉ với image processor — được chuyển tiếp qua _preprocess_image_like_inputs/_prepare_image_like_inputs. do_sample_frames được miễn trừ: preprocess() cơ bản sẽ sử dụng nó trước khi _preprocess() chạy. Một do_X mà bản ghi đè không bao giờ tham chiếu là vô dụng: việc đặt do_X=False sẽ không có tác dụng, thao tác vẫn được thực hiện, và các ghi đè theo từng lần gọi sẽ bị hỏng một cách im lặng.

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

Với các class mang cả @auto_docstring và @dataclass, @auto_docstring được kiểm tra trước. Các decorator được áp dụng từ dưới lên, nên @dataclass ở trên sẽ chạy @auto_docstring trước, trên một class chưa có init được tổng hợp: khi đó nó sẽ sửa init của class cha thay vì doc của class con.

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

TRF018

Kiểm tra rằng mọi lớp con của PreTrainedModel ghi đè _init_weights(self, module, ...) đều gọi lên qua super()._init_weights(...). Các file modular cũng chấp nhận các sentinel PreTrainedModel._init_weights(self, module), PreTrainedModel._init_weights(module) và raise AttributeError(...). Đối với việc ghi đè hoàn toàn có chủ đích, hãy tắt cảnh báo bằng cách đặt # trf-ignore: TRF018 phía trên phương thức. Phương thức cơ sở _init_weights bao phủ các loại module chuẩn (Linear, Embedding, LayerNorm, RotaryEmbedding, …). Việc bỏ qua nó sẽ khiến mọi submodule mà bản ghi đè không xử lý được ở trạng thái chưa khởi tạo — điều này vẫn vượt qua các bài kiểm tra và chỉ bộc lộ về sau như một lỗi khởi tạo trọng số tinh vi (xem 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

Đánh dấu các _defaults không rỗng trên các TypedDict *ProcessorKwargs trong processing_*.py. Các mô hình được phát hành trước ngày cắt sẽ được miễn. Việc hardcode _defaults khiến cấu hình processor bị phân tán trong mã nguồn Python, gây khó khăn khi ghi đè từ config và làm phình to mã nguồn. Trong processor_config.json trên hub, chúng đi kèm với checkpoint và có thể được cập nhật mà không cần thay đổi mã.

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

TRF020

Trong các thư mục mô hình có cấu hình khai báo kv_lora_rank (Multi-head Latent Attention), kiểm tra lớp attention sở hữu phép chiếu mở rộng KV LoRA (kv_b_proj, hoặc bất kỳ nn.Linear(config.kv_lora_rank, ...) nào): phép mở rộng này phải nằm trong một phương thức chuyên dụng (ví dụ expand_kv) được forward() gọi, chứ không được viết inline. Trong các file modular, một phương thức kế thừa từ lớp cơ sở được import được tính là hợp lệ. Các backend bên ngoài (vLLM/SGLang) ghi đè phép mở rộng để sử dụng trực tiếp bộ nhớ đệm KV đã nén. Nếu viết inline trong forward(), sẽ không có gì để ghi đè, do đó backend phải vật chất hóa toàn bộ bộ nhớ đệm — làm mất đi lợi ích tiết kiệm bộ nhớ mà MLA tồn tại để phục vụ.

+    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

In modeling*.py and modular.py, flags torch.tensor(<value>, ..., device=<non-cpu>) where <value> provably resolves to a Python scalar — from numeric literals and arithmetic on them, torch.finfo/iinfo fields, scalar-returning builtins and math. calls, locals bound exactly once, self.<attr> assigned in the class body, and config fields annotated int/float/bool in the companion configuration file (following attribute_map). Anything that may also be a sequence (eos_token_id: int | list[int] | None) or that cannot be resolved is left alone. init, _init_weights, post_init and post_init are exempt: they never run inside a capture region. torch.tensor(<python scalar>, device=<accelerator>) materialises the value on the host then copies it to the device; CUDA graph capture forbids that copy, so the model cannot be captured. torch.full((), <value>, dtype=…, device=…) fills the same 0-d tensor on-device with a capturable kernel and no synchronisation.

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

Kiểm tra rằng mọi chuỗi trong danh sách _no_split_modules trong modeling*.py hoặc modular*.py đều đặt tên cho một lớp được định nghĩa trong tệp đó, được nhập vào tệp đó, hoặc được định nghĩa bởi một module anh em trong cùng thư mục model. Bổ sung cho TRF005, vốn chỉ kiểm tra hình dạng của giá trị. device_map khớp các chuỗi này với module.__class__.__name__ khi chạy, nên một tên cũ hoặc sai chính tả sẽ không khớp với gì và bị bỏ qua một cách im lặng — module mà nó nên giữ nguyên vẹn vẫn có thể bị tách ra giữa các thiết bị. Xóa các mục đặt tên cho các lớp của model khác thay vì sửa chúng: post_init đã thu thập _no_split_modules từ các submodel con.

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

Trong modeling*.py và modular.py, báo lỗi khi một hằng số nguyên lớn hơn 8 xuất hiện trong đối số kích thước của một bộ khởi tạo torch.nn (Linear, Embedding, LayerNorm, RMSNorm, GroupNorm, BatchNorm, InstanceNorm, Convd, ConvTranspose*d, Bilinear, MultiheadAttention), dù được truyền theo vị trí hay theo tên (in_features, out_features, in_channels, out_channels, num_embeddings, embedding_dim, embed_dim, normalized_shape, num_channels, hidden_size). Các đối số liên quan đến hình dạng toán tử (kernel_size, stride, padding, num_groups) bị bỏ qua; các hằng số không vượt quá 8 giúp giữ cho các đầu ra vô hướng, bộ phân loại nhị phân và số kênh RGB sạch sẽ. Các mô hình được thêm trước cutoff_date được miễn trừ. Việc cố định một chiều rộng bằng hằng số sẽ khóa module vào một kích thước checkpoint duy nhất: cùng một kiến trúc ở một quy mô khác sẽ bị lỗi lệch hình dạng khi nạp, và from_pretrained không thể chỉ ra giá trị nào là sai vì không có trường cấu hình nào trỏ đến nó. Điều này cũng làm chia rẽ nguồn sự thật, khiến việc chỉnh sửa cấu hình không còn thay đổi được mô hình được xây dựng.

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

Trong *.py và modular.py, các cờ gọi đến nhà máy mask (các điểm vào tiện ích mask create_causal_mask, create_bidirectional_mask, create_sliding_window_causal_mask, create_chunked_causal_mask, create_masks_for_generate, và bất kỳ hàm trợ giúp create_mask nào) bên trong một lớp không kế thừa từ PreTrainedModel — các khối nn.Module thuần túy như các lớp, module chú ý và bộ mã hóa. Việc xây dựng mask là công việc có độ phức tạp O(bình phương độ dài chuỗi) và không thay đổi theo từng lớp, do đó việc xây dựng nó trong lớp sẽ trả chi phí đó một lần cho mỗi lớp, và mỗi lớp sau đó sẽ sở hữu mask riêng của mình, khiến các backend chú ý không còn có thể nhận được một mask đã chuẩn bị duy nhất. Hãy xây dựng nó một lần trong model và truyền nó xuống.

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

Trong modeling*.py và modular*.py, một lớp không phải là PreTrainedModel được xác định chỉ có init và forward, gán chính xác một self.<attr> trong init, và thân forward chính xác là return self.<attr>(...) cho nó (docstring ở đầu bị bỏ qua). Bất kỳ phương thức nào khác, thuộc tính bổ sung, câu lệnh trước return, hoặc lời gọi super() trong forward đều có nghĩa là lớp đó thực hiện công việc riêng của nó. Lớp bao (wrapper) thêm một cấp độ vào mọi tên trọng số, vào _no_split_modules, các kế hoạch song song hóa và mọi ánh xạ chuyển đổi, trong khi không tính toán gì — và người đọc phải mở thêm một lớp nữa để tìm ra điều đó. Các lớp con của PreTrainedModel được miễn trừ: chúng tồn tại cho from_pretrained và các lớp auto ngay cả khi forward chỉ ủy quyền.

-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

Flags any assert statement in modeling*.py, modular.py and configuration_.py. python -O strips asserts, so a shape or config check written as one silently disappears in optimised runs. An assert also gives a bare AssertionError, where a ValueError can name the offending value and say what to do about it.

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

Kiểm tra 25 dòng đầu tiên của modeling*.py, modular.py, configuration_.py, processing*.py, image_processing.py và videoprocessing.py để tìm dòng Licensed under the <name> License được theo sau bởi mọi điều khoản của đoạn văn bản bảo hành tiêu chuẩn, từ You may obtain a copy of the License at đến limitations under the License.. Các dòng được làm phẳng và chuyển thành chữ thường trước, nên việc xuống dòng và phong cách chú thích không quan trọng. Tên giấy phép và dòng bản quyền không được kiểm tra: chúng thay đổi theo từng model. Một file được phát hành mà thiếu phần header sẽ khiến nguồn gốc của nó trở nên mơ hồ, và việc bổ sung sau đó đồng nghĩa với việc phải chỉnh sửa một file đã được phát hành. Việc chỉ khớp với Apache License sẽ bỏ qua các lỗi thực sự xảy ra: một đoạn văn bị cắt cụt giữa chừng, một header dừng lại sau URL, hoặc một header bị hỏng do thao tác tìm-đổi sai.

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

TRF029

Trong modeling*.py và modular*.py, một cờ báo hiệu __init__ nhận config cùng với một tham số có tên rõ ràng là trường của config (hidden_size, num_attention_heads, intermediate_size, head_dim, num_hidden_layers, embed_dim, dropout, eps, patch_size, rope_theta, …). Một tham số tùy chọn có giá trị mặc định là None được miễn trừ: đó là một sự ghi đè, không phải nguồn sự thật thứ hai, và đây là cách một lớp MLP phục vụ cả chiều rộng dense lẫn chiều rộng expert của một mô hình MoE. Một giá trị mặc định được hardcode như hidden_size: int = 1024 thì không được — nó sẽ thắng config bất cứ khi nào người gọi không truyền gì. kosmos2 được đưa vào danh sách cho phép: trang tài liệu của nó không thể suy ra từ tên thư mục, nên điểm cắt không thể bảo trợ nó. Cùng một con số giờ đây có hai nguồn sự thật và người gọi chọn người thắng, nên việc chỉnh sửa config không còn thay đổi mô hình được xây dựng nữa. Nó cũng đẩy kiến thức về kiến trúc ra mọi vị trí gọi, nơi nó không nên có mặt.

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

Trong modeling*.py và modular*.py, các chuỗi thuộc tính bắt nguồn từ config hoặc self.config có độ sâu từ ba cấp trở lên. config.hidden_size (một bước) và config.text_config.hidden_size (hai bước, truy cập sub-config thông thường) là hợp lệ. Mỗi dòng chỉ tính một vi phạm. Một module duyệt qua config.diffusion_config.atom_encoder_config.hidden_size sẽ bị ràng buộc với toàn bộ hệ thống phân cấp config thay vì chỉ phần riêng của nó, do đó không thể tái sử dụng, kiểm thử hoặc gán một sub-config khác. Hãy truyền sub-config liên quan xuống và chuỗi sẽ rút gọn về một bước.

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

Trong modeling*.py và modular*.py, một @dataclass cấp cao nhất mà các lớp cơ sở của nó không có lớp nào kết thúc bằng Output sẽ bị đánh dấu, trừ khi nó có hai hoặc nhiều trường bắt buộc — đó là các nhóm tham số nội bộ, mà ModelOutput sẽ từ chối lúc chạy. Một dataclass đầu ra thông thường không thể chỉ mục như tuple, không tồn tại khi return_dict=False, và không hiển thị với @auto_docstring, do đó các trường của nó không bao giờ xuất hiện trong tài liệu API được tạo. ModelOutput có sẵn cả ba tính năng này.

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

TRF032

Trong modeling*.py và modular*.py, các cờ maskedfill, masked_fill, full, full_like và new_full được gọi với một hằng số số học bị phủ định có độ lớn từ 1e3 trở lên. Một giá trị -1e9 được hardcode sẽ tràn thành -inf trong float16 và không hề gần giá trị nhỏ nhất trong float32, do đó cùng một mask sẽ hoạt động khác nhau tùy theo dtype và có thể tạo ra NaN sau softmax. torch.finfo(dtype).min là giá trị nhỏ nhất có thể biểu diễn được trong dtype đang thực sự chạy.

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

TRF033

Trong modeling*.py và modular*.py, các phương thức có tên bắt đầu bằng set_, ngoại trừ các phương thức theo hợp đồng của PreTrainedModel là set_input_embeddings, set_output_embeddings, set_decoder, set_encoder, set_attn_implementation và set_default_language. Một setter khiến hành vi phụ thuộc vào thứ tự gọi: giá trị không nằm trong config, do đó không được lưu, không được khôi phục bởi from_pretrained, và không hiển thị cho device-map hay kế hoạch song song hóa. Người dùng phải biết cách gọi nó, và việc quên gọi sẽ diễn ra một cách im lặng.

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

Cờ # noqa các chú thích, có hoặc không có mã, trong modeling*.py, modular.py và configuration_.py. Trong một tệp modular, F401, F821 và F822 được chấp nhận: đây là nguồn sinh ra mà cố ý không định nghĩa mọi tên mà nó sử dụng, nên nhóm lỗi tên chưa xác định của ruff sẽ kích hoạt trên mã đúng — các mục __all__ mà trình chuyển đổi điền vào, các lớp nằm trong mô hình cha, các import được giữ lại để xuất lại. Một # noqa chỉ nêu tên những mã đó sẽ bị bỏ qua; một # noqa nêu tên bất kỳ mã nào khác sẽ được báo cáo trên các mã còn lại. Một # noqa trần luôn được báo cáo; trong tệp modular, thông báo sẽ yêu cầu mã cụ thể thay vì viết lại. Các tệp mô hình là mã thông thường phải tuân theo các quy tắc lint của repo, nên một lệnh tắt nghĩa là vấn đề gốc vẫn còn đó — và một # noqa trần cũng che giấu mọi vi phạm tương lai trên dòng đó. Hãy sửa mã thay vì tắt.

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

TRF036

Trong *.py và modular*.py, mọi cấu trúc nn.Sequential(...) đều được đánh dấu. Sequential đặt tên cho các phần tử con theo vị trí, nên trọng số sẽ nằm tại mlp.0.weight và mlp.2.weight: do đó, ánh xạ chuyển đổi, _tied_weights_keys và mọi kế hoạch song song hóa đều tham chiếu đến các chỉ số, và việc chèn một lớp sẽ đổi tên mọi thứ phía sau nó. Nó cũng che giấu hàm forward, khiến các phép chuyển dtype và phần dư giữa các bước không thể nhìn thấy được tại nơi chúng diễn ra.

-        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

Trong modeling*.py và modular*.py, các lời gọi einsum được đánh dấu, đồng thời báo cáo phương trình nếu đó là một chuỗi văn bản cố định. Tính năng này bị tắt theo mặc định: einsum đôi khi là cách rõ ràng nhất để biểu diễn một phép co (contraction), nên đây là tùy chọn bật thay vì một quy ước bắt buộc. Một phương trình einsum mã hóa các hình dạng (shape) bằng một ký hiệu mà người đọc phải giải mã, và một phương trình được xây dựng động che giấu phép co nào thực sự được thực thi. Hãy mở rộng nó thành các thao tác matmul/transpose tường minh.

-        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

Kiểm tra rằng mọi tệp modeling*.py, processing.py, imageprocessing.py, videoprocessing.py, featureextraction.py và tokenization*.py đều có tệp tests/models/<model>/test.py tương ứng (modelingacme.py -> tests/models/acme/test_modeling_acme.py). Ngoại lệ: configuration.py, được bao phủ bởi ConfigTester trong tệp testmodeling.py đồng hành, và tokenization_utils.py, một helper được bao phủ thông qua tokenizer của nó; tokenization<name>_fast.py ánh xạ đến tệp test của phiên bản slow tương ứng. Một tệp modular*.py có thể định nghĩa nhiều họ cùng lúc, do đó các class của nó được định tuyến theo hậu tố tên — XxxModel/XxxPreTrainedModel/XxxFor<Task> modeling, XxxImageProcessor(Fast) image processing, XxxProcessor processing, XxxVideoProcessor video processing, XxxFeatureExtractor feature extraction, XxxTokenizer(Fast) tokenization, XxxConfig bị bỏ qua — và một vi phạm được báo cáo cho mỗi tệp test bị thiếu. # trf-ignore: TRF038 không được hỗ trợ; hãy dùng allowlist_models để ngoại lệ hiển thị rõ trong review. Một tệp nguồn không có tệp test sẽ không có độ bao phủ hồi quy: một forward pass bị hỏng, một ánh xạ chuyển đổi sai, hoặc một tokenizer làm mất token đặc biệt có thể được đưa vào và ở trạng thái hỏng vô thời hạn. Một config giả với trọng số ngẫu nhiên, hoặc một bảng từ vựng nhỏ viết tay, là đủ để chạy thử bất kỳ trường hợp nào trong số đó.

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

Tìm các khối if is_*_available(): import ... (bao gồm các tổ hợp như is_vision_available() and is_torch_available()) và đánh dấu import khi tên đó không được tham chiếu ở bất kỳ đâu khác trong file, kể cả bên trong các type hint dạng chuỗi và all. Kiểm tra unused-import của ruff không dọn dẹp được những trường hợp này: import vẫn có thể truy cập được, nên khối đó trông có vẻ ổn khi xét riêng lẻ. Khi một lần refactor không còn cần đến PIL.Image, torch, v.v., import được bảo vệ sẽ tồn tại như một gánh nặng chết và là tín hiệu gây hiểu nhầm về các phụ thuộc thực sự của file.

if is_vision_available():
-    from PIL import Image

TRF040

Trong modeling*.py và modular*.py, các phương thức được đánh dấu bằng cả @capture_outputs và @can_return_tuple. Bổ sung cho TRF003, vốn bao phủ việc phân nhánh return_dict thủ công trong forward(). Cả hai decorator đều pop return_dict, nên chỉ decorator ngoài cùng mới nhìn thấy giá trị thực. @capture_outputs đã xử lý chuyển đổi to_tuple, khiến @can_return_tuple trở nên thừa.

-@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

Trong tests/models//testtokenization.py, kiểm tra tệp có định nghĩa một lớp test được thu thập kế thừa từ TokenizerTesterMixin. Chỉ các lớp mà runner thu thập mới được tính — một cơ sở TestCase, hoặc quy ước đặt tên *Test khi cơ sở là lớp test của một model khác — do đó các tệp chỉ chứa helper sẽ bị bỏ qua, và một helper trộn vào bộ suite không đáp ứng quy tắc cho một lớp test thực sự. Việc kế thừa được theo dõi qua các cơ sở trong cùng tệp và vào lớp test tokenizer của một model khác được nhập theo tên; một cơ sở không thể phân giải sẽ không bao giờ được tính. Báo cáo trên lớp test đầu tiên không chạy bộ suite. auto được đưa vào danh sách cho phép: test_tokenization_auto.py kiểm tra việc phân giải AutoTokenizer, không phải một tokenizer. TokenizerTesterMixin là nơi thực sự kiểm tra vòng lặp encode/decode, padding và truncation, xử lý token đặc biệt, tính bền vững của token đã thêm và sự tương đương khi lưu/tải. Một test chỉ khẳng định một vài danh sách token id viết tay sẽ vượt qua trong khi tokenizer bị hỏng ở tất cả các khía cạnh đó, và vẫn trông như đã được kiểm tra khi xem xét.

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

TRF043

Đánh dấu tham số position_ids được khai báo trong chữ ký forward của các lớp có tên kết thúc bằng Attention. position_ids được tiêu thụ ở phía hạ nguồn bởi flash-attention padding-free training và phải được truyền qua kwargs. Việc đặt tên cho nó trong chữ ký sẽ nuốt mất nó trước khi giao diện attention có thể đọc được; chuẩn llama truyền position_embeddings cùngkwargs.

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

TRF044

Đánh dấu một tham số có tên cacheposition trong bất kỳ hàm nào trong modeling.py và modular_.py. cache_position đã bị loại bỏ khỏi tất cả các mô hình trong v5. Việc đưa nó trở lại (thường được sao chép từ các nguồn trước v5) sẽ kéo theo một đối số không còn hiệu lực xuyên qua mọi lớp; việc cập nhật cache là past_key_values.update(key_states, value_states, self.layer_idx), không có việc truyền 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

Đánh dấu các tham số output legacy attentions, output_hidden_states và return_dict trong các chữ ký forward trong modeling.py và modular_.py. Các mô hình được đóng góp trước ngày giới hạn được miễn trừ. Bộ chồng decorator chịu trách nhiệm kiểm soát output: @captureoutputs giải quyết các cờ output* đối với config và ghi lại các tensor thông qua _can_record_outputs, còn @can_return_tuple xử lý return_dict. Việc khai báo chúng trong chữ ký sẽ đưa lại việc truyền cờ thủ công, gây lệch khỏi các decorator.

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

TRF046

Gán cờ cho các thuộc tính của self trong các phương thức forward của modeling*.py và modular*.py. Trạng thái được ghi trong quá trình forward làm hỏng batching, torch.compile và việc suy luận về module. Trạng thái được mang theo phải được truyền một cách tường minh (các đối tượng cache, vòng lặp generate); các giá trị chỉ phụ thuộc vào config hoặc các hình dạng tĩnh nên được đặt trong 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

Gán cờ cho các thuộc tính của self trong preprocess, preprocess, call và post_process* methods trong image_processing.py và videoprocessing.py. Một processor giữ trạng thái giữa các lần gọi sẽ phá vỡ việc batch hóa preprocess-nhiều-rồi-postprocess: lần preprocess thứ hai sẽ ghi đè lên trạng thái mà lần postprocess thứ nhất cần. Trả về giá trị hoặc truyền nó qua chuỗi phương thức.

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

Các literal dạng list/tuple/set trong khai báo _tied_weights_keys ở cấp lớp. Bản v5 đã thay đổi _tied_weights_keys thành một dict ánh xạ mỗi tham số đích bị ràng buộc (tied) đến tham số nguồn của nó. Dạng list không còn chỉ rõ tham số nào là nguồn, do đó việc ràng buộc, tính toán device_map và lưu trữ sẽ hoạt động sai một cách im lặng.

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

TRF049

Các lệnh gọi init trong các phương thức init trong modeling*.py và modular.py: các nguyên thủy nn.init. / init.* và các bộ khởi tạo tại chỗ trên các tham số của chính lớp (self.weight.data.normal_()). Các mô hình được khởi tạo trên thiết bị meta, do đó các giá trị tensor được ghi trong init sẽ bị loại bỏ trước khi tải: một tham số chỉ được khởi tạo ở đó sẽ chứa nội dung ngẫu nhiên khi tinh chỉnh từ đầu hoặc sau khi tải lại từ thiết bị meta. Phân bổ bằng torch.empty trong init, khởi tạo trong _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

Các cờ gọi đến một lớp *RotaryEmbedding trong init của các lớp có tên kết thúc bằng Attention. Model sở hữu một rotary_emb duy nhất, xây dựng inv_freq một lần và truyền cos/sin xuống dưới dạng position_embeddings. Mỗi module rotary cho từng lớp attention sẽ nhân đôi các buffer, tính lại tần số cho từng lớp và lệch khỏi hợp đồng rằng attention nhận 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

So sánh các cờ với thuộc tính attn_implementation trong modeling.py và modular_.py. Việc điều phối backend thuộc về ALL_ATTENTION_FUNCTIONS.get_interface, và việc xử lý tensor có điều kiện theo backend (padding, reshaping) thuộc về các wrapper dùng chung dưới integrations/. Việc phân nhánh inline khiến phần thân model nhận thức được kernel và sẽ bị lỗi khi các backend mới được đăng ký.

-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

Đánh dấu các gán cấp module cho các tên kết thúc bằng ATTENTION_CLASSES trong modeling.py và modular_.py. Các lớp attention theo từng backend được chọn từ một dict là cách viết trước khi có interface: các lớp gần như giống hệt nhau sẽ dần khác biệt, và các kernel attention trên hub được đăng ký vào ALL_ATTENTION_FUNCTIONS sẽ không bao giờ đến được chúng. Một lớp attention duy nhất điều phối thông qua interface sẽ thay thế dict; không lan truyền nó từ một lớp cha cũ.

-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

Trong *.py và modular*.py, các gán cờ xây dựng logits/shift_labels (và các biến thể đã dịch chuyển) bằng cách cắt lát, chẳng hạn như labels[…, 1:], sẽ bị báo lỗi. Việc nhận các nhãn đã được dịch chuyển (shift_labels = kwargs.pop(“shift_labels”, labels)) là cách viết đúng và sẽ không bị báo lỗi. self.loss_function tự dịch chuyển nhãn, do đó việc dịch chuyển trước trong mã modeling sẽ huấn luyện trên các mục tiêu bị dịch chuyển hai lần hoặc buộc phải dùng một đường dẫn loss riêng. Các mô hình chỉ có decoder truyền nhãn thô và để loss tự dịch chuyển chúng. Các mô hình encoder-decoder là trường hợp đối xứng: nhãn của chúng đã được dịch chuyển bởi token bắt đầu decoder được thêm vào trước, do đó chúng truyền shift_labels=labels để ngăn loss dịch chuyển lần nữa.

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 như một thuộc tính lớp trên các lớp con của PreTrainedModel trong modeling*.py và modular*.py. PreTrainedModel.__init_subclass__ suy ra config_class từ một config annotation, thông qua inspect.get_annotations(cls). Một phép gán sẽ tạo ra một thuộc tính lớp thừa mà cuộc gọi đó không báo cáo, do đó lớp con âm thầm giữ lại config_class của lớp cha. Một annotation đơn thuần không có giá trị thời gian chạy, không tạo ra thuộc tính nào và được nhận diện đúng cách.

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

TRF056

Trong modeling*.py và modular*.py, các cờ .item() và .tolist() được gọi bên trong bất kỳ forward nào. Một .tolist() cung cấp cho đối số kích thước tách của split(...) được miễn trừ: torch.split cần các int của Python. Cả hai cuộc gọi đều đọc tensor trở lại host, điều mà dynamo không thể theo dõi, do đó đồ thị bị ngắt.

-        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

Kiểm tra @auto_docstring trên các lớp con công khai của PreTrainedModel (<Model>PreTrainedModel, <Model>Model, <Model>For<Task>, backbones), các lớp con của PreTrainedConfig, các lớp con của ModelOutput, image processors và các lớp con của ProcessorMixin, cũng như trên các phương thức công khai của chúng: forward, get_image_features, get_video_features, get_audio_features, get_text_features, preprocess và __call__. Một tệp modular_*.py được kiểm tra đối chiếu với các tệp được tạo ra từ nó. Nếu không có tệp này, một lớp sẽ được phát hành mà không có phần giới thiệu và không có tài liệu tham số, còn một phương thức sẽ không có tài liệu đối số, không có phần Returns và không có ví dụ sử dụng — tất cả những điều này sau đó sẽ phải được viết tay cho từng model thay vì được lấy từ auto_docstring.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

Trong modeling*.py và modular*.py, các cờ register_buffer("<name>", ...) được gọi với tên buffer là chuỗi literal, trên bất kỳ receiver nào (self, hoặc một module khác như layer.mamba). Một tên được tính toán — một biến hoặc f-string, ví dụ một buffer cho mỗi layer bên trong một vòng lặp — không có tương đương gán thuộc tính và được miễn trừ. Vì torch>=2.5 nn.Buffer đăng ký một buffer thông qua gán thuộc tính thông thường, giống như nn.Parameter. Một buffer được tạo bởi một lời gọi phương thức chỉ tồn tại như một tác dụng phụ của việc chạy __init__, do đó một file modular muốn chỉnh sửa một buffer phải định nghĩa lại toàn bộ __init__. Khi được gán như một thuộc tính, nó có thể được kế thừa và ghi đè một cách độc lập.

-        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

Đối với các thư mục mô hình mà kế hoạch song song tensor gán moe_tp_experts, kiểm tra xem các lớp *Experts được định tuyến có nhận trạng thái ẩn, chỉ số top-k và trọng số định tuyến top-k làm ba đối số vị trí đầu tiên của forward hay không. Các tên gọi khác như selected_experts và routing_weights được chấp nhận. MoeExpertsParallel áp dụng phép biến đổi gradient cho đối số vị trí thứ 3. Một chữ ký khác sẽ âm thầm áp dụng nó cho tensor sai hoặc bỏ qua nó.

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

Chặn các vi phạm

Nếu bạn cần tắt một vi phạm quy tắc, hãy sử dụng một trong hai tùy chọn bên dưới.

Inline suppression

Thêm chú thích # trf-ignore: RULE_ID vào dòng vi phạm. Bao gồm một lời giải thích để người xem hiểu tại sao việc bỏ qua này là hợp lý.

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

Không sử dụng trf-ignore để tắt các vi phạm cần được sửa trong mã.

allowlist_models

Đối với các model có mã nguồn cũ không thể sửa ngay, hãy thêm tên thư mục của model vào danh sách allowlist_models của quy tắc tương ứng trong mlinter rules.toml.

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