본문 바로가기
C.W.K.
Stream
Lesson 06 of 06 · published

프로파일링: 진짜 병목 찾기

~12 min · profiler, perf, memory

Level 0텐서 탐구자
0 XP0/62 lessons0/13 achievements
0/120 XP to next level120 XP to go0% complete

측정하지 않은 건 최적화하지 마

PyTorch 프로파일러는 CPU와 GPU에서 연산별 실행 시간을 포착하고 Chrome 추적 JSON으로 내보내며, profile_memory=True일 때는 텐서 할당도 추적해. '학습 시간이 실제로 어디에 쓰이지?'와 '왜 메모리가 부족하지?'에 답하는 알맞은 도구야.

두 프로파일러의 서로 다른 목적

  • torch.profiler.profile: 현대적이고 포괄적인 기본 선택이야. CPU와 CUDA 시간, 메모리, Chrome 추적을 모두 다뤄.
  • torch.utils.bottleneck: 더 오래됐지만 가벼운 Python 감싸개야. 전체 프로파일러를 구성하지 않고 무엇이 느린지 빠르게 확인할 때 유용해.

Chrome 추적

프로파일러는 Chrome의 chrome://tracing 뷰어나 perfetto.dev에서 열 수 있는 JSON을 내보내. CPU와 GPU 연산을 시간축 위에서 소요 시간과 호출 관계까지 함께 볼 수 있어. 'cudaStreamSynchronize가 아주 길다'거나 '작은 연산 하나가 10,000번 호출된다'는 문제가 눈에 바로 보여.

재현성은 별도 주제지만 알아 둘 가치가 있어

디버깅이나 논문식 대조 실험을 위해 비트 단위로 같은 실행이 필요하다면 모든 난수 생성기의 씨앗을 설정하고 PyTorch에 결정론적 알고리즘을 사용하라고 명령해. 비용 없이 얻는 기능은 아니야. 일부 연산은 결정론적 구현이 없고, 다른 연산은 결정론적 모드에서 더 느려. 운영 학습보다는 디버깅에 사용해.

Code

torch.profiler: 기본 CPU+GPU 측정·python
import torch
from torch.profiler import profile, record_function, ProfilerActivity

with profile(
    activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
    record_shapes=True,
    profile_memory=True,
    with_stack=True,
) as prof:
    with record_function("model_inference"):
        out = model(input_data)

# Top ops by GPU time
print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=10))

# Export Chrome trace — open in chrome://tracing or perfetto.dev
prof.export_chrome_trace("/tmp/trace.json")
학습 반복문에 맞춰 단계를 나눈 프로파일러·python
import torch
from torch.profiler import profile, schedule, tensorboard_trace_handler, ProfilerActivity

# schedule(wait, warmup, active, repeat) — only profile some steps
sched = schedule(wait=2, warmup=2, active=4, repeat=1)

with profile(
    activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
    schedule=sched,
    on_trace_ready=tensorboard_trace_handler('/tmp/profile'),
) as prof:
    for step, (x, y) in enumerate(loader):
        if step >= 10: break
        out = model(x.cuda())
        loss = criterion(out, y.cuda())
        loss.backward()
        optimizer.step()
        optimizer.zero_grad()
        prof.step()                 # tells the profiler we crossed a step boundary
메모리 스냅샷: 누수 찾기·python
import torch

# Begin recording allocator history
torch.cuda.memory._record_memory_history(max_entries=100_000)

# ... run your training for a while ...

# Dump a snapshot — visualize at https://pytorch.org/memory_viz
torch.cuda.memory._dump_snapshot('/tmp/memory.pickle')

# Quick numeric summary
print(torch.cuda.memory_summary(abbreviated=True))
print(f"allocated: {torch.cuda.memory_allocated()/1e9:.2f} GB")
print(f"reserved : {torch.cuda.memory_reserved()/1e9:.2f} GB")
재현성을 최대로 높이기·python
import os, random, torch
import numpy as np

def seed_everything(seed=42):
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    # Force deterministic behavior even at a perf cost
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False
    torch.use_deterministic_algorithms(True, warn_only=True)
    os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8'

seed_everything(42)

External links

Exercise

모델 하나를 골라 학습 단계에 torch.profiler를 실행해 봐. 결과인 Chrome 추적을 perfetto.dev에서 열고 가장 오래 걸린 GPU 연산과 CPU 연산을 찾아. 컴파일, 더 큰 배치, num_workers 조정 중 하나를 적용한 뒤 다시 프로파일링하고 전후 수치를 기록해. 이 습관이 근거 있는 최적화와 막연한 믿음을 가르는 기준이야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.