인공지능(특히 신경망)의 계산 단위 FLOP과 MAC
인공지능의 계산량을 어떻게 수치화할 것인가? 이는 인공지능 모델에 입력하는 데이터의 크기나 모델 내에서 계산되는 방식에 따라 다를 것이다. 정확한 수치로 나타내긴 어렵겠지만 그래도 상대적인 계산량을 가늠하기 위한 표현법들이 있다. 마치 전통적인 컴퓨팅 알고리즘에서 사용되던 빅오나 세타 등의 노테이션처럼 말이다. (개념은 전혀 다르다!)
대표적으론 FLOP과 MAC이 있다.
FLOP
FLOP은 FLoating-point OPerations (부동소수점 연산)의 약자이다. 인공지능의 가중치들은 대부분 부동소수점(대표적으로 FP32)으로 되어있다. 그리고 인공지능이라는 게 결국엔 숫자 입력받아, 모델 안에 있는 숫자들에 곱하고 더해서 숫자를 결과로 주는 연산이기 때문에 부동소수점 곱, 덧셈 등의 횟수로 표현이 가능하다. 기존의 알고리즘이나 로직처럼 조건문(if)이나 반복문(for, while)같은 게 있다면 복잡해지겠지만 대부분의 인공지능 모델은 그런 것이 없기에 FLOP으로 표현하기 용이하다.
예를 들어 어떤 논문에서 "우리 모델은 200 GFLOPs가 필요하다"라고 표현하는 것을 볼 수 있다.
MAC
MAC은 Multiply-ACcumulate (곱셈-누산)의 약자이다. 즉 어떤 숫자들을 한번 곱하고 한번 더하는 경우(ex. A*B+C)가 1MAC이다. 이런 정의를 사용하는 이유는 인공지능이 대부분 y=ax+b와 같이 weight를 곱하고 bias를 더하는 행위를 반복하기 때문이다. 물론 그 사이 사이에 곱셈-누산이 아닌 다른 자잘한 연산들도 있지만 이런 건 거대한 모델에서 큰 영향을 주는게 아니라고 무시해버린다.
정확하진 않지만 대략 2 FLOPs = 1 MAC으로 본다. 그래서 연구자들은 FLOP단위가 나오든 MAC단위가 나오든 그냥 환산해서 2를 나누거나 곱해 이해하는 경우가 많다. 애초에 이런 단위들이 인공지능의 계산량을 정확히 표현하긴 힘들고 대략적인, 상대적인 계산량으로 봐야하기 때문이다.
예를 들어 어떤 논문에서 "우리 모델은 200 GFLOPs가 필요하다"라고 표현한다면, MACs가 익숙한 사람은 "100 GMACs구나"라고 이해해버려도 큰 문제는 없다.
Example
예시로 우리에게 익숙한 Transformer 아키텍처를 보자. 그 중 셀프 어센션 부분은 대략 아래와 같은데, 계산량 측면에서 가장 부담이 되는 건 Linear와 QKV 어텐션 부분이다. Dropout이나 LayerNorm 등은 계산량이 없는 건 아니지만 주요 계산량들에 비해 너무 미미하므로 생략되는 경우가 많다.

언어 모델에선 계산량을 표현하기 위해 아래 기호들이 사용된다.
B: Batch size (한 번에 처리하는 문장 수)
- e.x. 한 번의 학습 step에서 16개 문장
L :Sequence length (문장 길이, 토큰 수)
- e.x. 문장당 128 token
E: Embedding dimension (모델 내부 벡터 차원)
- e.x. GPT-2 small이면 768, BERT base면 768
예를 들어 Linear Layer에서 입력 텐서의 사이즈는 [L, E]일테고, 가중치가 [E, E]라면 출력은 [L, E]가 된다.
이 때 배치 크기가 B이므로 [L, E] * [E, E] 연산은이 B번 일어나게 되기 때문에 결국 B x L x E2이 연산량이 된다. 왜 그렇게 되는지는 간단히 B=2, L=3, E=4로 행렬을 그려놓고 곱셈을 해 보면 이해할 수 있다. 공식으로는 아래 행렬 곱 연산 공식을 이용할 수도 있다.
[M,N] x [N,P] = [M,P]
이 때 연산량은
M x N x P
Attention Weight QKT에 대해선
Q는 [L, E]이고 KT는 [E, L]로 전치된 형태이다. 이를 곱하면 [L, L]이 된다. 연산량은 B x L2 x E 이다.
QKT에 Attention Value를 적용하는 계산은 어떨까
우리가 앞서 계산한 Attention Weight가 [L, L]이였다. Value는 [L, E] 모양이다. 즉 연산량은 또 한번 B x L2 x E 이다.
셀프 어탠션 블록엔 Linear Layer가 4군데 있으므로 총 4 x B x L x E2, 그리고 Attention Weight 계산 (QKᵀ) 한번, Attention Value 적용 (QKᵀ)V 한번이 있으므로 총 4BLE2 + 2BL2E가 된다.
그리고 여기서 나오지 않은 Feed Forward는 계산 과정은 생략했지만 8BLE2인데, 이것까지 더하면 트랜스포머 블록 전체의 계산량은 12BLE2 + 2BL2E가 된다.
이렇게 트랜스포머 블록이 12개인 LLM이라면 여기에 12를 곱해주면 된다. (자잘한 다른 레이어들은 일단 생략)
그리고 만약 우리가 트랜스포머 블록을 하나 뺐다거나, 중간에 Linear Layer 제거 했다거나, 프루닝을 해서 1/2 분량의 Sparse Matrix를 만들어서 처리했다거나 하면 저 계산량에서 일부를 변경할 수 있다. 그렇게 계산량이 개선된 모델을 발표할 때는 계산량을 MACs로 써주면 기존의 다른 모델과 비교가 가능하다.
그럼 모델별로 비교를 하면 어떻게 될까? 예를들어 정석적인 트랜스포머 블록으로 구성된 GPT-2를 기준으로 보자면 아래와 같다.
| 모델명 | 레이어 | 임베딩 | 파라미터 | 토큰 |
| GPT-2 Small | 12 | 768 | 117M | 1024 |
| GPT-2 Medium | 24 | 1024 | 345M | 1024 |
| GPT-2 Large | 36 | 1280 | 774M | 1024 |
| GPT-2 XL | 48 | 1600 | 1.5B | 1024 |
GPT-2 Small (117M)을 기준으로 수치까지 계산해보면
C=12×(12×1×1024×7682+2×1×10242×768)
약 1.1 x 10^11 MACs로 계산된다.
| 모델명 | 레이어 | 임베딩 | 근사 MACs |
| GPT-2 Small | 12 | 768 | 1.1 × 10¹¹ |
| GPT-2 Medium | 24 | 1024 | ≈ 3.1 × 10¹¹ |
| GPT-2 Large | 36 | 1280 | ≈ 7.5 × 10¹¹ |
| GPT-2 XL | 48 | 1600 | ≈ 1.47 × 10¹² |
이를 통해 모델별로 계산량의 차이가 얼마나 되는지 비교를 해볼 수 있다. GPT-2만 가지고 계산했을 때는 MACs이 파라미터의 수와 거의 정비례하는 것을 볼 수 있는데, 그건 GPT-2가 동일한 구조를 가지고 사이즈만 변형된 여러 모델들의 집합이기 때문이다.
하지만 LLaMA와 나열하고 파라미터 수 대비로 나누어 보면 차이가 조금은 드러난다.
| 모델 | MACs (@L = 1024) | 파라미터 |
MACs/Param
|
| GPT-2 Small | 1.1 × 10¹¹ | 124 M | 887 |
| GPT-2 Medium | 3.1 × 10¹¹ | 355 M | 873 |
| GPT-2 Large | 7.5 × 10¹¹ | 774 M | 969 |
| GPT-2 XL | 1.47 × 10¹² | 1.5 B | 980 |
| LLaMA 0.5B | 5.0 × 10¹¹ | 0.5 B | 1000 |
| LLaMA 1B | 1.2 × 10¹² | 1.0 B | 1200 |
| LLaMA 3B | 3.5 × 10¹² | 3.0 B | 1167 |
즉 모델이 커짐에 따라서 연산량이 완전 정비례 하다기 보다는, 파라미터 수 대비 더 빠르게 커지는 경향을 보인다. 그리고 GPT-2보단 LLaMA가 더 무거운 연산을 한다는 것을 알 수 있다.
이런 모델들은 모두 기본적인 형태로 공개된 구조를 그대로 차용해서 계산을 한 것이다. 인공지능 효율에 대해 연구를 하는 사람들은 이를 기준으로, 어떤 효율화 기법을 적용하는지에 따라서, 연산량을 30%나 감소를 시켰는데 벤치마크 성능은 2%밖에 줄지 않았다는 식으로 효과가 제시된다. (결국에 트레이드 오프가 있을 수 밖에 없다)
부디 이 글이 인공지능 효율화와 관련된 기사나 논문 등을 볼 때 참고가 되길 바란다.