증류
Knowledge Distillation
큰 모델의 지식을 작은 모델로 전이하는 기법. 모델 경량화에 활용.
Knowledge Distillation
큰 모델의 지식을 작은 모델로 전이하는 기법. 모델 경량화에 활용.
증류(Knowledge Distillation)는 대규모 모델(Teacher)의 지식을 작고 효율적인 모델(Student)로 전달하는 모델 압축 기법입니다. Teacher 모델의 출력 확률 분포(soft labels)를 Student 모델이 학습함으로써, 단순히 정답만 학습하는 것보다 더 풍부한 정보를 전달받습니다.
증류 개념은 2015년 Geoffrey Hinton의 논문 "Distilling the Knowledge in a Neural Network"에서 처음 제안되었습니다. 이후 BERT를 6배 작게 압축한 DistilBERT(2019), GPT를 경량화한 다양한 시도들이 이어졌습니다. 2024-2025년에는 DeepSeek-R1, Llama 3.2, Phi-4 등이 대형 모델에서 증류한 소형 모델로 주목받으며, 증류가 LLM 시대의 핵심 기술로 자리잡았습니다.
증류의 핵심 원리는 "soft labels"에 있습니다. 예를 들어 고양이 이미지를 분류할 때, hard label은 "고양이=1, 개=0"이지만, Teacher의 soft label은 "고양이=0.9, 개=0.08, 호랑이=0.02"처럼 클래스 간 유사성 정보를 포함합니다. Temperature 파라미터로 확률 분포를 부드럽게 만들어 이 정보를 더 효과적으로 전달합니다. 최근에는 중간 레이어의 표현(intermediate representations)까지 증류하는 기법이 발전했습니다.
실무에서 증류는 모델 배포 비용 절감의 핵심입니다. 70B 파라미터 모델을 7B로 증류하면 GPU 비용을 90% 이상 절감하면서 원본 성능의 85-95%를 유지할 수 있습니다. 특히 엣지 디바이스, 모바일 앱, 실시간 서비스에서 지연시간과 비용을 줄이는 데 필수적입니다. 2025년 현재 대부분의 상용 LLM 서비스는 증류된 모델을 함께 제공합니다.
PyTorch를 활용한 기본 지식 증류 구현:
# 지식 증류 (Knowledge Distillation) 기본 구현
import torch
import torch.nn as nn
import torch.nn.functional as F
class DistillationLoss(nn.Module):
"""
Knowledge Distillation Loss
- alpha: soft/hard loss 비율
- temperature: 확률 분포 smoothing
"""
def __init__(self, alpha=0.5, temperature=4.0):
super().__init__()
self.alpha = alpha
self.temperature = temperature
self.ce_loss = nn.CrossEntropyLoss()
self.kl_loss = nn.KLDivLoss(reduction='batchmean')
def forward(self, student_logits, teacher_logits, labels):
# Hard Loss: Student vs 실제 정답
hard_loss = self.ce_loss(student_logits, labels)
# Soft Loss: Student vs Teacher (temperature scaling)
T = self.temperature
soft_student = F.log_softmax(student_logits / T, dim=1)
soft_teacher = F.softmax(teacher_logits / T, dim=1)
soft_loss = self.kl_loss(soft_student, soft_teacher) * (T * T)
# 총 손실: alpha로 가중 평균
total_loss = self.alpha * soft_loss + (1 - self.alpha) * hard_loss
return total_loss
# 사용 예시
def train_with_distillation(student, teacher, dataloader, optimizer):
teacher.eval() # Teacher는 학습하지 않음
student.train()
criterion = DistillationLoss(alpha=0.7, temperature=4.0)
for inputs, labels in dataloader:
optimizer.zero_grad()
# Teacher 추론 (gradient 계산 안 함)
with torch.no_grad():
teacher_logits = teacher(inputs)
# Student 학습
student_logits = student(inputs)
loss = criterion(student_logits, teacher_logits, labels)
loss.backward()
optimizer.step()
print(f"Distillation 학습 완료!")
Hugging Face를 활용한 LLM 증류 예제:
# Hugging Face 기반 LLM 증류 (DistilBERT 스타일)
from transformers import (
AutoModelForSequenceClassification,
AutoTokenizer,
Trainer,
TrainingArguments
)
from datasets import load_dataset
# Teacher: 대형 모델 (예: BERT-large)
teacher_name = "klue/roberta-large"
teacher = AutoModelForSequenceClassification.from_pretrained(
teacher_name, num_labels=2
)
# Student: 소형 모델 (예: DistilBERT)
student_name = "monologg/distilkobert"
student = AutoModelForSequenceClassification.from_pretrained(
student_name, num_labels=2
)
tokenizer = AutoTokenizer.from_pretrained(student_name)
# 커스텀 Trainer for Distillation
class DistillationTrainer(Trainer):
def __init__(self, teacher_model, alpha=0.5, temperature=4.0, **kwargs):
super().__init__(**kwargs)
self.teacher = teacher_model
self.teacher.eval()
self.alpha = alpha
self.temperature = temperature
def compute_loss(self, model, inputs, return_outputs=False):
labels = inputs.pop("labels")
# Student forward
student_outputs = model(**inputs)
student_logits = student_outputs.logits
# Teacher forward
with torch.no_grad():
teacher_outputs = self.teacher(**inputs)
teacher_logits = teacher_outputs.logits
# Distillation loss 계산
loss = distillation_loss(
student_logits, teacher_logits, labels,
self.alpha, self.temperature
)
return (loss, student_outputs) if return_outputs else loss
print("Student 모델 파라미터:", sum(p.numel() for p in student.parameters()))
print("Teacher 모델 파라미터:", sum(p.numel() for p in teacher.parameters()))
# 출력: Student가 Teacher 대비 약 40-60% 크기
주요 증류 모델 성능 비교 (2025년 기준):
| 모델 | 파라미터 | 원본 대비 크기 | 성능 유지율 | 추론 속도 |
|---|---|---|---|---|
| BERT-base | 110M | 100% (원본) | 100% | 1x |
| DistilBERT | 66M | 60% | 97% | 1.6x |
| Llama 3.1 70B | 70B | 100% (원본) | 100% | 1x |
| Llama 3.2 8B (증류) | 8B | 11% | ~90% | 8x+ |
| DeepSeek-R1-Distill-Qwen-7B | 7B | 1% (671B 대비) | ~85% | 100x+ |
* 성능 유지율은 벤치마크 평균 기준, 추론 속도는 동일 하드웨어 기준 상대값
Teacher 대비 Student가 너무 작으면 지식을 담을 용량이 부족합니다. 일반적으로 Teacher의 20-40% 크기가 적당하며, 10% 이하로 줄이면 성능 저하가 급격해집니다.
T=1로 두면 hard label 학습과 비슷해져서 증류 효과가 감소합니다. 대부분의 경우 T=3~6이 최적이며, 작업에 따라 튜닝이 필요합니다.
중간 레이어 증류(Intermediate Layer Distillation)를 함께 사용하세요. 최종 출력만 증류하는 것보다 hidden states까지 증류하면 성능이 크게 향상됩니다. TinyBERT, MiniLM이 이 방식으로 성공했습니다.