지식 증류와 모델 경량화: 대형 LLM을 작은 모델로

AI 기술

지식 증류모델 경량화양자화LoRA엣지 AI

이 글은 누구를 위한 것인가

  • 대형 LLM 비용을 줄이기 위해 소형 모델로 증류하려는 팀
  • 엣지 디바이스(모바일, IoT)에 AI를 배포하려는 개발자
  • 도메인 특화 소형 모델을 만들려는 팀

들어가며

GPT-4 수준의 답변을 GPT-4 가격으로 모든 요청에 사용할 수는 없다. 지식 증류는 대형 모델(Teacher)의 출력으로 소형 모델(Student)을 학습시켜 성능을 최대한 유지하면서 속도/비용을 줄인다.

이 글은 bluefoxdev.kr의 지식 증류 모델 경량화 가이드 를 참고하여 작성했습니다.


1. 모델 경량화 전략

[경량화 방법 비교]

지식 증류 (Knowledge Distillation):
  Teacher → Student 학습
  성능 유지율: 85-95%
  학습 필요: O
  적합: 도메인 특화 모델

양자화 (Quantization):
  FP32 → INT8/INT4 변환
  크기: 50-75% 감소
  학습 불필요: X
  속도: 2-4배 향상
  GPTQ, AWQ, GGUF (llama.cpp)

가지치기 (Pruning):
  불필요한 가중치 제거
  크기: 20-50% 감소
  정확도 손실 있음

LoRA (Low-Rank Adaptation):
  전체 파인튜닝 대신 저차원 행렬
  학습 파라미터: 0.1-1%
  메모리: 극적 감소

[증류 데이터 전략]
  Teacher: GPT-4, Claude Opus
  Student: Llama 3 8B, Mistral 7B
  학습 데이터: Teacher의 소프트 레이블 + 실제 데이터
  소프트 레이블: 확률 분포 (argmax 아님)

2. 지식 증류 구현

# Teacher-Student 증류 (Python/PyTorch)
import torch
import torch.nn.functional as F
from anthropic import Anthropic

client = Anthropic()

# Teacher: Claude로 소프트 레이블 생성
async def generate_soft_labels(questions: list[str]) -> list[dict]:
    """Teacher 모델이 각 질문에 대한 상세 답변 생성"""
    soft_labels = []
    
    for question in questions:
        response = client.messages.create(
            model="claude-opus-4-7",  # Teacher: 대형 모델
            max_tokens=512,
            messages=[{"role": "user", "content": question}]
        )
        soft_labels.append({
            "question": question,
            "teacher_response": response.content[0].text,
            "logprobs": None  # 실제로는 log probabilities 추출
        })
    
    return soft_labels

# Student 파인튜닝 데이터셋 생성
def create_distillation_dataset(soft_labels: list[dict]) -> list[dict]:
    """증류 학습 데이터 포맷 변환"""
    return [
        {
            "messages": [
                {"role": "user", "content": item["question"]},
                {"role": "assistant", "content": item["teacher_response"]}
            ]
        }
        for item in soft_labels
    ]

# 지식 증류 손실 함수
def distillation_loss(
    student_logits: torch.Tensor,
    teacher_logits: torch.Tensor,
    labels: torch.Tensor,
    temperature: float = 4.0,
    alpha: float = 0.7
) -> torch.Tensor:
    """
    KL 발산: Student가 Teacher 확률 분포를 모방
    CrossEntropy: 실제 레이블로 정확도 유지
    """
    # 소프트 레이블 손실 (온도 스케일링)
    soft_student = F.log_softmax(student_logits / temperature, dim=-1)
    soft_teacher = F.softmax(teacher_logits / temperature, dim=-1)
    kl_loss = F.kl_div(soft_student, soft_teacher, reduction='batchmean') * (temperature ** 2)
    
    # 하드 레이블 손실 (실제 정답)
    ce_loss = F.cross_entropy(student_logits, labels)
    
    # 결합: alpha * KL + (1-alpha) * CE
    return alpha * kl_loss + (1 - alpha) * ce_loss
// GGUF 양자화 모델 서빙 (llama.cpp + TypeScript)
// llama-node 또는 @llama-node/llama-cpp 패키지 사용

async function runQuantizedModel(prompt: string): Promise<string> {
  // 실제로는 llama.cpp 바인딩 또는 Ollama API 사용
  const response = await fetch('http://localhost:11434/api/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3:8b-instruct-q4_K_M', // 4비트 양자화
      prompt,
      stream: false,
    }),
  });
  const data = await response.json();
  return data.response;
}

// 모델 크기 비교
const modelComparison = [
  { name: 'Llama 3 70B FP16', size: '140GB', speed: '10 tok/s', quality: 95 },
  { name: 'Llama 3 70B INT8', size: '70GB', speed: '20 tok/s', quality: 93 },
  { name: 'Llama 3 8B FP16', size: '16GB', speed: '80 tok/s', quality: 80 },
  { name: 'Llama 3 8B Q4_K_M', size: '4.9GB', speed: '150 tok/s', quality: 77 },
];

// 라우팅: 복잡도에 따라 모델 선택
async function smartModelRouter(query: string): Promise<string> {
  const isComplex = query.length > 200 || /분석|비교|설명해|이유|왜/.test(query);

  if (isComplex) {
    // 복잡한 질문: 대형 모델 (Claude API)
    const { default: Anthropic } = await import('@anthropic-ai/sdk');
    const client = new Anthropic();
    const r = await client.messages.create({
      model: 'claude-sonnet-4-6',
      max_tokens: 1024,
      messages: [{ role: 'user', content: query }],
    });
    return r.content[0].type === 'text' ? r.content[0].text : '';
  }

  // 단순한 질문: 로컬 양자화 모델
  return runQuantizedModel(query);
}

마무리

지식 증류의 핵심은 Teacher의 소프트 레이블(확률 분포)을 Student에게 전달하는 것이다. 하드 레이블(정답만)보다 소프트 레이블이 더 많은 정보를 담아 Student가 더 효율적으로 학습한다. 도메인 특화 데이터로 Student를 증류하면 해당 도메인에서 Teacher에 근접한 성능을 훨씬 작은 모델로 달성할 수 있다.