GPU 시스템 01 - GPU Kernel Engineer 로드맵
GPU 아키텍처부터 CUDA, Triton, 커널 최적화까지 어떤 순서로 공부하면 되는지
왜 GPU 시스템을 따로 공부해야 할까?
딥러닝을 하다 보면 결국 GPU를 쓰게 된다. 처음에는 PyTorch 한 줄로 모델을 올리고 학습하는 것만으로도 충분해 보인다. 그런데 모델이 커지고, 학습 시간이 길어지고, 특정 연산이 병목이 되기 시작하면 그때부터는 "GPU를 사용한다"와 "GPU를 이해한다" 사이의 차이가 크게 느껴진다.
GPU Kernel Engineer를 목표로 한다면 라이브러리를 잘 쓰는 것만으로는 부족하다. warp가 어떻게 스케줄링되는지, shared memory를 왜 쓰는지, 메모리 대역폭이 왜 항상 병목으로 나오는지 같은 질문을 직접 다룰 수 있어야 한다.
이 시리즈는 바로 그 감각을 만드는 데 초점을 둔다. GPU 아키텍처의 기본부터 CUDA 커널 작성, Triton, 그리고 실제 최적화 포인트까지 순서대로 올라간다.
조금 더 현실적인 상황으로 바꿔보자. 예를 들어 PyTorch로 모델을 학습시키는데 특정 attention block이나 normalization 구간이 병목이라고 하자. 프로파일러에서는 GPU 시간이 길게 찍히지만, 왜 느린지는 바로 안 보인다. 이때 필요한 것은 단순 API 사용법이 아니라:
- warp가 어떤 식으로 실행되는지
- 메모리 계층이 어떤 비용을 만드는지
- 현재 연산이 memory-bound인지 compute-bound인지
- kernel을 직접 손대야 하는 상황인지
를 판단하는 감각이다. 이 시리즈는 그 판단력을 만드는 쪽에 더 가깝다.
전체 흐름은 이렇게 잡는 편이 좋다
GPU 관련 학습은 주제가 너무 넓어서 처음부터 프레임워크나 최적화 팁만 따라가면 금방 헷갈린다. 그래서 아래 순서로 보는 것이 훨씬 낫다.
- GPU architecture
- CUDA kernel programming
- Triton kernel
- kernel optimization
이 순서가 중요한 이유는, 뒤로 갈수록 앞의 개념을 계속 재사용하기 때문이다. 예를 들어 memory coalescing이 왜 중요한지 이해하지 못하면 Triton의 block tiling도 그저 문법처럼 보이기 쉽다. 반대로 GPU 메모리 계층과 warp 실행 모델이 머릿속에 들어오면 CUDA 코드와 Triton 코드가 같은 문제를 다른 인터페이스로 푸는 것으로 보이기 시작한다.
Phase 1. GPU Architecture
가장 먼저 잡아야 할 것은 GPU가 CPU와 완전히 다른 방식으로 계산을 밀어붙인다는 사실이다.
여기서 핵심은 다음과 같다.
- thread, warp, block, grid의 관계
- global memory, shared memory, register의 차이
- memory bandwidth와 latency의 의미
- occupancy가 왜 중요한지
이 단계의 목표는 "코드가 GPU에서 어떻게 퍼져서 실행되는지"를 머릿속에 그릴 수 있게 되는 것이다.
많은 초심자가 여기서 바로 CUDA 문법부터 들어가지만, 그렇게 하면 코드가 왜 느린지 설명하기 어렵다. 반대로 thread, warp, block, memory hierarchy를 먼저 이해하면 나중에 CUDA 코드가 단순한 문법이 아니라 하드웨어 위의 execution plan처럼 보이기 시작한다.
실습은 너무 복잡할 필요가 없다. 아래 정도면 충분하다.
- CUDA 환경 구축
- vector add kernel
- matrix multiply kernel
vector add는 단순하지만 thread indexing을 이해하기 좋고, matrix multiply는 메모리 접근 패턴과 shared memory의 필요성을 보여주기 좋다.
Phase 2. CUDA Kernel Programming
아키텍처를 어느 정도 이해했다면, 이제는 직접 커널을 써야 한다.
이 단계에서는 단순히 CUDA 문법을 익히는 것이 아니라, 커널이 실제로 빨라지거나 느려지는 이유를 배워야 한다.
핵심 주제는 다음과 같다.
- memory coalescing
- shared memory 사용 패턴
- warp shuffle
- kernel launch configuration
- register pressure
실습은 reduction kernel, softmax kernel, optimized matrix multiply 정도가 좋다. 특히 softmax는 "계산 자체보다 메모리 이동과 reduction 구조가 더 중요하다"는 사실을 체감하기 좋은 예제다.
이 단계부터는 "코드가 돈다"와 "코드가 잘 돈다"의 차이를 본격적으로 보게 된다. 같은 연산이라도 coalescing, block size, shared memory, register pressure 때문에 성능이 크게 갈릴 수 있기 때문이다.
Phase 3. Triton Kernel
최근 LLM 쪽에서는 Triton을 빼놓고 이야기하기 어렵다. CUDA만 알아도 도움이 되지만, 실제 현장에서는 Triton으로 작성된 커널이나 Triton 기반 최적화를 자주 만나게 된다.
여기서는 다음을 다룬다.
- Triton programming model
- block tiling
- tile 단위 메모리 접근
- fused softmax
- layernorm kernel
Triton의 장점은 GPU 세부사항을 완전히 숨기지 않으면서도 CUDA보다 빠르게 실험해볼 수 있다는 점이다. 그래서 "GPU 커널 엔지니어링 입문"과 "실제 모델 연산 최적화" 사이의 다리 역할을 한다.
즉, Triton은 CUDA를 대체하는 마법이 아니라, 이미 알고 있는 GPU 개념을 더 빠르게 실험하게 해주는 도구에 가깝다. CUDA 배경 없이 보면 편리한 DSL처럼 보이지만, CUDA 배경이 있으면 memory path와 tile design을 더 빠르게 검증하는 도구처럼 읽히기 시작한다.
Phase 4. Kernel Optimization
이 시점부터는 단순히 돌아가는 커널이 아니라, 실제로 빠른 커널을 만드는 단계로 넘어간다.
중점적으로 봐야 할 것은 다음과 같다.
- kernel fusion
- tiling 전략
- tensor core 활용
- mixed precision
- memory bottleneck 분석
예를 들어 transformer block을 볼 때도 단순히 matmul 몇 개가 이어지는 구조로 보는 것이 아니라, 어느 지점에서 메모리를 다시 읽고 쓰는 비용이 커지는지, 어떤 연산을 fuse해야 의미가 있는지 판단할 수 있어야 한다.
실습은 아래 정도가 좋다.
- fused transformer block
- fast attention kernel
이 시점부터는 GPU 커널 최적화가 toy example를 넘어 실제 모델 병목과 직접 연결된다. 결국 kernel engineer가 하는 일은 "수식을 빨리 계산한다"보다 "모델 수준 bottleneck을 하드웨어 친화적으로 다시 설계한다"에 더 가깝다.
이 시리즈를 어떻게 읽으면 좋은가
이 시리즈는 "CUDA 튜토리얼 한 번 훑기" 용도가 아니다. 목표는 GPU를 사용하는 사람에서, GPU를 분석하고 손댈 수 있는 사람으로 올라가는 것이다.
그래서 읽을 때는 다음 기준을 잡는 편이 좋다.
- 코드가 돌아가는지만 보지 말고 왜 느린지까지 본다
- 연산량보다 메모리 이동이 더 큰 문제인지 항상 확인한다
- 작은 커널 예제를 실제 모델 연산과 연결해서 본다
GPU kernel engineer를 목표로 한다면 결국 중요한 것은 API 사용법보다 성능 감각이다. 이 시리즈는 그 감각을 만드는 출발점이 될 것이다.
다음 글에서는 GPU thread model, warp, block, memory hierarchy를 중심으로 GPU 아키텍처의 큰 그림부터 정리한다.