FLOPs와 Bytes 계산하기

performancemeasurement

성능 분석에서는 먼저 두 양을 계산한다.

FLOPs: 얼마나 많이 계산하는가
Bytes: 얼마나 많은 데이터를 움직이는가

이 둘을 같은 연산에 대해 계산해야 compute-bound인지 memory-bound인지 판단할 수 있다.

FLOPs

FLOP은 floating-point operation의 약자다. 부동소수점 덧셈, 곱셈 같은 연산 하나를 센다.

행렬 곱셈:

A[m,k]×B[k,n]=C[m,n]A[m,k] \times B[k,n] = C[m,n]

에서는 출력 원소가 mn개이고, 각 출력 원소를 만들 때 길이 k의 내적을 한다.

multiply-add를 2 FLOPs로 세면:

FLOPs2mnk\text{FLOPs} \approx 2mnk

Bytes

Bytes는 메모리에서 이동한 데이터의 양이다.

원소 개수를 bytes로 바꾸려면 dtype의 크기를 곱한다.

FP32: 4 bytes
FP16/BF16: 2 bytes
INT8: 1 byte

원소 이동량이 E이고 원소 하나가 s bytes라면:

Bytes=sE\text{Bytes} = sE

Algorithmic bytes와 actual bytes

bytes를 셀 때는 두 관점을 구분해야 한다.

algorithmic bytes:
  알고리즘이 이상적으로 한 번씩만 읽고 쓴다고 보는 최소 이동량

actual bytes:
  실제 구현이 메모리 계층 사이에서 움직인 데이터량

행렬 곱셈의 이상적인 원소 이동량 하한은:

mk+kn+mnmk + kn + mn

하지만 naive 구현은 같은 A, B 원소를 여러 번 다시 읽을 수 있다. 이때 실제 입력 읽기량은 훨씬 커진다.

그래서 block-matrix-multiplication이 중요하다. 블록 행렬 연산은 actual bytes를 algorithmic bytes에 더 가깝게 만든다.

확인

  • BF16 원소 1,000개를 읽으면 몇 bytes인가?
  • 행렬곱 A[m,k] x B[k,n]의 FLOPs는 왜 2mnk에 가까운가?
  • algorithmic bytes와 actual bytes는 왜 다를 수 있는가?