Communitygithub.com

pytorch-patterns

PyTorch 딥러닝 패턴과 모범 사례로, 강력하고 효율적이며 재현 가능한 학습 파이프라인, 모델 아키텍처, 데이터 로딩을 구축합니다. PyTorch 학습 루프, 모델 아키텍처, 또는 데이터 로딩을 작성하거나 검토할 때, 또는 실행 결과가 재현되지 않을 때 사용하세요.

pytorch-patterns란 무엇인가요?

이 스킬은 PyTorch 개발자에게 필수적인 관용적 패턴과 모범 사례를 제공합니다. 디바이스에 구애받지 않는 코드 작성, 재현성 보장, 텐서 형태 관리 등 핵심 원칙을 강조하며, 깔끔한 nn.Module 구조, 적절한 가중치 초기화, 표준 학습/검증 루프, 효율적인 데이터 로딩 구성, 체크포인트 저장 및 로드 등 실용적인 예제를 포함합니다. 또한 혼합 정밀도 학습, 그래디언트 체크포인팅, torch.compile을 통한 성능 최적화 기법을 다루고, 일반적인 안티 패턴(예: model.eval() 누락, in-place 연산 남용)을 지적합니다. Cursor, Codex, Claude Code 등 다양한 AI 어시스턴트에서 활용 가능하며, SKILL.md 형식으로 제공되어 개발자가 즉시 참고할 수 있습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/pytorch-patterns

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

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가 없으면 충돌
model = MyModel().cuda()
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. 명시적인 형태 관리

항상 텐서 형태를 문서화하고 검증하세요.

# 좋음: 형태 주석이 달린 forward 패스
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()  # 항상 평가 모드 설정 — 드롭아웃 비활성화, 배치 정규화 실행 통계 사용
    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, # 에폭 간 워커 유지
    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.autocast2배 속도를 위한 혼합 정밀도
pin_memory=True더 빠른 CPU→GPU 데이터 전송
torch.compile속도를 위한 JIT 컴파일 (2.0+)
weights_only=True안전한 모델 로딩
torch.manual_seed재현 가능한 실험
gradient_checkpointing메모리를 위해 연산 절충

피해야 할 안티 패턴

# 나쁨: 검증 중 model.eval()을 잊어버림
model.train()
with torch.no_grad():
    output = model(val_data)  # 드롭아웃이 아직 활성화! BatchNorm이 배치 통계를 사용!

# 좋음: 항상 평가 모드 설정
model.eval()
with torch.no_grad():
    output = model(val_data)

# 나쁨: 자동미분을 깨뜨리는 in-place 연산
x = F.relu(x, inplace=True)  # 그래디언트 계산을 깨뜨릴 수 있음
x += residual                  # In-place 덧셈이 autograd 그래프를 깨뜨림

# 좋음: Out-of-place 연산
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)

# 나쁨: 역전파 전에 .item() 사용
loss = criterion(output, target).item()  # 그래프에서 분리!
loss.backward()  # 오류: .item()을 통해 역전파할 수 없음

# 좋음: 로깅에만 .item() 호출
loss = criterion(output, target)
loss.backward()
print(f"Loss: {loss.item():.4f}")  # 역전파 후 .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/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.

관련 스킬