Environment/Ubuntu

NVIDIA GPU 드라이버, CUDA, cuDNN 개념 간단 정리

EddyLee 2026. 6. 4. 15:27

NVIDIA GPU Driver

(목적) 운영체제 (windows/Linux)와 내 본체에 있는 GPU를 연결해주는 커널 모듈.

GPU를 컴퓨터 자원으로 인식하는 과정.

⇒ 이것이 잘 깔려있다면, ‘nvidia-smi’ 명령어로 드라이버 버전과 GPU 상태를 확인 가능하다.

CUDA Toolkit

(목적) NVIDIA가 제공하는 GPU 병렬 프로그래밍을 위한 키트

GPU 프로그래밍을 위해 반드시 필요한 API · 라이브러리

컴파일러(nvcc), 런타임 라이브러리, API 헤더, 샘플 코드 등이 포함된다.

  • 컴파일: .cu 확장자 CUDA C/C++ 코드를 GPU에서 실행 가능한 바이너리로 빌드하게 해준다.
  • 런타임: 호스트와 디바이스 간 메모리 전송, 커널 실행, 스트림 관리 등 지원한다.
  • 수치 연산 라이브러리: 행렬곱이나 합성곱과 풀링(cuDNN과 함께) 등을 최적화된 형태로 제공한다.

cuDNN

(목적) 딥러닝 연산 (합성곱, 풀링 등등)에 특화된 함수 모음

딥러닝 연산을 수십 배 빠르게 해 주는 특수 가속기

  • PyTorch나 Tensorflow같은 프레임워크가 이 함수들을 내부적으로 호출한다.

 

따라서 제로베이스에서 딥러닝을 돌리려고 하면, 다음과 같은 과정으로 설치를 진행해주면 된다.

 

GPU 드라이버 설치 -> CUDA Toolkit 설치 (GPU마다 권장하는 CUDA 버전이 있으니 확인하고) -> cuDNN 라이브러리 설치 (이것 또한 CUDA 버전에 맞추기!) -> conda(가상환경), torch, tensorflow 등 필요한 것 다운받기.

 


그러면 아래의 간단한 MLP코드를 작성해놨는데, 이를 기반으로 머신러닝과 GPU의 연관성에 대해서 공부해보도록 하자.

 

코드에 주석으로 달아놨으니, 참고하자.

 

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

# 1) 하이퍼파라미터 정의
input_dim  = 28 * 28    # (예: MNIST 같은 28×28 흑백 이미지)
hidden_dim = 128
output_dim = 10         # (숫자 0~9를 분류)
batch_size = 64
lr         = 1e-3
epochs     = 5

# 2) 더미 데이터셋 준비 (여기서는 랜덤 텐서로 대체, CPU 메모리 상에 생성)
# 실제론 torchvision.datasets.MNIST 등을 사용.

# x, y 텐서들은 기본적으로 CPU DRAM에 위치
x = torch.randn(1000, input_dim)      
y = torch.randint(0, output_dim, (1000,))

dataset = TensorDataset(x, y)
loader  = DataLoader(dataset, batch_size=batch_size, shuffle=True)

# 3) MLP 모델 정의
class MLP(nn.Module):
    def __init__(self, in_dim, hid_dim, out_dim):
        super().__init__()
        self.layers = nn.Sequential(
            nn.Linear(in_dim, hid_dim),  # 가중치·바이어스 파라미터는 아직 CPU 메모리에
            nn.ReLU(),
            nn.Linear(hid_dim, out_dim)
        )
    def forward(self, x):
        # x: (batch_size, input_dim) → output: (batch_size, output_dim)
        return self.layers(x)

# 4) 디바이스 설정 (GPU가 있으면 GPU, 없으면 CPU)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 여기서 CUDA 드라이버/런타임 검사 후, GPU가 있으면 cuda:0을 선택

# 5) 모델·손실함수·최적화기 초기화
model     = MLP(input_dim, hidden_dim, output_dim).to(device)
# model.to(device) 호출 시에,
#   CUDA 런타임은 모델 파라미터가 CPU DRAM에서 GPU VRAM으로 복사
#   이후 모든 model.parameters()는 GPU 메모리에 위치하게 됨
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=lr)

# 6) 학습 루프
for epoch in range(1, epochs+1):
    model.train()
    total_loss = 0.0

    for xb, yb in loader:
        # 6-1) 배치를 device로 복사 (GPU라면 GPU로 복사)
        xb = xb.to(device)
        yb = yb.to(device)

        # 6-2) 순전파: 예측값 계산 (GPU VRAM 상에서 cuBLAS/cuDNN 커널을 실행한다)
        preds = model(xb)
        # 행렬곱, 합성곱이나 활성화 함수 ReLU 등, 커널이 VRAM 데이터를 꺼내와 SM 코어에서 병렬 연산

        # 6-3) 손실 계산 (GPU VRAM 상에서 연산)
        loss = criterion(preds, yb)

        # 6-4) 기울기 초기화 (GPU 메모리의 gradient 버퍼를 0으로)
        optimizer.zero_grad()

        # 6-5) 역전파: 그래디언트 계산 (GPU VRAM 상에서 연산, 그래디언트가 VRAM에 쌓임)
        loss.backward()

        # 6-6) 파라미터 업데이트 (GPU 메모리 상에서 가중치 조정)
        optimizer.step()
		
        # 6-7) CPU로 손실값 이동하여 집계
        total_loss += loss.item() * xb.size(0)

    avg_loss = total_loss / len(loader.dataset)
    print(f"Epoch {epoch}/{epochs} — Loss: {avg_loss:.4f}")