Level 8: GPU 프로그래밍 (CUDA 기초)

Level 8

CUDA 개요

커널, 스레드, 블록, 그리드

50분
CUDA 개요 강의 영상
강의 영상 보기 (새 탭에서 재생)YouTube

📓Google Colab에서 실습하기

이 레슨은 PyTorch/GPU가 필요합니다. 노트북을 다운로드 후 Google Colab에서 열어주세요.

학습 내용

CUDA 개요

학습 목표

  • CUDA 플랫폼의 개념을 이해한다
  • Host와 Device의 관계를 이해한다
  • 커널 함수의 개념을 배운다
  • 스레드 계층 구조(Thread, Block, Grid)를 이해한다
  • threadIdx, blockIdx, blockDim의 활용법을 익힌다

CUDA란?

**CUDA(Compute Unified Device Architecture)**는 NVIDIA가 개발한 병렬 컴퓨팅 플랫폼입니다.

CUDA의 특징

특징설명
개발사NVIDIA
목적GPU를 범용 연산에 활용
언어C/C++ 확장 문법
등장2007년

CUDA가 아니었다면?

과거: GPU는 그래픽 처리 전용
     → 범용 연산 불가능

CUDA 등장 후: GPU를 일반 연산에 활용
     → 딥러닝 혁명의 기반
     → 과학 시뮬레이션 가속
     → 영상 처리 실시간화

Host와 Device

CUDA 프로그래밍에서는 두 가지 처리 장치를 사용합니다.

용어 정의

용어의미역할
HostCPU + 시스템 메모리프로그램 제어, 데이터 준비
DeviceGPU + GPU 메모리병렬 연산 수행

실행 흐름

┌─────────── Host (CPU) ───────────┐ │ 1. 데이터 준비 │ │ 2. GPU 메모리 할당 │ │ 3. Host → Device 데이터 복사 │ │ 4. 커널 실행 명령 │ │ 5. Device → Host 결과 복사 │ │ 6. 결과 후처리 │ └──────────────────────────────────┘ ↕ PCIe / NVLink ┌─────────── Device (GPU) ─────────┐ │ 병렬 연산 수행 │ │ (수천 개 스레드 동시 실행) │ └──────────────────────────────────┘

메모리 분리

Host Memory (RAM) Device Memory (VRAM) ┌─────────────┐ ┌─────────────┐ │ data[] │ ────→ │ d_data[] │ │ result[] │ ←──── │ d_result[] │ └─────────────┘ └─────────────┘ CPU용 GPU용

커널 함수

**커널(Kernel)**은 GPU에서 실행되는 함수입니다.

커널의 특징

  • __global__ 키워드로 선언
  • Host에서 호출하고 Device에서 실행
  • 여러 스레드가 동시에 같은 코드를 실행

커널 선언 예시

cuda
// __global__ 키워드로 커널 함수 선언 __global__ void vectorAdd(float* a, float* b, float* c, int n) { int idx = threadIdx.x + blockIdx.x * blockDim.x; if (idx < n) { c[idx] = a[idx] + b[idx]; // 각 스레드가 하나의 원소 처리 } }

함수 실행 위치 지정자

지정자호출 위치실행 위치용도
__global__HostDevice커널 함수
__device__DeviceDeviceGPU 내부 헬퍼 함수
__host__HostHost일반 CPU 함수 (기본값)

스레드 계층 구조

CUDA는 3단계 계층 구조로 스레드를 조직합니다.

Thread → Block → Grid

┌─────────────────────────────────────────────────────┐ │ Grid (그리드) │ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ │ Block 0 │ │ Block 1 │ │ Block 2 │ ... │ │ │ ┌─┬─┬─┬─┐ │ │ ┌─┬─┬─┬─┐ │ │ ┌─┬─┬─┬─┐ │ │ │ │ │T│T│T│T│ │ │ │T│T│T│T│ │ │ │T│T│T│T│ │ │ │ │ ├─┼─┼─┼─┤ │ │ ├─┼─┼─┼─┤ │ │ ├─┼─┼─┼─┤ │ │ │ │ │T│T│T│T│ │ │ │T│T│T│T│ │ │ │T│T│T│T│ │ │ │ │ └─┴─┴─┴─┘ │ │ └─┴─┴─┴─┘ │ │ └─┴─┴─┴─┘ │ │ │ └───────────┘ └───────────┘ └───────────┘ │ └─────────────────────────────────────────────────────┘ T = Thread (스레드)

계층별 특징

계층설명공유 메모리
Thread최소 실행 단위레지스터, 로컬 메모리
Block스레드의 그룹 (최대 1024개)Shared Memory 공유
Grid블록의 그룹Global Memory 공유

스레드 인덱스 변수

각 스레드는 자신의 위치를 알 수 있는 변수를 가집니다.

