Communitygithub.com

pytorch-patterns

PyTorch 深度學習模式與最佳實務,用於建構穩健、高效且可重現的訓練流程、模型架構與資料載入。在編寫或審查 PyTorch 訓練迴圈、模型架構或資料載入時,或當執行結果無法重現時使用。

pytorch-patterns 是什麼?

此技能提供一套完整的 PyTorch 開發模式與最佳實務,涵蓋設備無關程式碼、可重現性設定、明確的張量形狀管理、模型架構、訓練驗證迴圈、資料管線、檢查點儲存與載入,以及效能最佳化(如混合精度訓練、梯度檢查點與 torch.compile)。支援所有 PyTorch 驅動的專案,包括分類、分割、生成模型等。透過遵循這些模式,開發者可以避免常見反模式(如遺漏模型 eval 模式、在訓練迴圈中重複移動模型至 GPU、或錯誤使用 .item()),確保程式碼可移植、記憶體效率高,並能產生穩定且可重現的實驗結果。此技能特別適合在 Codex 或 Cursor 等 AI 編碼助手中啟用,以自動生成或審查符合業界標準的 PyTorch 程式碼。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/pytorch-patterns

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

PyTorch 開發模式

符合慣例的 PyTorch 模式與最佳實務,用於建構穩健、高效且可重現的深度學習應用。

啟用時機

  • 編寫新的 PyTorch 模型或訓練腳本
  • 審查深度學習程式碼
  • 除錯訓練迴圈或資料管線
  • 最佳化 GPU 記憶體使用量或訓練速度
  • 設定可重現的實驗

核心原則

1. 設備無關程式碼

總是編寫能在 CPU 與 GPU 上運作且不硬編碼裝置的程式碼。

# 好:設備無關
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = MyModel().to(device)
data = data.to(device)

# 壞:硬編碼裝置
model = MyModel().cuda()  # 若無 GPU 則崩潰
data = data.cuda()

2. 可重現性優先

設定所有隨機種子以獲得可重現的結果。

# 好:完整可重現性設定
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

# 壞:無種子控制
model = MyModel()  # 每次執行權重都不同

3. 明確的形狀管理

始終記錄並驗證張量形狀。

# 好:帶有形狀註解的前向傳播
def forward(self, x: torch.Tensor) -> torch.Tensor:
    # x: (batch_size, channels, height, width)
    x = self.conv1(x)    # -> (batch_size, 32, H, W)
    x = self.pool(x)     # -> (batch_size, 32, H//2, W//2)
    x = x.view(x.size(0), -1)  # -> (batch_size, 32*H//2*W//2)
    return self.fc(x)    # -> (batch_size, num_classes)

# 壞:無形狀追蹤
def forward(self, x):
    x = self.conv1(x)
    x = self.pool(x)
    x = x.view(x.size(0), -1)  # 這是什麼尺寸?
    return self.fc(x)           # 這會正常運作嗎?

模型架構模式

乾淨的 nn.Module 結構

# 好:組織良好的模組
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)

# 壞:所有邏輯都在 forward 中
class ImageClassifier(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, x):
        x = F.conv2d(x, weight=self.make_weight())  # 每次呼叫都建立權重!
        return x

適當的權重初始化

# 好:明確的初始化
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)

訓練迴圈模式

標準訓練迴圈

# 好:完整的訓練迴圈含最佳實務
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()  # 務必設定為訓練模式
    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)  # 比 zero_grad() 更有效率

        # 混合精度訓練
        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)

驗證迴圈

# 好:正確的評估
@torch.no_grad()  # 比包在 torch.no_grad() 區塊中更有效率
def evaluate(
    model: nn.Module,
    dataloader: DataLoader,
    criterion: nn.Module,
    device: torch.device,
) -> tuple[float, float]:
    model.eval()  # 務必設定為評估模式——停用 dropout,使用執行中的 BN 統計量
    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

資料管線模式

自訂資料集

# 好:帶有型別提示的乾淨資料集
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

有效率的 DataLoader 設定

