1. 개요 및 작성 배경
딥러닝 모델의 성능이 날이 갈수록 발전하면서 모델의 크기와 연산량도 함께 비대해지고 있습니다. 이로 인해 서버 비용이 증가할 뿐만 아니라, 스마트폰이나 임베디드 기기 같은 자원이 제한된 환경(On-Device AI)에 모델을 배포하는 데 큰 걸림돌이 되고 있습니다. 따라서 모델의 정확도는 최대한 유지하면서 크기를 줄이고 연산 속도를 높이는 '모델 경량화 및 최적화' 기술은 이제 선택이 아닌 필수입니다. 본 글에서는 PyTorch 환경에서 바로 적용할 수 있는 대표적인 3대 경량화 기법인 양자화(Quantization), 가지치기(Pruning), 지식 증류(Knowledge Distillation)의 개념을 살펴보고 실무 핵심 코드를 공유합니다.

핵심 요약 3줄
- 양자화(Quantization)는 32비트 실수를 8비트 정수로 변환하여 메모리를 절약하고 연산 속도를 획기적으로 높입니다.
- 가지치기(Pruning)는 불필요한 가중치를 제거(0으로 설정)하여 모델의 복잡도를 낮추고 하드웨어 효율을 극대화합니다.
- 지식 증류(Knowledge Distillation)는 거대한 모델(Teacher)의 예측 분포를 작은 모델(Student)에 학습시켜 성능을 보존합니다.
2. 경량화 기법 핵심 비교
각 기법의 특징과 장단점을 한눈에 파악할 수 있도록 정리한 비교 표입니다.
| 경량화 기법 | 핵심 원리 | 대표적 장점 | 주의할 점 |
|---|---|---|---|
| 양자화 (Quantization) | FP32 데이터 타입을 INT8 등으로 하향 변환 | 메모리 사용량 4배 감소, 추론 속도 향상 | 미세한 정확도 손실 가능성, 데이터 보정(Calibration) 필요 |
| 가지치기 (Pruning) | 중요도가 낮은 가중치나 채널을 제거 | 모델 파라미터 수 감소, 희소 행렬 최적화 가능 | 가중치만 0으로 만들 경우 실제 속도 향상을 위해 전용 라이브러리 필요 |
| 지식 증류 (Distillation) | 큰 모델의 지식을 작은 모델로 전수 | 작은 모델의 한계 성능 돌파, 유연한 구조 설계 가능 | 두 개의 모델을 동시에 다뤄야 하므로 학습 시간 증가 |
3. Quantization (양자화)
양자화는 가중치와 활성화 함수의 연산 범위를 제한하여 용량을 줄이는 기법입니다. 주로 32비트 부동소수점(FP32)을 8비트 정수(INT8)로 변환합니다.
3.1 정적 양자화 (Post-Training Static Quantization)
학습이 끝난 모델의 가중치와 대표 데이터셋(Calibration Dataset)을 활용해 활성화 함수의 분포를 미리 계산하여 고정하는 방식입니다.
import torch
import torch.quantization
from torchvision.models import resnet18, ResNet18_Weights
# 1. 모델 로드 및 평가 모드 설정
model = resnet18(weights=ResNet18_Weights.DEFAULT)
model.eval()
# 2. 양자화 설정 (CPU 환경을 위한 fbgemm 또는 qnnpack 설정)
model.qconfig = torch.quantization.get_default_qconfig('fbgemm')
# 3. 양자화 준비 (관찰자(Observer) 삽입)
model_prepared = torch.quantization.prepare(model)
# 4. Calibration (실제 데이터 또는 더미 데이터로 분포 측정)
# 원래는 대표 데이터셋을 넣어야 하며, 여기서는 예시를 위해 더미 데이터를 사용합니다.
dummy_input = torch.randn(1, 3, 224, 224)
model_prepared(dummy_input)
# 5. 양자화 변환
quantized_model = torch.quantization.convert(model_prepared)
print(quantized_model)
3.2 동적 양자화 (Dynamic Quantization)
가중치는 미리 INT8로 변환해두고, 활성화 함수는 추론(Inference) 시점에 동적으로 범위를 계산하여 양자화합니다. 주로 LSTM이나 Transformer 같은 RNN 계열 및 선형 레이어(Linear Layer) 비중이 높은 모델에 효과적입니다.
import torch
import torch.quantization
from torchvision.models import resnet18, ResNet18_Weights
model = resnet18(weights=ResNet18_Weights.DEFAULT)
# Linear 레이어를 대상으로 동적 양자화 적용
quantized_dynamic_model = torch.quantization.quantize_dynamic(
model, {torch.nn.Linear}, dtype=torch.qint8
)
print(quantized_dynamic_model)
4. Pruning (가지치기)
가지치기는 모델 성능에 기여도가 낮은 가중치를 제거하는 기법입니다.
4.1 Unstructured Pruning (비구조적 가지치기)
네트워크 구조와 상관없이 절댓값이 작은 가중치들을 개별적으로 0으로 만듭니다. 구현은 쉽지만 하드웨어 가속을 받기 어렵다는 단점이 있습니다.
import torch
import torch.nn.utils.prune as prune
from torchvision.models import resnet18, ResNet18_Weights
model = resnet18(weights=ResNet18_Weights.DEFAULT)
# fc(전결합층) 레이어의 가중치 중 하위 30%를 0으로 설정
prune.l1_unstructured(model.fc, name='weight', amount=0.3)
# 가지치기가 적용되었는지 확인 (마스크가 생성됨)
print(model.fc.weight)
4.2 Structured Pruning (구조적 가지치기)
특정 뉴런이나 합성곱(Convolution) 필터 전체를 통째로 잘라냅니다. 행렬 형태가 그대로 유지되므로 별도의 특수 라이브러리 없이도 즉각적인 속도 향상을 기대할 수 있습니다.
import torch
import torch.nn.utils.prune as prune
from torchvision.models import resnet18, ResNet18_Weights
model = resnet18(weights=ResNet18_Weights.DEFAULT)
# layer1의 첫 번째 conv1 레이어에서 채널(dim=0) 단위로 L2 노름 기준 하위 50% 필터 제거
prune.ln_structured(model.layer1[0].conv1, name='weight', amount=0.5, n=2, dim=0)
5. Knowledge Distillation (지식 증류)
지식 증류는 이미 잘 학습된 거대 모델(Teacher)의 출력을 정답지(Soft Label)로 삼아, 가벼운 소형 모델(Student)을 학습시키는 방법입니다. 단순히 맞다 틀리다의 정답(Hard Label)만 배우는 것보다, 클래스 간의 관계 확률 정보까지 함께 배우기 때문에 소형 모델의 성능이 크게 끌어올려집니다.
import torch
import torch.nn as nn
import torch.nn.functional as F
class DistillationLoss(nn.Module):
def __init__(self, teacher_model, temperature=3.0, alpha=0.7):
super().__init__()
self.teacher_model = teacher_model
self.teacher_model.eval() # Teacher는 평가 모드로 고정
self.temperature = temperature
self.alpha = alpha
def forward(self, student_logits, inputs, labels):
# Teacher의 출력을 계산할 때는 그래디언트 추적을 비활성화합니다.
with torch.no_grad():
teacher_logits = self.teacher_model(inputs)
# Soft Target Loss (KL Divergence 이용)
soft_loss = F.kl_div(
F.log_softmax(student_logits / self.temperature, dim=1),
F.softmax(teacher_logits / self.temperature, dim=1),
reduction='batchmean'
) * (self.temperature ** 2)
# Hard Target Loss (일반적인 Cross Entropy)
hard_loss = F.cross_entropy(student_logits, labels)
# 두 손실 함수를 가중치(alpha)를 두어 결합
return self.alpha * soft_loss + (1 - self.alpha) * hard_loss
개발을 위한 팁
- 복합 기법 적용 순서: 최고의 효율을 내기 위해서는 단일 기법만 쓰는 것보다 혼합하여 사용하는 것이 좋습니다. 일반적으로 지식 증류(KD)를 통해 소형 모델을 먼저 학습시킨 후, 구조적 가지치기(Pruning)를 수행하고, 최종 배포 직전에 양자화(Quantization)를 적용하는 파이프라인이 정석으로 통합니다.
- 하드웨어 지원 확인: 양자화된 연산(INT8)은 대다수의 최신 모바일 AP나 서버향 GPU(Tensor Core 장착 모델)에서 가속을 지원합니다. 내가 배포할 타깃 환경이 해당 연산 타입을 지원하는지 하드웨어 스펙을 먼저 점검해야 합니다.
흔히 하는 실수
- Calibration 데이터 누락: 정적 양자화를 할 때 입력 데이터의 분포를 확인하는 Calibration 단계를 건너뛰거나, 너무 이질적인 샘플 데이터 몇 장으로만 수행하면 모델의 예측 성능이 엉망이 됩니다. 실제 검증 데이터셋 중 대표성이 있는 데이터를 충분히 입력해주어야 합니다.
- 가지치기 후 모델 영구 적용 누락: torch.nn.utils.prune 메서드를 사용하면 가중치에 마스크(Mask)를 씌워 임시로 0을 만듭니다. 실제 파일 용량을 줄이거나 완전히 구조를 변경하려면 학습 완료 후 prune.remove(model.fc, 'weight') 명령어를 호출하여 마스크를 가중치에 영구적으로 반영(Apply)해주어야 합니다.
6. 결론
PyTorch가 제공하는 다양한 모델 최적화 도구들은 서비스 상용화 단계에서 자원 효율성을 극대화하는 강력한 무기입니다.
- 양자화는 연산 비트를 낮춰 메모리와 연산 속도를 개선합니다.
- 가지치기는 불필요한 연결을 끊어 구조적 다이어트를 유도합니다.
- 지식 증류는 거인의 어깨 위에서 가벼운 모델을 똑똑하게 키워내는 방법입니다.
프로젝트가 처한 하드웨어 제약 조건과 목표 속도에 맞추어 적절한 기법들을 조합해 보시기 바랍니다. 초기 설계 단계부터 경량화를 염두에 둔다면 훨씬 가볍고 빠른 효율적인 딥러닝 서비스를 구축할 수 있습니다.
'Python for AI, Embedded > Deep Learning: PyTorch & AI Modeling' 카테고리의 다른 글
| PyTorch 모델 ONNX 변환부터 클라우드 및 엣지(Edge) 배포 완벽 가이드 (0) | 2026.06.01 |
|---|---|
| PyTorch 모델 배포 마스터: TensorRT로 추론 속도 극대화하는 방법 (0) | 2026.05.31 |
| PyTorch 모델을 ONNX로 변환하고 ONNX Runtime으로 배포하는 방법 (0) | 2026.05.30 |
| PyTorch OpenCV 실시간 객체 탐지: YOLOv5 웹캠 연동 가이드 (0) | 2026.05.29 |
| PyTorch 라이브러리로 사전 학습된 Faster R-CNN 객체 탐지 모델 구현하기 (0) | 2026.05.28 |