핵심 내장 변수

변수의미타입
threadIdx블록 내 스레드 인덱스dim3 (x, y, z)
blockIdx그리드 내 블록 인덱스dim3 (x, y, z)
blockDim블록의 크기dim3 (x, y, z)
gridDim그리드의 크기dim3 (x, y, z)

전역 인덱스 계산

cuda
// 1D 배열에서 전역 인덱스 계산 int globalIdx = threadIdx.x + blockIdx.x * blockDim.x; // 예시: blockDim.x = 256, blockIdx.x = 3, threadIdx.x = 100 // globalIdx = 100 + 3 * 256 = 868

시각적 이해

Block 0        Block 1        Block 2
[T0,T1,T2,T3]  [T0,T1,T2,T3]  [T0,T1,T2,T3]  (threadIdx.x)
 ↓              ↓              ↓
[0, 1, 2, 3]   [4, 5, 6, 7]   [8, 9,10,11]   (globalIdx)

커널 실행 구문

커널은 **실행 구성(Execution Configuration)**과 함께 호출됩니다.

실행 구문 형식

cuda
kernelFunction<<<gridSize, blockSize>>>(arguments); // └──────┬──────┘ // 그리드 크기, 블록 크기

예시: 10,000개 원소 처리

cuda
int n = 10000; int blockSize = 256; // 블록당 256 스레드 int gridSize = (n + blockSize - 1) / blockSize; // 올림 나눗셈 // gridSize = (10000 + 255) / 256 = 40 vectorAdd<<<gridSize, blockSize>>>(d_a, d_b, d_c, n); // 40개 블록 × 256 스레드 = 10,240 스레드 실행 // (240개는 경계 검사로 무시됨)

2D/3D 실행 구성

cuda
// 이미지 처리: 1920×1080 픽셀 dim3 blockSize(16, 16); // 16×16 = 256 스레드/블록 dim3 gridSize( (1920 + 15) / 16, // 120 블록 (1080 + 15) / 16 // 68 블록 ); imageProcess<<<gridSize, blockSize>>>(image, width, height); // 커널 내부 __global__ void imageProcess(...) { int x = threadIdx.x + blockIdx.x * blockDim.x; int y = threadIdx.y + blockIdx.y * blockDim.y; // 각 스레드가 하나의 픽셀 처리 }

완전한 CUDA 프로그램 구조

cuda
#include <cuda_runtime.h> #include <stdio.h> // 1. 커널 함수 정의 __global__ void vectorAdd(float* a, float* b, float* c, int n) { int idx = threadIdx.x + blockIdx.x * blockDim.x; if (idx < n) { c[idx] = a[idx] + b[idx]; } } int main() { int n = 10000; size_t size = n * sizeof(float); // 2. Host 메모리 할당 및 초기화 float *h_a = (float*)malloc(size); float *h_b = (float*)malloc(size); float *h_c = (float*)malloc(size); // 3. Device 메모리 할당 float *d_a, *d_b, *d_c; cudaMalloc(&d_a, size); cudaMalloc(&d_b, size); cudaMalloc(&d_c, size); // 4. Host → Device 복사 cudaMemcpy(d_a, h_a, size, cudaMemcpyHostToDevice); cudaMemcpy(d_b, h_b, size, cudaMemcpyHostToDevice); // 5. 커널 실행 int blockSize = 256; int gridSize = (n + blockSize - 1) / blockSize; vectorAdd<<<gridSize, blockSize>>>(d_a, d_b, d_c, n); // 6. Device → Host 복사 cudaMemcpy(h_c, d_c, size, cudaMemcpyDeviceToHost); // 7. 메모리 해제 cudaFree(d_a); cudaFree(d_b); cudaFree(d_c); free(h_a); free(h_b); free(h_c); return 0; }

정리

개념설명
CUDANVIDIA의 GPU 병렬 컴퓨팅 플랫폼
Host/DeviceCPU/GPU와 각각의 메모리
커널GPU에서 실행되는 __global__ 함수
Thread최소 실행 단위
Block스레드 그룹 (최대 1024개)
Grid블록 그룹
threadIdx블록 내 스레드 위치
blockIdx그리드 내 블록 위치
blockDim블록 크기

핵심 포인트: CUDA는 계층적 스레드 구조를 통해 수천 개의 스레드가 동시에 작업을 분담합니다.

레슨 정보

레벨
Level 8: GPU 프로그래밍 (CUDA 기초)
예상 소요 시간
50분
참고 영상
YouTube 링크

💡실습 환경 안내

이 레벨은 PyTorch/GPU가 필요하여 Google Colab 사용을 권장합니다.

Colab은 무료 GPU를 제공하여 PyTorch, CNN, Transformer 등을 실행할 수 있습니다.