1모델 경량화의 필요성
엣지 디바이스는 클라우드 서버에 비해 메모리, 연산 능력, 전력이 제한적입니다. 고성능 딥러닝 모델을 제조 현장의 엣지 디바이스에서 실행하려면 모델 경량화(Model Compression)가 필수입니다.
경량화의 목표는 정확도 손실을 최소화하면서 모델 크기와 연산량을 줄여, 제한된 하드웨어에서도 실시간 추론이 가능하게 만드는 것입니다.
경량화 3대 기법: Pruning(가지치기) + Quantization(양자화) + Knowledge Distillation(지식 증류)
2Pruning (가지치기)
Pruning은 모델에서 중요도가 낮은 가중치(weight)나 뉴런을 제거하는 기법입니다. 신경망의 많은 파라미터가 실제로는 예측에 거의 기여하지 않는다는 점을 활용합니다.
Unstructured Pruning
개별 가중치 단위로 제거. 높은 압축률 가능하나 하드웨어 가속 어려움
Structured Pruning
필터/채널 단위로 제거. 실제 속도 향상에 효과적, GPU 최적화 용이
import torch
import torch.nn.utils.prune as prune
class ModelPruner:
"""제조 AI 모델을 위한 Pruning 유틸리티"""
def __init__(self, model, sparsity=0.5):
self.model = model
self.sparsity = sparsity # 50% 파라미터 제거
def apply_l1_unstructured(self):
"""L1 Norm 기반 비구조적 Pruning"""
for name, module in self.model.named_modules():
if isinstance(module, torch.nn.Conv2d):
prune.l1_unstructured(
module,
name='weight',
amount=self.sparsity
)
return self.model
def apply_structured_pruning(self):
"""채널 단위 구조적 Pruning"""
for name, module in self.model.named_modules():
if isinstance(module, torch.nn.Conv2d):
prune.ln_structured(
module,
name='weight',
amount=self.sparsity,
n=2, # L2 Norm
dim=0 # 출력 채널 기준
)
return self.model
def get_sparsity_stats(self):
"""현재 희소성 통계 반환"""
total, nonzero = 0, 0
for param in self.model.parameters():
total += param.numel()
nonzero += (param != 0).sum().item()
sparsity = 1 - (nonzero / total)
return {"total": total, "nonzero": nonzero, "sparsity": sparsity}
3Quantization (양자화)
Quantization은 모델의 가중치와 활성화를 낮은 비트 정밀도로 표현하는 기법입니다. FP32에서 INT8로 변환하면 메모리 사용량이 75% 감소하고, 정수 연산 유닛을 활용한 가속이 가능합니다.
Post-Training Quantization
학습 완료된 모델에 적용. 빠르고 간편하지만 정확도 손실 발생 가능
Quantization-Aware Training
학습 중 양자화 시뮬레이션. 정확도 유지에 효과적이나 재학습 필요
import torch
from torch.quantization import quantize_dynamic, get_default_qconfig
class ModelQuantizer:
"""제조 AI 모델 양자화 유틸리티"""
def dynamic_quantization(self, model):
"""동적 양자화 (추론 시 활성화 양자화)"""
quantized_model = quantize_dynamic(
model,
{torch.nn.Linear, torch.nn.LSTM},
dtype=torch.qint8
)
return quantized_model
def static_quantization(self, model, calibration_loader):
"""정적 양자화 (캘리브레이션 데이터 필요)"""
model.qconfig = get_default_qconfig('fbgemm')
model_prepared = torch.quantization.prepare(model)
# 캘리브레이션: 실제 데이터로 통계 수집
model_prepared.eval()
with torch.no_grad():
for batch in calibration_loader:
model_prepared(batch)
# 양자화 모델 변환
quantized_model = torch.quantization.convert(model_prepared)
return quantized_model
def compare_model_size(self, fp32_model, int8_model):
"""FP32 vs INT8 모델 크기 비교"""
fp32_size = sum(p.numel() * 4 for p in fp32_model.parameters())
int8_size = sum(p.numel() for p in int8_model.parameters())
compression = (1 - int8_size / fp32_size) * 100
return {
"fp32_mb": fp32_size / 1024**2,
"int8_mb": int8_size / 1024**2,
"compression_%": compression
}
4Knowledge Distillation (지식 증류)
Knowledge Distillation은 크고 정확한 "Teacher" 모델의 지식을 작은 "Student" 모델에 전달하는 기법입니다. Student 모델은 Teacher의 출력 분포(soft labels)를 학습하여, 원본 라벨만으로 학습했을 때보다 더 나은 성능을 달성합니다.
import torch
import torch.nn.functional as F
class KnowledgeDistillation:
"""Teacher-Student 지식 증류 학습"""
def __init__(self, teacher, student, temperature=4.0, alpha=0.7):
self.teacher = teacher.eval()
self.student = student
self.temperature = temperature # Softmax 온도
self.alpha = alpha # KD Loss 비중
def distillation_loss(self, student_logits, teacher_logits, labels):
"""
Knowledge Distillation Loss 계산
L = α * KL(soft_teacher || soft_student) + (1-α) * CE(student, labels)
"""
T = self.temperature
# Soft Target Loss (Teacher의 확률 분포 모방)
soft_teacher = F.softmax(teacher_logits / T, dim=1)
soft_student = F.log_softmax(student_logits / T, dim=1)
kd_loss = F.kl_div(soft_student, soft_teacher, reduction='batchmean')
kd_loss = kd_loss * (T ** 2) # 스케일 보정
# Hard Target Loss (실제 라벨)
ce_loss = F.cross_entropy(student_logits, labels)
# 최종 손실
total_loss = self.alpha * kd_loss + (1 - self.alpha) * ce_loss
return total_loss
def train_step(self, batch, optimizer):
"""한 배치 학습 스텝"""
inputs, labels = batch
# Teacher 추론 (gradient 불필요)
with torch.no_grad():
teacher_logits = self.teacher(inputs)
# Student 추론
student_logits = self.student(inputs)
# Loss 계산 및 역전파
loss = self.distillation_loss(student_logits, teacher_logits, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
return loss.item()
Knowledge Distillation의 핵심: Teacher의 "Dark Knowledge" (오답에 대한 확률 분포)가 Student 모델의 일반화 능력을 향상시킴
5경량화 기법 조합
최적의 결과를 위해 여러 경량화 기법을 순차적으로 적용합니다. 일반적인 파이프라인은 다음과 같습니다:
class ModelCompressionPipeline:
"""통합 모델 경량화 파이프라인"""
def compress(self, teacher_model, target_device="jetson"):
"""
경량화 파이프라인:
1. Knowledge Distillation → 작은 Student 모델 학습
2. Pruning → 불필요한 가중치 제거
3. Quantization → INT8 변환
4. TensorRT 최적화 → 하드웨어 가속
"""
# Step 1: Knowledge Distillation
student = self._create_student_architecture()
student = self._train_with_distillation(teacher_model, student)
# Step 2: Structured Pruning (30%)
pruner = ModelPruner(student, sparsity=0.3)
student = pruner.apply_structured_pruning()
student = self._finetune(student) # Pruning 후 재학습
# Step 3: Quantization (INT8)
quantizer = ModelQuantizer()
student = quantizer.static_quantization(student, self.calib_loader)
# Step 4: Export for TensorRT
onnx_path = self._export_to_onnx(student)
trt_engine = self._convert_to_tensorrt(onnx_path, target_device)
return trt_engine
def benchmark(self, original, compressed):
"""원본 vs 경량화 모델 벤치마크"""
results = {
"size_reduction": self._calc_size_reduction(original, compressed),
"speedup": self._calc_speedup(original, compressed),
"accuracy_diff": self._calc_accuracy_diff(original, compressed),
"power_reduction": self._calc_power_reduction(original, compressed)
}
return results
6제조 AI 경량화 사례
실제 제조 현장의 경량화 적용 사례와 결과입니다:
다음 장에서는 NVIDIA TensorRT를 활용하여 경량화된 모델을 GPU에서 최적 실행하는 방법을 학습합니다.