15장. 모델 경량화: 양자화, 프루닝, 지식증류
경량화 방법 고르기
짐이 많을 때 먼저 압축 팩을 쓰고, 그래도 넘치면 짐을 빼고, 그래도 안 되면 작은 가방으로 다시 꾸립니다. 경량화도 손이 덜 가는 것부터 차례로 씁니다.
1번에서 이미 만들어진 4비트 판(GGUF, GPTQ, AWQ)이나 bitsandbytes 로 양자화해 봅니다. 손이 가장 덜 갑니다. 2번에서 그래도 들어가지 않거나 느리면 같은 계열의 더 작은 모델로 바꿉니다. 3번에서 작은 모델의 품질이 모자라면, 큰 모델의 답으로 작은 모델을 가르칩니다(증류). 4번에서 어느 단계든 우리 과제 묶음으로 재어 정합니다. 프루닝은 큰 회사가 전용 도구로 만든 작은 판을 쓰는 경우가 아니면 손이 많이 가서 뒤로 미룹니다. 여기서 압축 팩이 양자화, 작은 가방이 증류입니다.
상황별 고르기
| 상황 | 먼저 해 볼 것 |
|---|---|
| GPU 에 안 들어간다 | 4비트 양자화(GGUF Q4_K_M, AWQ) |
| GPU 가 없다(CPU, 노트북) | GGUF + Ollama 나 llama.cpp |
| 들어가는데 느리다 | 더 작은 모델, 동시 처리(vLLM, 16장) |
| 작은 모델의 품질이 모자란다 | 큰 모델의 답으로 증류, LoRA 미세조정(5장) |
| 아주 많은 요청을 싸게 | 증류한 작은 모델 + 양자화 |
조건으로 거르기
candidates = [{"이름": "A", "메모리GB": 2.2, "초당토큰": 30, "정답률": 0.84},
{"이름": "B", "메모리GB": 1.2, "초당토큰": 70, "정답률": 0.72},
{"이름": "C", "메모리GB": 4.8, "초당토큰": 12, "정답률": 0.90}] # 설명용 숫자
ok = [c for c in candidates if c["메모리GB"] <= 3.5 and c["초당토큰"] >= 20] # 먼저 조건을 거르고
print(max(ok, key=lambda c: c["정답률"])["이름"]) # 남은 것 가운데 정답률로 고른다코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
candidates = [{...}, ...] | 후보 모델 셋의 메모리, 속도, 정답률을 적은 목록이다. 숫자는 설명을 위해 지어낸 것이다 |
[c for c in candidates if 조건] | 조건에 맞는 후보만 남긴 새 목록을 만든다 |
max(ok, key=lambda c: c["정답률"]) | 남은 후보 가운데 정답률이 가장 큰 것을 고른다. key 는 "무엇으로 견줄지"다 |
lambda c: c["정답률"] | 이름 없는 짧은 함수다. 후보 하나를 받아 정답률을 돌려준다 |
이 코드가 뜻하는 것
노트북을 살 때 "무게 1.5kg 이하, 값 100만 원 이하"로 먼저 거르고, 남은 것 가운데 성능이 가장 좋은 것을 고르는 것과 같습니다. 여기서 무게와 값이 메모리와 속도 조건, 성능이 정답률입니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
candidates = [...] | 후보 A, B, C 를 적는다 | 매장의 노트북 셋 |
ok = [c for c in candidates if ...] | 메모리 3.5GB 이하, 초당 20토큰 이상만 남긴다 | 조건에 맞는 것만 남긴다 |
max(ok, key=...)["이름"] | 남은 것 가운데 정답률이 가장 큰 후보의 이름을 꺼낸다 | 남은 것 중 성능이 가장 좋은 것 |
C 는 정답률이 0.90 으로 가장 높지만 메모리 4.8GB 라서 먼저 걸러졌습니다. 남은 A(0.84)와 B(0.72) 가운데 A 가 골라져 결과가 A 입니다.
주의할 점
- 조건(메모리, 속도)은 먼저 정하고, 그 안에서 품질로 고릅니다. 품질만 보고 고르면 서비스에서 감당하지 못합니다.
- 모델의 라이선스도 조건에 넣습니다. 작은 모델이 성능이 좋아도 상업적 사용이 제한될 수 있습니다(6장의 모델 표).