# 好:最佳化的 DataLoader
dataloader = DataLoader(
    dataset,
    batch_size=32,
    shuffle=True,            # 訓練時打亂
    num_workers=4,           # 平行資料載入
    pin_memory=True,         # 更快的 CPU->GPU 傳輸
    persistent_workers=True, # 各 epoch 間保持 worker 存活
    drop_last=True,          # 為 BatchNorm 保持一致的批次大小
)

# 壞:緩慢的預設值
dataloader = DataLoader(dataset, batch_size=32)  # num_workers=0, 無 pin_memory

可變長度資料的自訂 Collate

# 好:在 collate_fn 中填充序列
def collate_fn(batch: list[tuple[torch.Tensor, int]]) -> tuple[torch.Tensor, torch.Tensor]:
    sequences, labels = zip(*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)

檢查點模式

儲存與載入檢查點

# 好:包含所有訓練狀態的完整檢查點
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

# 壞:只儲存模型權重(無法恢復訓練)
torch.save(model.state_dict(), "model.pt")

效能最佳化

混合精度訓練

# 好:使用 GradScaler 的 AMP
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)

大型模型的梯度檢查點

# 好:以計算換取記憶體
from torch.utils.checkpoint import checkpoint

class LargeModel(nn.Module):
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        # 在反向傳播時重新計算激活值以節省記憶體
        x = checkpoint(self.block1, x, use_reentrant=False)
        x = checkpoint(self.block2, x, use_reentrant=False)
        return self.head(x)

使用 torch.compile 加速

# 好:編譯模型以加快執行(PyTorch 2.0+)
model = MyModel().to(device)
model = torch.compile(model, mode="reduce-overhead")

# 模式:"default"(安全),"reduce-overhead"(更快),"max-autotune"(最快)

快速參考:PyTorch 慣用語

慣用語說明
model.train() / model.eval()訓練/評估前務必設定模式
torch.no_grad()推論時停用梯度
optimizer.zero_grad(set_to_none=True)更有效率的梯度清除
.to(device)設備無關的張量/模型放置
torch.amp.autocast混合精度,速度提升 2 倍
pin_memory=True更快的 CPU→GPU 資料傳輸
torch.compileJIT 編譯以加速(2.0+)
weights_only=True安全的模型載入
torch.manual_seed可重現的實驗
gradient_checkpointing以計算換取記憶體

應避免的反模式

# 壞:驗證時忘記 model.eval()
model.train()
with torch.no_grad():
    output = model(val_data)  # Dropout 仍在作用!BatchNorm 使用批次統計量!

# 好:務必設定為評估模式
model.eval()
with torch.no_grad():
    output = model(val_data)

# 壞:原地操作破壞 autograd
x = F.relu(x, inplace=True)  # 可能破壞梯度計算
x += residual                  # 原地加法破壞 autograd 圖

# 好:非原地操作
x = F.relu(x)
x = x + residual

# 壞:在訓練迴圈內重複將資料移至 GPU
for data, target in dataloader:
    model = model.cuda()  # 每次迭代都移動模型!

# 好:在迴圈前一次移動模型
model = model.to(device)
for data, target in dataloader:
    data, target = data.to(device), target.to(device)

# 壞:在 backward 之前使用 .item()
loss = criterion(output, target).item()  # 從計算圖中分離!
loss.backward()  # 錯誤:無法透過 .item() 反向傳播

# 好:僅在記錄時使用 .item()
loss = criterion(output, target)
loss.backward()
print(f"Loss: {loss.item():.4f}")  # backward 之後使用 .item() 沒問題

# 壞:未正確使用 torch.save
torch.save(model, "model.pt")  # 儲存整個模型(脆弱,不可移植)

# 好:儲存 state_dict
torch.save(model.state_dict(), "model.pt")

請記住:PyTorch 程式碼應為設備無關、可重現且注重記憶體效率。若有疑問,請使用 torch.profiler 進行分析,並透過 torch.cuda.memory_summary() 檢查 GPU 記憶體。

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/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

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.

相關技能