cuDNN (CUDA Deep Neural Networks library)는 NVIDIA가 개발한 GPU 가속 라이브러리입니다.
┌─────────────────────────────────┐
│ 당신의 코드 (Python) │
│ model = nn.Conv2d(...) │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ PyTorch/TensorFlow │
│ (딥러닝 프레임워크) │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ cuDNN ← 여기! │
│ (딥러닝 연산 최적화) │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ CUDA │
│ (GPU 프로그래밍 플랫폼) │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ GPU 하드웨어 (RTX 4090 등) │
└─────────────────────────────────┘
이미지 처리에서 가장 많이 사용되는 연산
# 당신이 작성하는 코드
conv = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3)
output = conv(input_image)
# 내부적으로 cuDNN이 수행
# → GPU에서 초고속 합성곱 연산 실행
예시 3가지:
이미지 크기를 줄이는 연산
# 당신의 코드
maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
output = maxpool(feature_map)
# cuDNN이 최적화
# → GPU에서 빠르게 최댓값 찾기
예시 3가지:
학습을 안정화하는 연산
# 당신의 코드
batch_norm = nn.BatchNorm2d(64)
output = batch_norm(input)
# cuDNN이 가속화
# → 배치 통계를 GPU에서 빠르게 계산
예시 3가지:
비선형성을 추가하는 연산
# 당신의 코드
relu = nn.ReLU()
output = relu(x)
# cuDNN이 최적화
# → GPU에서 병렬로 빠르게 처리
예시 3가지:
시계열 데이터 처리
# 당신의 코드
lstm = nn.LSTM(input_size=100, hidden_size=50)
output, (h, c) = lstm(sequence)
# cuDNN이 전문 최적화
# → 순환 연산을 GPU에서 효율적으로 처리
예시 3가지:
cudnn.deterministictorch.backends.cudnn.deterministic = True # 또는 False
deterministic = True (결정론적 모드)의미: 항상 같은 알고리즘 사용
# 예시 1: 합성곱 연산
torch.backends.cudnn.deterministic = True
conv = nn.Conv2d(3, 64, 3).cuda()
input = torch.randn(1, 3, 224, 224).cuda()
# 실행 1
output1 = conv(input) # [0.123, 0.456, 0.789, ...]
# 실행 2
output2 = conv(input) # [0.123, 0.456, 0.789, ...] ← 완전히 동일!
왜 이렇게 할까?
True로 설정하면 가장 안정적인 알고리즘만 사용deterministic = False (기본값)의미: 빠른 알고리즘 우선 사용 (결과가 미세하게 다를 수 있음)
torch.backends.cudnn.deterministic = False
# 실행 1
output1 = conv(input) # [0.123, 0.456, 0.789, ...]
# 실행 2
output2 = conv(input) # [0.123, 0.456, 0.790, ...] ← 미세한 차이
# ↑ 마지막 자리 다름
예시 3가지:
# 예시 1: 부동소수점 오차
# GPU 연산 순서에 따라 0.0000001 정도 차이
# 예시 2: 병렬 처리
# 여러 GPU 코어가 동시에 계산하면 합산 순서가 달라질 수 있음
# (0.1 + 0.2) + 0.3 ≠ 0.1 + (0.2 + 0.3) (컴퓨터에서)
# 예시 3: 메모리 접근 패턴
# 데이터를 읽는 순서에 따라 미세한 차이 발생
cudnn.benchmarktorch.backends.cudnn.benchmark = True # 또는 False
benchmark = True (기본값, 자동 최적화)의미: 입력 크기에 맞는 가장 빠른 알고리즘을 자동으로 선택
torch.backends.cudnn.benchmark = True
conv = nn.Conv2d(3, 64, 3).cuda()
# 첫 실행: 여러 알고리즘 테스트 (느림)
input1 = torch.randn(32, 3, 224, 224).cuda()
output1 = conv(input1) # 0.5초 소요 (알고리즘 선택 중)
# 두 번째 실행: 캐시된 최적 알고리즘 사용 (빠름)
input2 = torch.randn(32, 3, 224, 224).cuda()
output2 = conv(input2) # 0.01초 소요 (최적화됨!)
동작 과정:
1. 처음 실행 시: 여러 알고리즘을 테스트해서 가장 빠른 것 선택
2. 이후 실행: 선택된 알고리즘을 계속 사용 (매우 빠름)
예시 3가지:
# 예시 1: 고정된 입력 크기 (이상적)
for epoch in range(100):
for batch in train_loader: # 항상 (32, 3, 224, 224)
output = model(batch) # 매우 빠름!
# 예시 2: 가변 입력 크기 (비효율적)
for image in images:
# 크기가 매번 다름: (1, 3, 200, 200), (1, 3, 300, 300), ...
output = model(image) # 매번 새로 알고리즘 선택! (느림)
# 예시 3: RNN에서 시퀀스 길이 변화
for sequence in sequences:
# 길이가 다름: [10, 20, 30, ...]
output = lstm(sequence) # 매번 최적화 재수행
benchmark = False (수동 모드)의미: 미리 정해진 알고리즘만 사용
torch.backends.cudnn.benchmark = False
# 항상 같은 알고리즘 사용
# → 느리지만 예측 가능
deterministic=True, benchmark=False ✅ 완벽한 재현성torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
특징:
사용 시기:
예시 3가지:
# 예시 1: 논문 작성
# "우리 모델은 정확도 87.3%를 달성했다"
# → 다른 연구자가 정확히 87.3%를 재현할 수 있어야 함
# 예시 2: A/B 테스트
# 두 모델을 공정하게 비교
model_A = train(config_A) # 정확도 85.2%
model_B = train(config_B) # 정확도 87.1%
# → B가 확실히 더 좋음
# 예시 3: 디버깅
# NaN 에러가 발생하는 지점을 정확히 찾기
deterministic=False, benchmark=True 🚀 최고 속도torch.backends.cudnn.deterministic = False
torch.backends.cudnn.benchmark = True
특징:
사용 시기:
예시 3가지:
# 예시 1: 대규모 데이터셋 학습
# ImageNet (100만 장) 학습 시 속도 중요
# 예시 2: 하이퍼파라미터 탐색
# 수백 번의 실험을 빠르게 수행
# 예시 3: 실시간 추론
# 자율주행, 실시간 번역 등
deterministic=True, benchmark=True ⚠️ 모순torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = True # 권장하지 않음!
특징:
deterministic이 우선순위를 가짐benchmark=True가 무시됨deterministic=False, benchmark=False 🤷 중간torch.backends.cudnn.deterministic = False
torch.backends.cudnn.benchmark = False
특징:
import time
import torch
import torch.nn as nn
def benchmark_test():
model = nn.Conv2d(3, 64, 3).cuda()
input = torch.randn(32, 3, 224, 224).cuda()
# 조합 1: 완벽한 재현성
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
start = time.time()
for _ in range(100):
output = model(input)
time1 = time.time() - start
# 조합 2: 최고 속도
torch.backends.cudnn.deterministic = False
torch.backends.cudnn.benchmark = True
start = time.time()
for _ in range(100):
output = model(input)
time2 = time.time() - start
print(f"재현성 모드: {time1:.3f}초")
print(f"속도 모드: {time2:.3f}초")
print(f"속도 차이: {(time1/time2 - 1)*100:.1f}% 느림")
# 실행 결과 예시:
# 재현성 모드: 1.523초
# 속도 모드: 1.285초
# 속도 차이: 18.5% 느림
# 1. 일반 실험/개발 (기본 설정)
torch.backends.cudnn.benchmark = True
torch.backends.cudnn.deterministic = False
# → 빠르고 실용적
# 2. 논문 제출/재현 실험
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.deterministic = True
# → 완벽한 재현성
# 3. 대회 제출 (중간)
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.deterministic = False
# → 합리적인 타협
| 설정 | 의미 | True일 때 | False일 때 |
|---|---|---|---|
deterministic | 알고리즘 선택 | 안정적 알고리즘만 | 빠른 알고리즘 우선 |
benchmark | 자동 최적화 | 입력별 최적화 ON | 기본 알고리즘만 |
benchmark=True, deterministic=False (빠름)benchmark=False, deterministic=True (재현성)기억할 점: 대부분의 경우 결과 차이는 소수점 5~6자리 수준으로 미미하므로, 일반 실험에서는 속도를 우선하는 것이 실용적입니다! 🚀