Q. GPU와 CPU를 비교하여 설명해 보시오
들어가며
인공지능, 빅데이터, 그래픽 처리 등의 분야에서는 동시에 많은 작업을 처리하는 능력이 중요하다. 이러한 병렬 연산에 최적화된 대표적인 하드웨어가 GPU(Graphics Processing Unit)이다. 원래 GPU는 그래픽 연산을 위해 설계되었지만, 최근에는 병렬 계산이 필요한 범용 분야(딥러닝, 가상화폐 채굴 등)에서 활발히 쓰인다.
- GPU와 CPU 비교
- CPU(Central Processing Unit)
- 범용 프로세서
- 코어 개수는 적지만(수 개 ~ 수십 개), 개별 코어가 강력
- 복잡한 연산과 다양한 명령 처리에 유리
- GPU(Graphics Processing Unit)
- 그래픽/병렬 연산 전용 프로세서
- 수백~수천 개의 단순 코어
- 동일한 연산을 대규모로 동시에 수행하기 탁월
- 딥러닝, 데이터 분석 등 다양한 병렬 연산 분야에서 쓰임
A.
결국, GPU는 다수의 단순 코어를 활용하여 동일한 작업을 동시에 처리하기에 특화된 장치이고, CPU는 여러 종류의 작업을 빠르게 전환하면서 유연하게 처리하기 좋은 프로세서이다.
2. CUDA의 핵심 개념
CUDA는 NVIDIA가 개발한 GPU 프로그래밍 플랫폼이다. GPU에서 병렬 연산을 쉽게 코딩할 수 있게 해주며, 다음과 같은 주요 개념을 이해해야 한다.
- 스레드(Thread)와 블록(Block)
(예: c[i] = a[i] + b[i]를 담당하는 단위)
- 그리드(Grid)
- 메모리 구조
- 호스트(Host)와 디바이스(Device)
3. Python에서 CUDA를 사용하는 방법 (Numba 활용 예시)
Python에서 CUDA를 사용하는 대표적인 라이브러리로는 Numba, PyCUDA, CuPy 등이 있다. 여기서는 Numba를 이용해 벡터(1차원 배열) 덧셈 예제를 간단히 살펴본다.
import numpy as np
from numba import cuda
# GPU에서 실행될 커널 함수
@cuda.jit
def vector_add(a, b, c):
idx = cuda.grid(1) # 스레드의 1차원 인덱스
if idx < a.size:
c[idx] = a[idx] + b[idx]
# 호스트에서 데이터 준비
N = 10**9
A = np.ones(N, dtype=np.float32)
B = np.ones(N, dtype=np.float32)
C = np.zeros(N, dtype=np.float32)
# 디바이스로 데이터 복사
dA = cuda.to_device(A)
dB = cuda.to_device(B)
dC = cuda.to_device(C)
# 블록과 그리드 크기 설정
threads_per_block = 256
blocks_per_grid = (N + (threads_per_block - 1)) // threads_per_block
# GPU 커널 함수 실행
vector_add[blocks_per_grid, threads_per_block](dA, dB, dC)
# 결과를 다시 호스트로 복사
C = dC.copy_to_host()
print("첫 10개 결과:", C[:10])
아래는 이 코드가 실제로 수행되는 과정을 그림으로 요약한 것이다.
┌─────────────────────────────┐ ┌───────────────────────────────┐
│ (1) CPU │ │ (2) GPU 메모리 │
│ A, B, C 배열 준비 │ -- cuda.to_device → │ dA, dB, dC 복사 │
│ (A, B = 1, C = 0 초기화) │ │ (A→dA, B→dB, C=0 설정) │
└─────────────────────────────┘ └──────────────────────────────┘
│ │
└───────────────┬─────────────────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ (3) GPU 커널 실행 │
│ vector_add <<<blocks, threads>>> │
│ (약 1,000,000 스레드가 각각 │
│ c[i] = a[i] + b[i] 수행) │
└───────────────────────────────────────┘
│
▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ (4) GPU 메모리 │ -- copy_to_host → │ (5) CPU │
│ dC에 결과 저장 │ │ C = dC 복사 │
│ (모든 원소 2로 채워짐) │ │ (결과: 모든 원소 2) │
└─────────────────────────────┘ └─────────────────────────────┘
│
▼
[출력: 첫 10개 결과 → [2, 2, …]]
실행해보면, 배열 A와 B의 원소를 GPU에서 병렬로 더해 C에 저장한다. 큰 배열(수억~수십억 원소)을 다룰수록 GPU의 병렬 처리 장점을 더욱 체감할 수 있다.
첫 10개 결과: [2. 2. 2. 2. 2. 2. 2. 2. 2. 2.]
4. CPU vs. GPU 실행 시간 차이
- CPU (NumPy)
- 고도로 최적화된 C 코드와 SIMD 명령어를 사용해도, 10억 원소 벡터 덧셈은 대략 100~200ms 정도 걸릴 수 있다.
- GPU (CUDA + Numba)
- 연산 자체는 병렬로 처리되어 10~20ms 안에 끝날 수 있다.
- 단, CPU ↔ GPU 사이 데이터 전송이 필요하고, 이 과정에서 30~80ms 정도가 추가될 수 있다.
- 총합으로 50~100ms 정도 소요될 수 있지만, 배열 규모가 커질수록 GPU의 강점이 두드러진다.
마무리
GPU는 대량의 단순 코어를 통해 동일한 연산을 동시에 수행하는 데 특화된 장치이고, CPU는 다양한 연산을 유연하게 처리하기 좋은 범용 프로세서이다. 실제 업무나 프로젝트에서는 CPU와 GPU를 적절히 분배해 최적의 성능을 이끌어내는 전략이 중요하다.
CUDA의 기초 개념인 스레드, 블록, 그리드, 메모리 구조 등을 이해하면 GPU를 보다 효율적으로 활용할 수 있다. 이후에는 공유 메모리 활용, 스트리밍, 파이프라이닝 등 고급 기능을 익혀 대규모 연산에서 최고의 성능을 끌어내길 바란다.
참고 자료
- NVIDIA 공식 CUDA 문서
- Numba 공식 문서
- CuPy 공식 문서
- _이것이 취업을 위한 컴퓨터 과학이다 with CS 기술 면접 – 한빛미디어_