C.W.K.
Stream
Lesson 03 of 04 · published

AXPY, GEMV, GEMM — 단 세 op

~12 min · linalg, blas, axpy, gemv, gemm

Level 0Beginner
0 XP0/38 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

BLAS Level 1, 2, 3 — 그리고 어느 게 GPU 밥값 하는가

벡터랑 행렬 있으면 BLAS가 모든 걸 정리하는 op은 셋뿐:

OpLevel시그니처커널 이름전형적 용도
AXPYBLAS-1y ← α·x + ySAXPY, VectorAddBias add, residual skip
GEMVBLAS-2y ← A·x + yMatVec, DenseInferenceSingle-token autoregressive inference
GEMMBLAS-3C ← α·A·B + β·Cmatmul, mma, wmmaSelf-attention, batched inference, training

왜 BLAS Level 3가 1, 2 보다 훨씬 중요한가? Arithmetic intensity. AXPY는 byte당 ~1 FLOP — 모든 연산이 fresh DRAM trip 요구. GEMV도 비슷. 반면 GEMM은 load한 element 각각을 O(k)번 써서 GPU가 부수도록 만들어진 FLOPs/byte 비율을 가져.

Roofline 어림 룰:

  • 낮은 FLOPs/byte (< 4) — bandwidth-bound. 커널이 DRAM 기다림. AXPY, GEMV, element-wise op이 여기 살아.
  • 높은 FLOPs/byte (> 8) — compute-bound. ALU / Tensor Core 포화. Tiled GEMM이 여기 살아.

그래서 7B 모델의 single-token decode (GEMV 모양: activation × weight)이 RTX 4090에서 50 tokens/s, 64 토큰 batch (GEMM 모양)는 800 tokens/s. 수학은 같고, FLOPs/byte 비율이 바뀐 거야.

Code

세 op, NumPy로 나란히·python
import numpy as np

# AXPY — vector scale + add (BLAS-1)
alpha = 0.5
x = np.random.randn(1_000_000)
y = np.random.randn(1_000_000)
y = alpha * x + y          # 원소당 1 FLOP ≈ 1 FLOP/byte

# GEMV — 행렬 × 벡터 (BLAS-2)
A = np.random.randn(4096, 4096)
x = np.random.randn(4096)
y = A @ x                  # ~ 2N² FLOP / ~N² byte ≈ 2 FLOPs/byte

# GEMM — 행렬 × 행렬 (BLAS-3)
A = np.random.randn(4096, 4096)
B = np.random.randn(4096, 4096)
C = A @ B                  # ~ 2N³ FLOP / ~N² byte ≈ N FLOPs/byte
Arithmetic intensity 계산기 (back-of-envelope)·python
def intensity(flops, bytes_):
    return flops / bytes_

# 4096 × 4096 GEMM, FP32 (원소당 4 byte)
N = 4096
flops = 2 * N**3
bytes_ = 3 * N * N * 4         # A, B, C 각 N²
print(f'GEMM intensity: {intensity(flops, bytes_):.0f} FLOPs/byte')
# ~ 1365  → 매우 compute-bound, GPU가 사랑

# 같은 모양 vector add
flops = N * N
bytes_ = 3 * N * N * 4
print(f'AXPY intensity: {intensity(flops, bytes_):.2f} FLOPs/byte')
# ~ 0.08 → 심각하게 bandwidth-bound

External links

Exercise

위 intensity 계산기를 1024×1024 / 8192×8192 GEMM에 돌려봐. intensity가 N에 선형으로 증가하는 거 확인 (compute는 N³, byte는 N²). 큰 GEMM이 작은 거보다 compute-bound 만들기 쉬운 대수적 이유 — 그리고 작은 행렬을 'good' 사이즈로 padding 하는 게 zero work 늘려도 가끔 이기는 이유.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.