sy/dev
Concept
16 min read

AI 모델 압축을 12살도 이해할 수 있게 설명하기 — BF16 가중치를 줄이는 방법

GLM-5.2 753B 모델을 대상으로 한 lossless weight compression 실험을 바탕으로, AI 모델의 가중치를 왜 줄일 수 있고 무엇을 아직 조심해서 봐야 하는지 쉽게 설명한다.

한 줄 요약

AI 모델 압축은 책가방에 들어 있는 똑같은 색연필을 매번 길게 쓰지 않고, 번호표로 바꿔 적는 것과 비슷하다. 원래 내용은 하나도 잃지 않으면서 더 적은 공간에 담는 것이 목표다.

이번에 본 글은 Brian Bell의 Lossless Model Compression Experiment다. GLM-5.2 753B라는 아주 큰 모델의 BF16 가중치를 분석했고, 핵심 결과는 다음처럼 정리할 수 있다.

  • GLM-5.2의 BF16 가중치 전체 크기: 약 1,403 GiB
  • K15 방식으로 계산한 압축 크기: 약 980 GiB, 약 30.168% 감소
  • 별도로 실제 복원까지 검증한 byte-split 방식: 약 24.967% 감소
  • 모든 59,509개 BF16 tensor가 bit-for-bit로 정확히 돌아오는지 검증됨
  • 다만 30.168% K15 결과는 전체 모델 규모에서 실제 파일로 직렬화하고 다시 디코딩한 결과가 아니라, 완전히 비용을 계산한 accounting 결과
  • GPU에서 더 빨라진다는 주장도 아직 조심해야 한다. dense prototype은 A40에서 BF16 GEMV 대비 0.733× 시간이 나왔지만, sparse escape correction까지 합친 end-to-end serving 결과는 아니다
💡

이 글의 핵심은 “와, 30% 줄었다!”가 아니라 “왜 큰 모델의 숫자들이 이렇게 줄어들 수 있고, 어떤 결과는 아직 미완성 주장으로 봐야 하는가?”다.

먼저 BF16이 뭔가요?

AI 모델은 아주 많은 숫자로 이루어져 있다. 이 숫자들을 **가중치(weight)**라고 부른다.

예를 들어 모델에게 이런 질문을 한다고 해보자.

"고양이는 어떤 동물이야?"

모델은 머릿속에 단어, 문장, 지식, 패턴을 전부 숫자로 저장해 둔다. 그 숫자들이 계산을 거쳐 답을 만든다.

그런데 이 숫자를 저장하는 방법이 여러 가지다.

  • FP32: 숫자 하나를 32비트로 저장
  • FP16: 숫자 하나를 16비트로 저장
  • BF16: 숫자 하나를 16비트로 저장하되, 큰 숫자와 작은 숫자를 다루는 방식이 AI 학습에 유리함

BF16은 16비트짜리 숫자다. 아주 단순하게 보면 이렇게 나눌 수 있다.

BF16 숫자 하나 = 부호 + 지수 + 꼬리 숫자

조금 더 정확히 말하면 다음과 비슷하다.

sign: 이 숫자가 양수인지 음수인지
exponent: 숫자의 대략적인 크기
mantissa: 더 자세한 값

초등학생 버전으로 비유하면 이렇다.

숫자 = 방향 + 몇 층짜리 건물인지 + 방 번호
  • 방향: 양수/음수
  • 몇 층짜리 건물인지: 숫자의 크기 범위
  • 방 번호: 그 안에서의 자세한 위치

왜 AI 모델 숫자는 압축될 수 있을까?

일반적인 압축의 핵심은 반복되는 것을 짧게 쓰는 것이다.

예를 들어 친구에게 이런 메시지를 보낸다고 하자.

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

이걸 그대로 쓰면 길다. 하지만 이렇게 쓰면 짧다.

ㅋㅋ × 10

뜻은 같다. 더 짧게 썼을 뿐이다.

AI 모델의 BF16 숫자에서도 비슷한 일이 생긴다. 특히 exponent, 즉 숫자의 대략적인 크기를 나타내는 부분이 생각보다 많이 반복된다.

모델 안에는 수천억 개의 숫자가 있지만, 그 숫자들의 “크기 구간”은 아무렇게나 흩어져 있지 않다. 학습이 끝난 모델에서는 자주 나오는 sign/exponent 조합이 몇 개로 몰리는 경향이 있다.

Brian Bell의 실험은 이 점을 이용한다.

K15 아이디어: 자주 나오는 모양에는 짧은 번호를 붙인다

원래 BF16에서는 sign과 exponent 쪽 정보를 비교적 길게 저장한다. 그런데 자주 나오는 조합이 15개 정도로 몰린다면, 매번 긴 값을 저장하지 않고 짧은 번호로 바꿔 적을 수 있다.

비유해 보자.

원래 방식:
딸기맛 아이스크림
초코맛 아이스크림
바닐라맛 아이스크림
딸기맛 아이스크림
딸기맛 아이스크림
초코맛 아이스크림

이걸 이렇게 바꾸는 것이다.

1 = 딸기맛 아이스크림
2 = 초코맛 아이스크림
3 = 바닐라맛 아이스크림
 
1, 2, 3, 1, 1, 2

자주 나오는 이름을 매번 길게 쓰지 않고 번호로 바꾼다. 대신 번호표 사전은 따로 저장해야 한다.

K15 방식은 대략 이런 구조다.

자주 나오는 sign+exponent 조합 15개 -> 4비트 코드로 저장
드문 조합 -> escape stream에 정확히 저장
mantissa -> 원래대로 저장

여기서 중요한 점은 드문 값도 버리지 않는다는 것이다. 드문 값은 escape stream이라는 별도 통로에 정확히 저장한다.

그래서 목표는 lossy compression이 아니라 lossless compression이다.

Lossless와 lossy는 뭐가 다를까?

압축에는 크게 두 종류가 있다.

1. Lossy compression: 조금 잃어버려도 작게 만들기

사진을 JPEG로 저장하면 용량은 줄지만, 아주 자세히 보면 원본과 조금 다를 수 있다. 음악을 MP3로 줄일 때도 비슷하다.

이건 “사람이 보기에는 거의 티 안 나니까 조금 버리자”에 가깝다.

2. Lossless compression: 하나도 잃지 않고 작게 만들기

ZIP 파일은 압축을 풀면 원본 파일과 정확히 같아야 한다. 코드 파일을 ZIP으로 묶었는데 글자 하나가 바뀌면 큰일 난다.

AI 모델의 가중치도 마찬가지다. lossless라면 압축했다가 다시 풀었을 때 원래 숫자와 비트 단위로 완전히 같아야 한다.

이번 실험에서 byte-split 방식은 모든 59,509개 BF16 tensor에 대해 bit-for-bit round-trip을 통과했다. 즉 “압축했다가 다시 풀어도 원래와 정확히 같다”는 검증을 한 것이다.

그런데 왜 30%와 25%가 따로 나오나요?

여기가 가장 헷갈리기 쉬운 부분이다.

원문은 두 가지 결과를 분리해서 말한다.

결과 A. K15 charged-format accounting: 약 30.168% 감소

K15 방식으로 전체 비용을 계산했을 때, GLM-5.2의 BF16 가중치가 약 1,403 GiB에서 약 980 GiB로 줄어드는 것으로 계산됐다.

이 결과는 모든 side cost까지 포함한 bit accounting이다. 쉽게 말하면 “이런 방식으로 담으면 몇 비트가 필요한지 전체 계산표를 만든 것”에 가깝다.

하지만 원문도 명확히 말한다. 이 K15 layout은 GLM-5.2 전체 규모에서 독립적으로 직렬화하고 다시 디코딩한 결과가 아니다.

결과 B. Byte-split exact inverse: 약 24.967% 감소

별도의 byte-split 표현은 실제로 복원 검증을 했다. 모든 BF16 tensor가 bit-for-bit로 원본과 같게 돌아왔다.

이 결과는 약 24.967% 감소다.

즉 이렇게 기억하면 된다.

30.168%: K15 방식의 전체 비용 계산 결과
24.967%: 실제 round-trip 복원까지 검증한 byte-split 결과
⚠️

두 숫자를 섞어서 “30% 줄고, 정확히 복원되고, 실제 서빙도 빨라졌다”라고 말하면 과장이다. 원문은 이 세 가지를 서로 다른 evidence class로 분리한다.

실제로 모델이 더 빨라질까?

압축된 모델은 저장 공간을 덜 먹는다. 그런데 추론 속도도 빨라질까?

가능성은 있다. 큰 모델은 계산도 중요하지만, GPU 메모리에서 가중치를 읽어오는 비용도 크다. 가중치가 작아지면 메모리에서 읽어야 할 양이 줄어들 수 있다.

비유하면 이렇다.

책상 위 문제를 푸는 시간 = 문제를 읽는 시간 + 계산하는 시간

문제지가 너무 두꺼우면 읽고 넘기는 시간이 오래 걸린다. 문제지가 더 얇아지면 계산을 시작하기까지 빨라질 수 있다.

원문에는 A40 GPU에서 dense 12-bit prototype이 BF16 GEMV 시간의 0.733×로 측정됐다는 결과가 나온다. 즉 특정 microbenchmark에서는 더 빠른 경로가 보였다.

하지만 여기에도 단서가 있다.

  • sparse escape correction은 따로 검증됐지만 timed kernel에 합쳐지지 않았다
  • 전체 모델을 실제 서비스처럼 돌린 end-to-end 결과는 아니다
  • 따라서 “lossless 압축 모델이 실제 서빙에서 항상 빨라진다”는 결론은 아직 이르다

이건 연구에서 꽤 중요한 태도다. 좋은 아이디어와 좋은 prototype이 있어도, 실제 serving system에 들어가면 cache, kernel fusion, batch size, tensor shape, escape 처리 비용 같은 현실 문제가 따라온다.

이 실험이 재미있는 이유

나는 이 글에서 세 가지가 특히 좋았다.

첫째, 큰 모델의 가중치가 완전히 무작위가 아니라는 점을 잘 보여준다. 학습된 모델의 숫자들은 아무렇게나 흩어진 쓰레기 값이 아니다. 반복되는 구조가 있고, 그 구조를 잘 이용하면 저장 방식 자체를 바꿀 수 있다.

둘째, lossless라는 조건이 실무적으로 중요하다. 모델을 작게 만들기 위해 값을 바꾸면 성능이 달라질 수 있다. 하지만 lossless라면 적어도 “압축 때문에 모델의 답이 달라지는가?”라는 걱정은 줄어든다.

셋째, 주장 범위를 꽤 조심스럽게 나눴다. 원문은 30% accounting, 25% exact round-trip, dense-path timing을 하나의 거대한 성공담으로 합치지 않는다. 각각 무엇을 검증했고 무엇을 아직 검증하지 않았는지 구분한다.

AI 시스템 글에서 이 구분은 매우 중요하다.

12살 버전으로 다시 정리

아주 큰 AI 모델은 숫자 카드가 엄청나게 많은 카드 상자라고 생각하면 된다.

그런데 카드를 자세히 보니 이런 일이 있었다.

빨간 큰 카드
파란 작은 카드
빨간 큰 카드
빨간 큰 카드
노란 중간 카드
파란 작은 카드

자주 나오는 카드 모양이 반복된다. 그러면 매번 긴 이름을 쓰지 않고 이렇게 바꿀 수 있다.

1 = 빨간 큰 카드
2 = 파란 작은 카드
3 = 노란 중간 카드
 
1, 2, 1, 1, 3, 2

드문 카드는 따로 정확히 적어 둔다.

그래서 상자는 작아진다. 그리고 다시 풀면 원래 카드와 똑같아야 한다.

이번 실험은 “AI 모델 숫자 카드에도 이런 반복이 꽤 많다”는 것을 큰 모델에서 보여준 사례다. 다만 아직 완성된 제품처럼 “30% 작고, 완전히 복원되고, 실제 서비스도 빨라졌다”까지 한 번에 증명한 것은 아니다.

실무적으로 보면 무엇을 기대할 수 있을까?

이런 연구가 더 성숙해지면 다음 방향으로 이어질 수 있다.

  • 큰 모델 checkpoint 저장 비용 감소
  • 모델 다운로드와 배포 시간 감소
  • GPU memory bandwidth 부담 감소
  • inference runtime에서 직접 복원하며 계산하는 kernel 최적화
  • quantization과 다른 방식의 compression을 조합하는 새로운 serving stack

특히 agent나 RAG 시스템처럼 여러 모델을 운영하는 환경에서는 모델 저장, 배포, warm-up 비용도 무시하기 어렵다. 모델이 점점 커질수록 “가중치를 어떻게 표현할 것인가”는 단순한 파일 포맷 문제가 아니라 serving architecture 문제가 된다.

마무리

이 글을 한 문장으로 줄이면 이렇다.

AI 모델의 숫자에는 반복되는 패턴이 있고, 그 패턴을 잘 이용하면 원본을 잃지 않고도 큰 모델을 꽤 작게 저장할 수 있다.

하지만 좋은 연구일수록 숫자를 조심해서 읽어야 한다.

  • 30.168%는 K15 charged-format accounting 결과
  • 24.967%는 실제 bit-exact round-trip이 검증된 byte-split 결과
  • 0.733× timing은 dense prototype microbenchmark 결과
  • end-to-end lossless serving system은 아직 open work

그래서 이 실험은 “이미 끝난 제품”이라기보다, 큰 모델을 더 싸고 빠르게 다루기 위한 중요한 부품 후보로 보는 게 맞다.

참고 자료

Comments