TECH 으로 돌아가기
TECH HACKER NEWS 오늘 7분 읽기 41 READS

3진수 다섯 자리를 1바이트에 — 1.58비트 LLM 시대의 비트 패킹 기술

3진수 다섯 자리를 1바이트에 — 1.58비트 LLM 시대의 비트 패킹 기술

요즘 AI 모델 경량화 이야기에서 '1.58비트'라는 묘한 숫자가 자주 보여요. 마이크로소프트 리서치가 발표한 BitNet b1.58 계열 모델이 대표적인데요, 이 모델들은 가중치를 -1, 0, +1 딱 세 가지 값으로만 표현하거든요. 값이 세 개니까 2진수가 아니라 3진수(ternary) 체계예요. 그런데 우리가 쓰는 컴퓨터는 철저하게 2진수, 그것도 8비트 바이트 단위로 돌아가죠. 그러니 자연스럽게 이런 질문이 생겨요. '3진수 데이터를 8비트 바이트에 어떻게 낭비 없이 담을까?' llama.cpp에 양자화 포맷을 기여해 온 개발자 compilade가 바로 이 문제를 깊게 파고든 글을 올렸는데, 저수준 최적화의 재미가 가득해서 소개해 드릴게요.

왜 하필 1.58비트일까요

먼저 숫자의 정체부터 풀어볼게요. 세 가지 값 중 하나를 구분하는 데 필요한 정보량은 log₂3 ≈ 1.585비트예요. 이게 뭐냐면, 동전 던지기(2가지 결과)가 정확히 1비트의 정보를 주듯이, 세 갈래 갈림길에서 하나를 고르는 선택은 약 1.58비트어치 정보라는 뜻이거든요. 3진수 한 자리는 비트(bit)에 빗대서 '트리트(trit)'라고 불러요.

가장 게으른 저장 방법은 트리트 하나를 2비트에 담는 거예요. 2비트로는 네 가지 상태를 표현할 수 있는데 셋만 쓰니까, 공간의 20% 이상을 그냥 버리는 셈이죠. 파라미터가 수십억 개인 LLM에서는 이 낭비가 기가바이트 단위로 불어나요. 모델을 폰이나 노트북에 올리려는 입장에서는 뼈아픈 손실이에요.

핵심 아이디어: 3의 5제곱은 243

여기서 예쁜 수학이 등장해요. 3⁵ = 243인데, 이 값이 2⁸ = 256보다 살짝 작거든요. 그러니까 트리트 5개를 한 묶음으로 보면 경우의 수가 243가지라서, 1바이트 안에 딱 들어가요. 트리트 하나당 8÷5 = 1.6비트를 쓰는 셈이니 이론적 한계인 1.585비트에 거의 붙어 있죠. 낭비율이 20%대에서 1% 아래로 뚝 떨어지는 거예요.

진짜 문제는 저장이 아니라 꺼내 쓸 때예요. 진법 변환에서 자릿수를 뽑으려면 보통 나눗셈과 나머지 연산을 반복해야 하는데, 나눗셈은 CPU에서 꽤 비싼 연산이고 SIMD(하나의 명령으로 여러 데이터를 동시에 처리하는 벡터 연산)로 돌리기도 까다롭거든요. 추론할 때마다 가중치 수십억 개를 풀어야 하는 LLM 입장에서는 언패킹 속도가 곧 추론 속도예요.

그래서 이 글의 트릭이 빛나요. 바이트에 담긴 값을 정수가 아니라 0과 1 사이의 소수처럼 바라보는 거예요. 트리트 5개를 소수점 아래의 3진 자릿수라고 생각하면, 이 값에 3을 곱했을 때 가장 높은 자릿수가 소수점 위로 넘어와요. 8비트 곱셈 결과에서 상위 바이트만 읽으면 그게 바로 다음 트리트인 거죠. 남은 하위 바이트로 같은 작업을 반복하면 자릿수가 하나씩 튀어나오고요. 비싼 나눗셈 없이 곱셈과 시프트만으로 해결되는 데다, 이런 연산은 SIMD로 병렬화하기에도 아주 좋아요.

이미 llama.cpp에 들어가 있어요

이 아이디어는 이론으로 끝난 게 아니라 llama.cpp의 TQ1_0이라는 양자화 타입으로 구현돼 있어요. 글쓴이가 직접 기여한 포맷인데요, 블록마다 스케일 같은 부가 정보가 붙어서 실제로는 트리트당 1.6비트보다 조금 더 쓰지만, 2비트 방식(TQ2_0)보다는 확실히 작아요. 재미있는 건 트레이드오프예요. 2비트 패킹은 공간을 더 쓰는 대신 시프트와 마스크만으로 풀 수 있어서 빠르고, 5개 묶음 패킹은 더 작은 대신 언패킹 연산이 조금 더 들어가거든요. 메모리 대역폭이 병목인 환경에서는 오히려 작은 쪽이 빨라질 수도 있어서, 상황에 따라 답이 달라지는 문제죠.

업계 흐름에서 보면

극단적 양자화는 지금 LLM 경량화의 최전선이에요. GPTQ나 AWQ 같은 4비트 양자화가 사실상 표준이 됐고 그 아래로 내려가면 품질이 무너진다는 게 통념이었는데, BitNet처럼 아예 처음부터 3진 가중치로 학습하는 방식이 그 벽을 흔들고 있거든요. 마이크로소프트는 bitnet.cpp라는 전용 추론 프레임워크도 공개했고요. 3진 가중치는 행렬 곱셈을 덧셈과 뺄셈으로 바꿔버릴 수 있어서, 전용 하드웨어에서 전력 효율이 크게 좋아질 거라는 기대도 있어요.

우리에게 주는 시사점

당장 서비스에 3진 모델을 쓸 일은 없더라도, 비트 패킹 감각은 배워둘 가치가 충분해요. 네트워크 프로토콜 설계, 컬럼형 DB의 압축, 비트맵 인덱스, 게임의 상태 직렬화까지, '제한된 공간에 정보를 최대한 담고 빠르게 꺼내는' 문제는 어디에나 있거든요. 특히 나눗셈을 곱셈으로 바꾸는 고정소수점 트릭은 임베디드나 고성능 코드에서 두고두고 써먹는 고전 기법이에요. 온디바이스 AI에 관심 있는 분이라면 llama.cpp의 양자화 코드를 직접 읽어보는 것도 좋은 공부가 될 거예요.

정리하면, 3진수 다섯 자리가 1바이트에 딱 들어간다는 수학적 우연과 나눗셈을 곱셈으로 바꾸는 오래된 트릭이 만나서, 1.58비트 LLM의 실용화를 한 걸음 앞당겼다는 이야기예요. 여러분은 실무에서 비트 패킹으로 재미를 본 경험이 있나요? 아니면 극단적으로 양자화된 모델을 실제로 돌려보신 분 계신가요?


🔗 출처: Hacker News

SOURCE · HACKER NEWS
원문 전체 보기 → https://compilade.net/blog/ternary-packing
SHARE
처리 중...