15장. 모델 경량화: 양자화, 프루닝, 지식증류
경량화의 품질 재기
압축 팩에서 꺼낸 옷이 구겨졌는지는 입어 봐야 압니다. 경량화한 모델도 크기와 속도만 볼 것이 아니라, 글을 얼마나 잘 예측하는지(퍼플렉서티)와 실제 업무 질문을 얼마나 맞히는지(과제 정확도)를 함께 잽니다.
네 카드는 이 장에서 재는 것입니다. 크기와 메모리는 GPU 에 들어가는지를, 속도는 초당 토큰 수를, 퍼플렉서티는 언어 모델로서의 기본 실력을, 과제 정확도는 우리 업무에서의 실력을 봅니다. 퍼플렉서티는 쉽게 잴 수 있지만, 업무에 쓸지는 과제 정확도로 정합니다. 여기서 입어 보기가 과제 정확도입니다.
잴 것과 재는 법
| 잴 것 | 재는 법 | 이 장 |
|---|---|---|
| 크기, 메모리 | 파일 크기, get_memory_footprint(), max_memory_allocated(), Ollama 의 size_vram | 실습 2, 3 |
| 속도 | 만든 토큰 수 ÷ 걸린 시간(초당 토큰) | 실습 2, 3 |
| 퍼플렉서티 | 글 하나의 평균 손실의 exp | 실습 1, 2, 6 |
| 과제 정확도 | 업무 질문 묶음의 정답 수 | 실습 3, 프로젝트 |
퍼플렉서티 계산하기
import numpy as np
# 모델이 정답 토큰에 준 확률들(설명용). 확률이 높을수록 덜 헷갈린 것
probs = np.array([0.5, 0.25, 0.8, 0.1])
loss = -np.log(probs).mean() # 평균 손실(교차 엔트로피)
print("손실", round(loss, 3), "· 퍼플렉서티", round(float(np.exp(loss)), 2)) # 매번 약 몇 개의 보기 사이에서 헷갈리나코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
probs = np.array([...]) | 모델이 정답 토큰 넷에 준 확률이다. 설명을 위해 정한 숫자다 |
np.log(probs) | 자연로그(log)다. 확률이 1 이면 0, 작을수록 큰 음수가 된다 |
-np.log(probs).mean() | 부호를 바꿔 평균을 낸다. 이것이 평균 손실, 곧 교차 엔트로피(cross entropy)다 |
np.exp(loss) | 평균 손실을 e 의 거듭제곱으로 되돌린다. 이것이 퍼플렉서티다 |
round(값, 3), float(...) | 숫자를 반올림하고, numpy 숫자를 파이썬 숫자로 바꿔 깔끔히 찍는다 |
이 코드가 뜻하는 것
객관식 시험에서 학생이 매번 몇 개의 보기 사이에서 망설였는지 재는 것과 같습니다. 정답을 확신하면 1개, 두 보기 사이에서 망설이면 2개, 네 보기를 다 찍으면 4개입니다. 여기서 망설인 보기의 수가 퍼플렉서티입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
probs = np.array([0.5, 0.25, 0.8, 0.1]) | 네 토큰에서 정답에 준 확률이다 | 네 문제에서 정답에 건 확신 |
loss = -np.log(probs).mean() | 확률이 낮을수록 큰 벌점을 매겨 평균한다 | 문제마다 헷갈린 만큼 벌점 |
np.exp(loss) | 벌점을 "보기 몇 개"로 되돌린다 | 평균 몇 개 사이에서 망설였나 |
결과는 손실 1.151, 퍼플렉서티 3.16 입니다. 이 모델은 토큰마다 평균 약 3개의 보기 사이에서 헷갈렸다는 뜻입니다. 양자화한 모델의 퍼플렉서티가 원래보다 커졌다면 그만큼 더 헷갈리게 된 것입니다.
작게 줄여서 눈으로 보기
퍼플렉서티가 정말 "보기 몇 개"로 읽히는지 봅니다. 네 토큰 모두 정답 확률이 같다고 친 것은 설명을 위해 정한 것입니다.
import numpy as np
for name, p in [("보기 넷 중 아무거나", 0.25), ("반반", 0.5), ("거의 확신", 0.99)]:
probs = np.full(4, p) # 네 토큰 모두 정답 확률이 p 라고 치자(설명용)
print(name, "→ 퍼플렉서티", round(float(np.exp(-np.log(probs).mean())), 2))보기 넷 중 아무거나 → 퍼플렉서티 4.0
반반 → 퍼플렉서티 2.0
거의 확신 → 퍼플렉서티 1.01| 결과 | 읽는 법 |
|---|---|
퍼플렉서티 4.0 | 정답에 늘 0.25 를 주면 네 보기를 다 찍은 것과 같다 |
퍼플렉서티 2.0 | 정답에 늘 0.5 를 주면 두 보기 사이에서 망설인 것과 같다 |
퍼플렉서티 1.01 | 거의 확신하면 1 에 가깝다. 퍼플렉서티는 1 보다 작아지지 않는다 |
np.full(4, p) 는 모든 칸이 p 인 길이 4 의 배열을 만듭니다. 확률이 모두 같으면 퍼플렉서티는 1 ÷ 확률과 같아집니다.
주의할 점
- 퍼플렉서티는 같은 글, 같은 토크나이저로 잰 값끼리만 견줍니다. 모델이 다르면 토큰이 달라 견줄 수 없습니다.
- 처음 한 번의 호출에는 모델을 올리는 시간이 들어갑니다. 속도는 올린 뒤의 호출로 잽니다.