transformers — Cursor rule: clean 🤗 Transformers code
A Cursor rule that sets coding standards for 🤗 Transformers work: modular models, type hints, and Trainer instead of hand-rolled training loops.
.cursor/rules/transformers.mdcWhat transformers does
The rule attaches to Cursor and applies to **/*.py files. It spells out how to write 🤗 Transformers code: put new models under src/transformers/models/<model_name>/ in a modular file like modular_<model_name>.py, inherit from existing base classes, and reuse layers from other models rather than re-implementing them. After editing the modular file, the rule points you to python utils/modular_model_converter.py my_model to generate the single-file structure.
Style comes next. PEP 8 and the Google Python Style Guide, lines capped at 79 characters, docstrings and comments at 72. Before committing, run make style and make quality; for changes on your current branch, make fixup. Type hints are mandatory on public methods, and docstrings follow Google style with Args, Returns and Raises sections.
On performance the rule is blunt: train with transformers.Trainer instead of writing your own loop with an optimizer and manual gradient accumulation. Trainer brings mixed precision (fp16=True or bf16=True) and torch.compile via torch_compile=True. For inference, use transformers.pipeline rather than wiring a tokenizer, model and post-processing by hand. One caveat: make style, make fixup and the modular converter assume you are inside the library repo itself, so in an application project those commands won't do anything — worth checking before you rely on them.
What it helps with
- add a new model without copying existing layers
- get files PEP 8 clean before a commit
- annotate public methods with type hints
- swap a custom training loop for
Trainer - run inference through
pipelineinstead of manual glue
Example prompts for the agent
- Add a new model in
src/transformers/models/my_model/modular_my_model.pyfollowing the transformers rules - Rewrite this training loop using
Trainerwithfp16=True - Check this file against the transformers rule and fix line lengths
How to install transformers
Manually: put the files in place
.cursor/rules/transformers.mdcFrontmatter: description, globs, alwaysApply
Manually: put the files in place
.claude/rules/transformers.mdThe paths frontmatter field limits the files: move globs from the source into paths
AGENTS.md
Codex reads AGENTS.md: paste the rule text there
Manually: put the files in place
.github/instructions/transformers.instructions.mdThe applyTo field sets which files it applies to: move globs from the source into applyTo
Manually: put the files in place
.devin/rules/transformers.mdManually: put the files in place
.clinerules/transformers.mdStep by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules
Questions about transformers
How do I install the transformers rule in Cursor?
Create .cursor/rules/transformers.mdc and paste the rule contents into it. Cursor then applies it to files matching the **/*.py globs.
What does the transformers rule do?
It tells the agent how to write 🤗 Transformers code: modular model definitions, formatting, type hints, training through Trainer and inference through pipeline.
Which files does the rule cover?
The frontmatter sets globs to **/*.py, so it applies to Python files in your project.
Source text
transformers.mdc · CC0-1.0
---
description: Definitive guidelines for writing high-quality, maintainable, and performant code with 🤗 Transformers, ensuring consistency and adherence to 2025 best practices.
globs: **/*.py
---
# transformers Best Practices
This guide outlines the definitive best practices for developing with 🤗 Transformers, focusing on reliability, readability, and production readiness. Adhere to these rules to ensure your code integrates seamlessly with the ecosystem and passes all CI checks.
## 1. Code Organization and Structure
Always follow the "Modular Transformers" framework for new models. This reduces boilerplate and promotes reusability.
### 1.1. Modular Model Definitions
Place new model definitions in `src/transformers/models/<model_name>/` using a modular file (e.g., `modular_<model_name>.py`). Inherit from existing base classes and import components from other models to minimize code duplication.
❌ BAD: Re-implementing common layers or full models from scratch.
```python
# src/transformers/models/my_model/modeling.py
class MyModelAttention(nn.Module):
# ... duplicate attention logic ...
class MyModel(PreTrainedModel):
# ... full model re-implementation ...
```
✅ GOOD: Inheriting and reusing components.
```python
# src/transformers/models/my_model/modular_my_model.py
from ..llama.modeling_llama import LlamaAttention, LlamaModel
from ..llama.configuration_llama import LlamaConfig
class MyModelConfig(LlamaConfig):
model_type = "my_model"
# Add/override specific config parameters
class MyModelAttention(LlamaAttention):
# Only override specific methods if needed, otherwise inherit directly
def forward(self, hidden_states, attention_mask=None, **kwargs):
# Custom logic if different from LlamaAttention
return super().forward(hidden_states, attention_mask, **kwargs)
class MyModel(LlamaModel):
# Override the attention layer if MyModelAttention is different
def __init__(self, config):
super().__init__(config)
self.attention = MyModelAttention(config) # Use custom attention
```
After creating the modular file, generate the single-file structure:
```bash
python utils/modular_model_converter.py my_model
```
## 2. Python Style and Formatting
Strictly adhere to PEP 8 and the Google Python Style Guide. Automated tools enforce this.
### 2.1. Automated Formatting
Always run `make style` and `make quality` locally before committing. For changes in your current branch, use `make fixup`.
❌ BAD: Manual formatting, inconsistent spacing, un-sorted imports.
```python
import os, sys
from transformers import AutoModel
def my_func(arg1,arg2):
if arg1 == True:
return arg2
```
✅ GOOD: Consistent, auto-formatted code.
```python
import os
import sys
from transformers import AutoModel
def my_func(arg1: bool, arg2: str) -> str:
if arg1: # Use direct boolean evaluation
return arg2
return ""
```
### 2.2. Line Length
Limit all lines to a maximum of 79 characters. Docstrings and comments should be 72 characters. Use Python's implicit line continuation.
❌ BAD: Long, unreadable lines.
```python
model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=10, output_attentions=True, output_hidden_states=True, return_dict=True)
```
✅ GOOD: Wrapped lines using parentheses.
```python
model = AutoModelForSequenceClassification.from_pretrained(
"bert-base-uncased",
num_labels=10,
output_attentions=True,
output_hidden_states=True,
return_dict=True,
)
```
## 3. Type Hints and Docstrings
Type hints are mandatory for all public methods. Docstrings must follow the Google style.
### 3.1. Type Annotations
Use `from __future__ import annotations` for forward references. Annotate all function arguments, return values, and class attributes.
❌ BAD: Missing type hints, unclear intent.
```python
def process_data(data, config):
"""Processes input data."""
# ...
return processed_data
```
✅ GOOD: Clear, explicit type hints.
```python
from __future__ import annotations
from typing import Any, Dict
def process_data(data: list[str], config: Dict[str, Any]) -> list[int]:
"""Processes input data according to the provided configuration.
Args:
data: A list of string inputs to be processed.
config: A dictionary containing processing parameters.
Returns:
A list of integers representing the processed data.
"""
# ...
return [len(d) for d in data]
```
### 3.2. Docstring Conventions
Follow the Google Python Style Guide for docstrings. Include a concise summary, Args, Returns, and Raises sections where applicable.
## 4. Performance Considerations
Prioritize efficiency and leverage built-in optimizations.
### 4.1. Optimized Training with `Trainer`
For training, always use `transformers.Trainer`. It provides out-of-the-box support for:
* Mixed precision training (`fp16=True` or `bf16=True`).
* `torch.compile` for graph compilation (`torch_compile=True`).
* FlashAttention (if available for your model/hardware).
❌ BAD: Writing custom training loops that re-implement `Trainer` features.
```python
# Manual training loop
optimizer = AdamW(model.parameters(), lr=1e-5)
for epoch in range(num_epochs):
# ... manual gradient accumulation, mixed precision, etc. ...
```
✅ GOOD: Leveraging `Trainer` for robust and optimized training.
```python
from transformers import Trainer, TrainingArguments
training_args = TrainingArguments(
output_dir="./results",
num_train_epochs=3,
per_device_train_batch_size=8,
fp16=True, # Enable mixed precision
torch_compile=True, # Enable torch.compile
# ... other args ...
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
# ...
)
trainer.train()
```
### 4.2. Efficient Inference with `Pipeline`
For common inference tasks, use `transformers.pipeline`. It handles tokenization, model inference, and post-processing efficiently.
❌ BAD: Manually managing tokenizers, models, and post-processing.
```python
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased")
inputs = tokenizer("Hello, world!", return_tensors="pt")
outputs = model(**inputs)
predictions = torch.argmax(outputs.logits, dim=-1)
# ... manual label mapping ...
```
✅ GOOD: Using `pipeline` for streamlined inference.
```python
from transformers import pipeline
classifier = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
result = classifier("I love this movie!")
# result: [{'label': 'POSITIVE', 'score': 0.99987}]
```
## 5. Testing Approaches
Thorough testing is non-negotiable. Every new feature or model requires unit tests.
### 5.1. Unit Tests
Write unit tests for every new model, utility, and significant code change. Verify:
* **Forward-pass shapes**: Ensure model outputs have expected dimensions.
* **Serialization**: Test saving and loading with `safetensors`.
* **Edge cases**: Test with various input sizes, empty inputs, etc.
❌ BAD: No tests, or only manual verification.
```python
# No test file for new_model.py
# Developer manually runs `new_model.py` to check if it works.
```
✅ GOOD: Dedicated test files (`test_new_model.py`) verifying core functionality.
```python
# tests/test_new_model.py
import unittest
import torch
from transformers import AutoModel, AutoTokenizer
from transformers.models.new_model import NewModel, NewModelConfig
class NewModelTester(unittest.TestCase):
def setUp(self):
self.config = NewModelConfig(vocab_size=100, hidden_size=16)
self.model = NewModel(self.config)
self.tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") # or a dummy tokenizer
def test_forward_pass(self):
input_ids = torch.randint(0, self.config.vocab_size, (2, 10))
outputs = self.model(input_ids)
self.assertIn("last_hidden_state", outputs)
self.assertEqual(outputs.last_hidden_state.shape, (2, 10, self.config.hidden_size))
def test_safetensors_serialization(self):
# Save and load with safetensors
tmpdir = self.create_temporary_dir()
self.model.save_pretrained(tmpdir, safe_serialization=True)
loaded_model = NewModel.from_pretrained(tmpdir)
self.assertTrue(torch.equal(self.model.state_dict()["embeddings.word_embeddings.weight"],
loaded_model.state_dict()["embeddings.word_embeddings.weight"]))
```
### 5.2. Local Test Execution
Use `utils/tests_fetcher.py` to identify relevant tests and run them with `pytest`.
```bash
python utils/tests_fetcher.py
python -m pytest -n 8 --dist=loadfile -rA -s $(cat test_list.txt)
```
## 6. Packaging and Deployment
Leverage `safetensors` and MLflow for robust model packaging.
### 6.1. `safetensors` for Model Serialization
Always use `safetensors` for saving and loading model weights. It's faster and more secure than traditional PyTorch checkpoints.
❌ BAD: Using `torch.save` or `model.save_pretrained(safe_serialization=False)`.
```python
torch.save(model.state_dict(), "model.pt")
```
✅ GOOD: Using `model.save_pretrained` with `safe_serialization=True`.
```python
model.save_pretrained("./my_model_dir", safe_serialization=True)
# To load:
loaded_model = AutoModel.from_pretrained("./my_model_dir")
```
### 6.2. MLflow Integration
For production deployments, integrate with `mlflow.transformers` to log models, configurations, and prompt templates. This ensures reproducible and traceable deployments.
```python
import mlflow
from transformers import pipeline
# Log a pipeline
with mlflow.start_run():
text_generator = pipeline("text-generation", model="gpt2")
mlflow.transformers.log_model(
transformers_model=text_generator,
artifact_path="text_generator_pipeline",
model_config={"max_new_tokens": 50, "do_sample": True},
input_example="Hello, my name is",
)
# Load for inference
logged_model = mlflow.pyfunc.load_model("runs:/<run_id>/text_generator_pipeline")
result = logged_model.predict(["Hello, my name is"])
```
## 7. Virtual Environments
Always work within a dedicated virtual environment.
❌ BAD: Installing dependencies globally.
```bash
pip install transformers[dev] # Installs into system Python
```
✅ GOOD: Using `venv` or `conda` for isolated environments.
```bash
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]" # Editable install with dev dependencies
```
© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc