Communitygithub.com

pytorch-patterns

Modèles et bonnes pratiques PyTorch pour construire des pipelines d'entraînement, architectures de modèles et chargements de données robustes, efficaces et reproductibles. À utiliser lors de la rédaction ou de la révision de boucles d’entraînement, architectures ou chargements de données PyTorch, ou lorsque l’exécution ne sera pas reproductible.

Qu'est-ce que pytorch-patterns ?

Ce skill fournit un ensemble structuré de modèles idiomatiques PyTorch pour développer des applications d'apprentissage profond robustes, efficaces et reproductibles. Il couvre les principes fondamentaux comme l'écriture de code indépendant du périphérique (CPU/GPU), la configuration complète de la reproductibilité via les graines aléatoires, et la gestion explicite des formes des tenseurs. Le contenu détaille des modèles d'architecture propres pour les modules `nn.Module`, l'initialisation des poids, les boucles d'entraînement et de validation standard avec précision mixte et écrêtage de gradient, ainsi que des pipelines de données optimisés incluant `DataLoader`, `Dataset` personnalisé et fonctions `collate_fn`. Il aborde également les stratégies de checkpoint (sauvegarde/chargement complet), les optimisations de performance (précision mixte avec `GradScaler`, `torch.compile`, checkpointing de gradient) et présente un tableau de référence rapide des idiomes clés ainsi qu'une liste d'anti-modèles à éviter (comme l'oubli de `model.eval()`, les opérations sur place cassant l'autograd, ou les déplacements répétés des données sur GPU). Le skill est conçu pour être utilisé lors de l'écriture ou de la révision de code PyTorfch, du débogage de boucles d’entraînement, de l'optimisation de la mémoire GPU et de la mise en place d'expériences reproductibles, et s'applique à tout environnement utilisant PyTorch (Claude Code, Cursor, Codex, etc.).

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/pytorch-patterns

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Modèles de Développement PyTorch

Modèles idiomatiques PyTorch et bonnes pratiques pour construire des applications d'apprentissage profond robustes, efficaces et reproductibles.

Quand Activer

  • Écriture de nouveaux modèles PyTorch ou de scripts d’entraînement
  • Révision de code d’apprentissage profond
  • Débogage de boucles d’entraînement ou de pipelines de données
  • Optimisation de l’utilisation de la mémoire GPU ou de la vitesse d’entraînement
  • Mise en place d’expériences reproductibles

Principes Fondamentaux

1. Code Indépendant du Périphérique

Toujours écrire du code fonctionnant à la fois sur CPU et GPU sans coder en dur le périphérique.

# Bon : Indépendant du périphérique
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = MyModel().to(device)
data = data.to(device)

# Mauvais : Périphérique codé en dur
model = MyModel().cuda()  # Plante si pas de GPU
data = data.cuda()

2. Reproductibilité Avant Tout

Définir toutes les graines aléatoires pour des résultats reproductibles.

# Bon : Configuration complète de reproductibilité
def set_seed(seed: int = 42) -> None:
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    np.random.seed(seed)
    random.seed(seed)
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False

# Mauvais : Pas de contrôle de graine
model = MyModel()  # Poids différents à chaque exécution

3. Gestion Explicite des Formes

Toujours documenter et vérifier les formes des tenseurs.

# Bon : Passage avant annoté avec les formes
def forward(self, x: torch.Tensor) -> torch.Tensor:
    # x: (batch_size, canaux, hauteur, largeur)
    x = self.conv1(x)    # -> (batch_size, 32, H, L)
    x = self.pool(x)     # -> (batch_size, 32, H//2, L//2)
    x = x.view(x.size(0), -1)  # -> (batch_size, 32*H//2*L//2)
    return self.fc(x)    # -> (batch_size, num_classes)

# Mauvais : Pas de suivi des formes
def forward(self, x):
    x = self.conv1(x)
    x = self.pool(x)
    x = x.view(x.size(0), -1)  # Quelle est la taille ?
    return self.fc(x)           # Est-ce que ça marchera ?

Modèles d'Architecture

Structure Propre de nn.Module

# Bon : Module bien organisé
class ImageClassifier(nn.Module):
    def __init__(self, num_classes: int, dropout: float = 0.5) -> None:
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2),
        )
        self.classifier = nn.Sequential(
            nn.Dropout(dropout),
            nn.Linear(64 * 16 * 16, num_classes),
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = self.features(x)
        x = x.view(x.size(0), -1)
        return self.classifier(x)

# Mauvais : Tout dans forward
class ImageClassifier(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, x):
        x = F.conv2d(x, weight=self.make_weight())  # Crée le poids à chaque appel !
        return x

Initialisation Correcte des Poids

# Bon : Initialisation explicite
def _init_weights(self, module: nn.Module) -> None:
    if isinstance(module, nn.Linear):
        nn.init.kaiming_normal_(module.weight, mode="fan_out", nonlinearity="relu")
        if module.bias is not None:
            nn.init.zeros_(module.bias)
    elif isinstance(module, nn.Conv2d):
        nn.init.kaiming_normal_(module.weight, mode="fan_out", nonlinearity="relu")
    elif isinstance(module, nn.BatchNorm2d):
        nn.init.ones_(module.weight)
        nn.init.zeros_(module.bias)

model = MyModel()
model.apply(model._init_weights)

Modèles de Boucle d'Entraînement

Boucle d'Entraînement Standard

# Bon : Boucle d’entraînement complète avec bonnes pratiques
def train_one_epoch(
    model: nn.Module,
    dataloader: DataLoader,
    optimizer: torch.optim.Optimizer,
    criterion: nn.Module,
    device: torch.device,
    scaler: torch.amp.GradScaler | None = None,
) -> float:
    model.train()  # Toujours passer en mode entraînement
    total_loss = 0.0

    for batch_idx, (data, target) in enumerate(dataloader):
        data, target = data.to(device), target.to(device)

        optimizer.zero_grad(set_to_none=True)  # Plus efficace que zero_grad()

        # Entraînement en précision mixte
        with torch.amp.autocast("cuda", enabled=scaler is not None):
            output = model(data)
            loss = criterion(output, target)

        if scaler is not None:
            scaler.scale(loss).backward()
            scaler.unscale_(optimizer)
            torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
            scaler.step(optimizer)
            scaler.update()
        else:
            loss.backward()
            torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
            optimizer.step()

        total_loss += loss.item()

    return total_loss / len(dataloader)

Boucle de Validation

# Bon : Évaluation correcte
@torch.no_grad()  # Plus efficace que d'encapsuler dans un bloc torch.no_grad()
def evaluate(
    model: nn.Module,
    dataloader: DataLoader,
    criterion: nn.Module,
    device: torch.device,
) -> tuple[float, float]:
    model.eval()  # Toujours passer en mode évaluation — désactive dropout, utilise les stats BN cumulées
    total_loss = 0.0
    correct = 0
    total = 0

    for data, target in dataloader:
        data, target = data.to(device), target.to(device)
        output = model(data)
        total_loss += criterion(output, target).item()
        correct += (output.argmax(1) == target).sum().item()
        total += target.size(0)

    return total_loss / len(dataloader), correct / total

Modèles de Pipeline de Données

Dataset Personnalisé

# Bon : Dataset propre avec indications de type
class ImageDataset(Dataset):
    def __init__(
        self,
        image_dir: str,
        labels: dict[str, int],
        transform: transforms.Compose | None = None,
    ) -> None:
        self.image_paths = list(Path(image_dir).glob("*.jpg"))
        self.labels = labels
        self.transform = transform

    def __len__(self) -> int:
        return len(self.image_paths)

    def __getitem__(self, idx: int) -> tuple[torch.Tensor, int]:
        img = Image.open(self.image_paths[idx]).convert("RGB")
        label = self.labels[self.image_paths[idx].stem]

        if self.transform:
            img = self.transform(img)

        return img, label

Configuration Efficace de DataLoader

# Bon : DataLoader optimisé
dataloader = DataLoader(
    dataset,
    batch_size=32,
    shuffle=True,            # Mélanger pour l'entraînement
    num_workers=4,           # Chargement parallèle
    pin_memory=True,         # Transfert CPU->GPU plus rapide
    persistent_workers=True, # Garder les workers actifs entre les époques
    drop_last=True,          # Tailles de batch constantes pour BatchNorm
)

# Mauvais : Valeurs par défaut lentes
dataloader = DataLoader(dataset, batch_size=32)  # num_workers=0, pas de pin_memory

Collate Personnalisé pour Données de Longueur Variable

# Bon : Remplir les séquences dans collate_fn
def collate_fn(batch: list[tuple[torch.Tensor, int]]) -> tuple[torch.Tensor, torch.Tensor]:
    sequences, labels = zip(*batch)
    # Remplir à la longueur max du batch
    padded = nn.utils.rnn.pad_sequence(sequences, batch_first=True, padding_value=0)
    return padded, torch.tensor(labels)

dataloader = DataLoader(dataset, batch_size=32, collate_fn=collate_fn)

Modèles de Point de Contrôle (Checkpoint)

Sauvegarde et Chargement de Points de Contrôle

# Bon : Point de contrôle complet avec tout l'état d'entraînement
def save_checkpoint(
    model: nn.Module,
    optimizer: torch.optim.Optimizer,
    epoch: int,
    loss: float,
    path: str,
) -> None:
    torch.save({
        "epoch": epoch,
        "model_state_dict": model.state_dict(),
        "optimizer_state_dict": optimizer.state_dict(),
        "loss": loss,
    }, path)

def load_checkpoint(
    path: str,
    model: nn.Module,
    optimizer: torch.optim.Optimizer | None = None,
) -> dict:
    checkpoint = torch.load(path, map_location="cpu", weights_only=True)
    model.load_state_dict(checkpoint["model_state_dict"])
    if optimizer:
        optimizer.load_state_dict(checkpoint["optimizer_state_dict"])
    return checkpoint

# Mauvais : Sauvegarde uniquement des poids du modèle (impossible de reprendre l’entraînement)
torch.save(model.state_dict(), "model.pt")

Optimisation des Performances

Entraînement en Précision Mixte

# Bon : AMP avec GradScaler
scaler = torch.amp.GradScaler("cuda")
for data, target in dataloader:
    with torch.amp.autocast("cuda"):
        output = model(data)
        loss = criterion(output, target)
    scaler.scale(loss).backward()
    scaler.step(optimizer)
    scaler.update()
    optimizer.zero_grad(set_to_none=True)

Checkpointing de Gradient pour Grands Modèles

# Bon : Échanger du calcul contre de la mémoire
from torch.utils.checkpoint import checkpoint

class LargeModel(nn.Module):
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        # Recalculer les activations pendant la rétropropagation pour économiser la mémoire
        x = checkpoint(self.block1, x, use_reentrant=False)
        x = checkpoint(self.block2, x, use_reentrant=False)
        return self.head(x)

torch.compile pour la Vitesse

# Bon : Compiler le modèle pour une exécution plus rapide (PyTorch 2.0+)
model = MyModel().to(device)
model = torch.compile(model, mode="reduce-overhead")

# Modes : "default" (sûr), "reduce-overhead" (plus rapide), "max-autotune" (le plus rapide)

Référence Rapide : Idiomes PyTorch

IdiomeDescription
model.train() / model.eval()Toujours définir le mode avant entraînement/évaluation
torch.no_grad()Désactiver les gradients pour l'inférence
optimizer.zero_grad(set_to_none=True)Effacement plus efficace des gradients
.to(device)Placement tenseur/modèle indépendant du périphérique
torch.amp.autocastPrécision mixte pour une vitesse ×2
pin_memory=TrueTransfert de données CPU→GPU plus rapide
torch.compileCompilation JIT pour la vitesse (2.0+)
weights_only=TrueChargement sécurisé du modèle
torch.manual_seedExpériences reproductibles
gradient_checkpointingÉchanger du calcul contre de la mémoire

Anti-Modèles à Éviter

# Mauvais : Oublier model.eval() pendant la validation
model.train()
with torch.no_grad():
    output = model(val_data)  # Dropout toujours actif ! BatchNorm utilise les stats du batch !

# Bon : Toujours définir le mode évaluation
model.eval()
with torch.no_grad():
    output = model(val_data)

# Mauvais : Opérations sur place qui cassent l'autograd
x = F.relu(x, inplace=True)  # Peut casser le calcul des gradients
x += residual                  # L'ajout sur place casse le graphe autograd

# Bon : Opérations sans modification sur place
x = F.relu(x)
x = x + residual

# Mauvais : Déplacer les données sur GPU à plusieurs reprises dans la boucle d’entraînement
for data, target in dataloader:
    model = model.cuda()  # Déplace le modèle À CHAQUE itération !

# Bon : Déplacer le modèle une seule fois avant la boucle
model = model.to(device)
for data, target in dataloader:
    data, target = data.to(device), target.to(device)

# Mauvais : Utiliser .item() avant backward
loss = criterion(output, target).item()  # Détache du graphe !
loss.backward()  # Erreur : impossible de rétropropager avec .item()

# Bon : Appeler .item() uniquement pour les logs
loss = criterion(output, target)
loss.backward()
print(f"Perte : {loss.item():.4f}")  # .item() après backward est correct

# Mauvais : Ne pas utiliser torch.save correctement
torch.save(model, "model.pt")  # Sauvegarde tout le modèle (fragile, non portable)

# Bon : Sauvegarder state_dict
torch.save(model.state_dict(), "model.pt")

Rappel : Le code PyTorch doit être indépendant du périphérique, reproductible et économe en mémoire. En cas de doute, profiler avec torch.profiler et vérifier la mémoire GPU avec torch.cuda.memory_summary().

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

Skills associés