30B 모델을 24GB MacBook에서 돌린다는 말은 여전히 이상하게 들립니다. 4비트로 줄여도 가중치만 16GB 안팎이고, KV 캐시와 런타임 버퍼를 더하면 24GB도 빠듯합니다. Nota AI가 공개한 1.58비트 모델은 이 계산을 바꿉니다. BF16 기준 약 60GB인 Nemotron 3.5 Lightning 30B-A3B를 9.6GB로 줄였고, 7개 생성형 벤치마크 평균의 89.4%를 회복했습니다.
하지만 이 글의 핵심은 “1.58비트면 작아진다”가 아닙니다. Nota AI 블로그가 직접 밝히듯, BF16 모델을 ternary로 바로 변환하면 GSM8K와 HumanEval이 0.00이 됩니다. 파일 크기를 줄이는 일과 모델의 능력을 유지하는 일은 별개의 문제입니다. 이 글은 그 간극을 메우는 회복 절차를 중심으로 읽습니다.
1.58비트는 정보량이고, 파일 크기는 아니다
Ternary 양자화는 각 가중치를 -1, 0, +1 세 값 중 하나로 표현합니다. 세 값을 구분하는 데 필요한 이론적 최소 정보량이 log₂3 ≈ 1.585비트라서 1.58비트라고 부릅니다. 디스크에 저장되는 파일이 정확히 1.58비트라는 뜻은 아닙니다. 실제 파일에는 scale과 컨테이너 메타데이터가 함께 들어갑니다.
Nota AI가 쓴 절차는 세 단계입니다. 그룹의 평균 절댓값 α를 구하고, 임계값 τ = α/2를 정합니다. |w| > τ인 가중치는 부호에 따라 +1 또는 -1, |w| ≤ τ인 가중치는 0이 됩니다. 마지막으로 0이 아닌 코드의 평균 절댓값 s를 구해 ŵ = s × q로 복원합니다.
α = mean(|w|)
τ = α / 2
q = +1 if w > τ
0 if |w| ≤ τ
-1 if w < −τ
s = mean(|w|) over q ≠ 0
ŵ = s × q
예시 그룹 8개에서 α = 0.39, τ = 0.195, s = 0.58이 나옵니다. 0.90은 +1, -0.30은 -1, 0.05는 0이 됩니다. 복원값은 +0.58, -0.58, 0입니다. 중요한 것은 0이 되는 가중치의 비율입니다. 너무 적으면 0 근처의 작은 값이 ±1로 커지며 오차가 늘고, 너무 많으면 정보가 사라져 표현력이 떨어집니다. τ가 이 비율을 결정합니다.
바로 변환하면 0점이 되는 이유
Nota AI는 이미 학습된 BF16 체크포인트를 재사용하기 위해 PTQ(Post-Training Quantization)를 택했습니다. BitNet b1.58처럼 처음부터 ternary로 사전학습하는 QAT와 다른 경로입니다. PTQ는 절차 자체는 문제없이 끝났지만, 내부 평가에서 GSM8K 95.00 → 0.00, HumanEval 96.34 → 0.00, IFEval-ko 89.46 → 10.36이 나왔습니다.
원인은 누적되는 반올림 오차입니다. 각 가중치가 복원되면서 작은 오차가 생기고, 수십 개 층을 거치며 그 오차가 다음 토큰 확률에 영향을 줍니다. 토큰을 하나씩 생성하는 벤치마크에서는 이 차이가 거의 매번 틀린 답으로 이어집니다. 2비트 이하 극단적 저비트 양자화에서 흔한 실패 모드입니다.
회복 1: on-policy distillation과 STE
첫 번째 회복은 distillation입니다. 일반적인 off-policy distillation은 교사가 미리 만든 답을 학생이 따라 하게 합니다. 하지만 ternary 학생 모델의 출력 분포는 양자화 직후 크게 어긋나 있고, 교사의 문장만 보는 학습으로는 학생이 실제로 내는 오류가 학습 신호에 잘 드러나지 않습니다. Nota AI는 on-policy distillation을 함께 썼습니다. 학생이 직접 생성한 문맥에서 교사가 다음 토큰 분포를 계산하고, 학생은 그 분포와 자신의 분포 차이를 학습합니다.
양자화된 가중치는 미분할 수 없습니다. 이때 STE(Straight-Through Estimator)를 씁니다. 순전파에서는 ternary 코드를 그대로 쓰고, 역전파에서는 양자화 함수를 항등 함수처럼 취급해 그래디언트를 latent weight에 전달합니다. latent weight는 ternary 코드 뒤에 남아 있는 full-precision 값입니다. 작은 업데이트가 쌓이다 임계값을 넘으면 코드가 바뀝니다.
한 epoch 동안 실제로 코드가 바뀐 가중치는 전체의 약 5~7%였습니다. 이는 회복이 “새 지식을 넣는 일”이라기보다 “양자화가 바꿔 놓은 소수의 코드를 원래 출력에 맞게 고치는 일”에 가깝다는 뜻입니다.
회복 2: boundary masking
Distillation과 STE만으로도 처음 1~2 epoch에서 성능이 크게 올랐습니다. GSM8K는 82.56 → 87.57, HumanEval은 72.56 → 80.49, IFEval-ko는 61.79 → 68.39가 됐습니다. 그런데 3 epoch로 늘리자 GSM8K가 85.90, IFEval-ko가 64.82로 다시 내려갔습니다. 다른 모델에서도 같은 패턴이 나왔습니다.
Nota AI의 해석은 STE가 모든 latent weight에 신호를 보내면서, 바뀔 필요가 없는 값까지 업데이트해 노이즈로 코드를 뒤집는다는 것입니다. 그래서 학습 범위를 좁혔습니다. PTQ 초기값이 τ의 ±10% 안에 있는 가중치, 전체의 약 5.9%만 학습하고 나머지는 동결했습니다. 임계값 근처에 있는 값만 작은 업데이트로 코드가 바뀔 수 있고, 멀리 있는 값은 학습해도 코드가 거의 바뀌지 않으면서 노이즈만 더하기 때문입니다. 이 방법을 boundary masking이라고 부릅니다.
| 단계 | GSM8K | HumanEval | IFEval-ko |
|---|---|---|---|
| PTQ 직후 | 0.00 | 0.00 | 10.36 |
| 1 epoch | 82.56 | 72.56 | 61.79 |
| 2 epoch | 87.57 | 80.49 | 68.39 |
| 3 epoch | 85.90 | 82.93 | 64.82 |
| 3 epoch + boundary masking | 88.32 | 87.80 | 68.39 |
3 epoch + boundary masking은 GSM8K를 85.90에서 88.32로, IFEval-ko를 64.82에서 68.39로 되돌립니다. “더 오래 학습”보다 “어디를 학습”할지가 중요했다는 결과입니다.
최종 성적표
회복된 모델의 7개 생성형 벤치마크 평균은 83.82로, BF16 교사의 93.80에 대해 89.4%입니다. 세부 항목은 평균보다 더 많은 정보를 줍니다.
| 벤치마크 | BF16 교사 | Nota 1.58-bit | 회복률 |
|---|---|---|---|
| GSM8K | 95.00 | 89.31 | 94.0% |
| MATH500 | 97.60 | 81.60 | 83.6% |
| HumanEval | 96.34 | 90.85 | 94.3% |
| IFEval | 92.05 | 83.36 | 90.6% |
| HRM8K | 91.05 | 83.24 | 91.4% |
| HumanEval-ko | 95.12 | 85.37 | 89.7% |
| IFEval-ko | 89.46 | 73.04 | 81.6% |
| 평균 | 93.80 | 83.82 | 89.4% |
영어 4개 평균은 86.28로 90.6%, 한국어 3개 평균은 80.55로 87.7%입니다. 수학(GSM8K)과 코드(HumanEval)는 약 94%까지 회복됐지만, 긴 풀이가 필요한 MATH500은 83.6%, 한국어 지시 따르기는 81.6%에 그칩니다. “평균 89.4%”만 보고 한국어 에이전트에 투입하면 기대와 다른 결과가 나올 수 있습니다.
평가 조건도 함께 봐야 합니다. temperature 0.7, 전체 테스트셋, 32K 생성 예산, Nota AI 내부 평가입니다. 독립 재현은 없습니다. 모델 카드도 이 체크포인트가 “완전히 회복된 모델이 아니라” 공개용 중간 체크포인트라고 명시합니다.
10GB 모델을 실제로 올리려면
모델 카드 기준 BF16 60GB가 9.6GB로 줄어 6.25배 작아졌습니다. MLX에는 1.58비트 컨테이너가 없어서 2비트 affine 컨테이너를 씁니다. bits=2, group_size=64, levels={0,1,2}, level 3은 사용하지 않습니다. bias = -scale이라서 dequantization은 scale × (q - 1) = {-a, 0, +a}가 됩니다. 저장된 값은 ternary지만, 파일 포맷은 2비트 affine이라는 점을 구분해야 합니다.
메모리 계산도 공개돼 있습니다. 가중치 약 10GB, 128K 토큰에서 KV 캐시 약 0.8GB, Mamba 상태와 런타임 버퍼를 포함한 추가 메모리가 최대 약 2.4GB로 총 약 12.4GB입니다. 24GB MacBook의 기본 GPU 한도 약 16GB에는 들어갑니다. 16GB MacBook은 기본 약 10.7GB로는 부족하고, macOS 설정에서 한도를 약 13.5GB까지 올리면 이론적으로 들어가지만 시스템과 다른 앱에 남는 메모리가 크게 줄어듭니다. Nota AI가 24GB 이상을 권장하는 이유입니다.
어디에 쓸 수 있고, 어디에 쓰면 안 되나
이 모델의 매력은 “30B급 추론을 로컬에서”라는 비용 구조입니다. 코드 자동완성, 로컬 문서 요약, 분류·추출, 반복적인 에이전트 하위 작업처럼 89% 수준의 품질이 허용되는 작업에 먼저 맞춰볼 만합니다. 반대로 MATH500과 IFEval-ko가 낮은 항목을 핵심으로 하는 한국어 수학·지시 수행 워크플로에는 그대로 넣지 말고, 작업별 평가셋으로 다시 확인해야 합니다.
또한 이 결과는 “1.58비트면 무엇이든 된다”는 주장이 아닙니다. 교사 모델의 품질, distillation 데이터, boundary masking 비율, MLX 커널 지원이 모두 결과에 영향을 줍니다. 모델 카드는 아키텍처가 mlx-lm 또는 mlx-vlm 빌드에 구현돼 있어야 한다고 안내합니다. 양자화 파일만 받아서 아무 런타임에나 올릴 수 있는 것은 아닙니다.
인사이트: 극단적 양자화는 회복 문제다
1.58비트의 진짜 교훈은 비트 수가 아니라 회복의 단위입니다. Nota AI는 모든 가중치를 다시 학습하지 않았습니다. 양자화로 코드가 바뀔 수 있는 경계 근처의 5.9%만 골라 학습했습니다. “더 많이 학습”이 아니라 “어디를 학습”할지가 성능을 되돌렸습니다.
이 관점은 로컬 모델 도입에도 그대로 적용됩니다. 파일 크기와 메모리 계산만 보고 결정하지 말고, 내 작업의 실패 비용이 어느 정도인지, 평균이 아니라 어느 벤치마크가 낮은지, 회복되지 않은 항목이 내 워크플로의 핵심인지 확인해야 합니다. 10GB 모델이 24GB 노트북에 들어간다는 사실은 시작점이고, 89.4%가 내 업무에서도 89.4%라는 보장은 아닙니다.
모델 선택과 라우팅 비용을 다룬 글로 Muse Ember를, 장면을 데이터로 유지하는 렌더링 엔진으로 raea 0.1.0을 이어서 읽을 수 있습니다.