
강의 영상 보기 (새 탭에서 재생)YouTube
📓Google Colab에서 실습하기
이 레슨은 PyTorch/GPU가 필요합니다. 노트북을 다운로드 후 Google Colab에서 열어주세요.
학습 내용
모델 배포
학습 목표
- •학습된 모델을 저장하고 최적화하는 방법을 배운다
- •FastAPI로 REST API 서버를 구축한다
- •TorchScript와 ONNX 변환을 이해한다
- •Docker 컨테이너화와 엣지 디바이스 배포를 알아본다
왜 배포가 중요한가?
비유: 아무리 맛있는 요리를 만들어도, 손님 테이블에 가져다주지 않으면 아무 소용이 없습니다.
모델 학습은 "요리"이고, 배포는 "서빙"입니다. 주방(개발 환경)에서 잘 되던 모델이 식당(운영 환경)에서도 잘 동작하도록 만드는 과정이 배포입니다.
배포에서 고려해야 할 핵심 요소들이 있습니다.
| 요소 | 질문 | 예시 |
|---|---|---|
| 성능 | 충분히 빠른가? | 30ms 이내 응답 |
| 안정성 | 24시간 안정적인가? | 에러 처리, 메모리 관리 |
| 확장성 | 사용자가 늘면? | 로드 밸런싱 |
| 환경 | 어디서 실행되는가? | 클라우드, 엣지, 모바일 |
모델 저장과 최적화
PyTorch 모델 저장 방식
import torch
# 방법 1: state_dict만 저장 (권장)
# 모델 구조는 코드에, 가중치만 파일에 저장
torch.save(model.state_dict(), "char_classifier_weights.pth")
# 로드할 때: 모델 구조를 먼저 만들고 가중치를 불러옴
model = CharClassifier(num_classes=50)
model.load_state_dict(torch.load("char_classifier_weights.pth"))
model.eval()
# 방법 2: 전체 모델 저장
# pickle 기반 - 코드 구조가 바뀌면 깨질 수 있음
torch.save(model, "char_classifier_full.pth")
model = torch.load("char_classifier_full.pth")
TorchScript 변환
TorchScript는 PyTorch 모델을 Python 없이 실행 가능한 형태로 변환합니다. C++ 환경에서도 실행할 수 있어 배포에 유리합니다.
import torch
# 방법 1: torch.jit.trace (입력 예시 기반)
dummy_input = torch.randn(1, 1, 32, 32)
traced_model = torch.jit.trace(model, dummy_input)
traced_model.save("classifier_traced.pt")
# 방법 2: torch.jit.script (코드 분석 기반)
scripted_model = torch.jit.script(model)
scripted_model.save("classifier_scripted.pt")
# 로드 (Python 없이도 가능)
loaded = torch.jit.load("classifier_traced.pt")
output = loaded(dummy_input)
ONNX 변환
비유: ONNX는 "만국 공통어"입니다. PyTorch로 만든 모델을 TensorFlow, TensorRT 등 어디서든 쓸 수 있게 변환합니다.
import torch
# ONNX로 변환
dummy_input = torch.randn(1, 1, 32, 32)
torch.onnx.export(
model,
dummy_input,
"classifier.onnx",
input_names=["input"],
output_names=["output"],
dynamic_axes={"input": {0: "batch_size"}} # 배치 크기 가변
)
# ONNX Runtime으로 추론
import onnxruntime as ort
session = ort.InferenceSession("classifier.onnx")
input_data = dummy_input.numpy()
result = session.run(None, {"input": input_data})
print(f"Output shape: {result[0].shape}")
| 변환 형식 | 장점 | 적합한 경우 |
|---|---|---|
| state_dict | 유연, 디버깅 쉬움 | 개발/실험 단계 |
| TorchScript | Python 불필요 | C++ 서버, 모바일 |
| ONNX | 프레임워크 독립 | TensorRT, 엣지 디바이스 |
FastAPI로 REST API 구축
프로젝트 구조
plate-api/
main.py # FastAPI 앱
models/
detector.pt # YOLO 모델
classifier.pth # CNN 모델
recognizer.py # 인식 파이프라인
requirements.txt # 의존성
Dockerfile # 컨테이너 설정
FastAPI 서버 코드
python⚠️ 로컬 실행 필요from fastapi import FastAPI, UploadFile, File, HTTPException from fastapi.responses import JSONResponse import numpy as np import cv2 import time app = FastAPI( title="License Plate Recognition API", description="Upload a car image to recognize the license plate", version="1.0.0" ) # 모델은 서버 시작 시 한 번만 로드 recognizer = None @app.on_event("startup") async def load_models(): global recognizer recognizer = PlateRecognizer( detector_path="models/detector.pt", classifier_path="models/classifier.pth", class_names=CLASS_NAMES ) print("Models loaded successfully") @app.post("/recognize") async def recognize_plate(file: UploadFile = File(...)): """번호판 인식 API""" # 파일 형식 검증 if not file.content_type.startswith("image/"): raise HTTPException(status_code=400, detail="Image file required") # 이미지 읽기 contents = await file.read() nparr = np.frombuffer(contents, np.uint8) image = cv2.imdecode(nparr, cv2.IMREAD_COLOR) if image is None: raise HTTPException(status_code=400, detail="Invalid image") # 인식 수행 및 시간 측정 start_time = time.time() result = recognizer.recognize(image) elapsed = time.time() - start_time result["processing_time_ms"] = round(elapsed * 1000, 1) return JSONResponse(content=result) @app.get("/health") async def health_check(): """서버 상태 확인""" return { "status": "healthy", "model_loaded": recognizer is not None }
서버 실행과 테스트
bash# 설치 pip install fastapi uvicorn python-multipart # 개발 모드 (코드 변경 시 자동 재시작) uvicorn main:app --reload --host 0.0.0.0 --port 8000 # 프로덕션 모드 (워커 여러 개) uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4 # API 문서 자동 생성: http://localhost:8000/docs
API 호출 예시
pythonimport requests # 이미지 파일 전송 with open("test_car.jpg", "rb") as f: response = requests.post( "http://localhost:8000/recognize", files={"file": ("test_car.jpg", f, "image/jpeg")} ) result = response.json() print(f"Plate: {result.get('plate_text', 'N/A')}") print(f"Confidence: {result.get('confidence', 0):.2%}") print(f"Processing time: {result.get('processing_time_ms', 0)}ms")
Docker 컨테이너화
비유: Docker는 "이삿짐 박스"입니다. 모든 것(코드, 모델, 라이브러리)을 하나의 박스에 담아서, 어떤 집(서버)으로 옮겨도 똑같이 동작하게 만듭니다.
Dockerfile
dockerfileFROM python:3.9-slim WORKDIR /app # 시스템 패키지 (OpenCV 의존성) RUN apt-get update && apt-get install -y libgl1-mesa-glx libglib2.0-0 && rm -rf /var/lib/apt/lists/* # Python 패키지 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 코드와 모델 복사 COPY . . EXPOSE 8000 # 헬스체크 HEALTHCHECK CMD curl -f http://localhost:8000/health || exit 1 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
빌드와 실행
bash# 이미지 빌드 docker build -t plate-recognition:v1 . # CPU로 실행 docker run -d -p 8000:8000 --name plate-api plate-recognition:v1 # GPU 사용 시 (nvidia-docker 필요) docker run -d --gpus all -p 8000:8000 --name plate-api plate-recognition:v1 # 로그 확인 docker logs -f plate-api
엣지 디바이스 배포
모든 시스템이 클라우드에 있을 필요는 없습니다. 카메라 옆에 소형 컴퓨터를 두고 현장에서 바로 인식하는 것이 엣지 배포입니다.
| 디바이스 | GPU | 용도 |
|---|---|---|
| NVIDIA Jetson Nano | 128 CUDA cores | 소규모 현장 |
| NVIDIA Jetson Xavier | 512 CUDA cores | 중규모 시설 |
| Raspberry Pi + Coral TPU | Edge TPU | 초저전력 환경 |
| Intel NUC + OpenVINO | CPU 최적화 | 서버룸 없는 환경 |
엣지 배포 최적화 전략
python# 1. 모델 경량화 # YOLOv8n (nano) 사용 - 가장 작은 모델 model = YOLO("yolov8n.pt") # 2. ONNX + TensorRT 변환 (Jetson에서) model.export(format="engine") # TensorRT 엔진 생성 # 3. 입력 해상도 줄이기 # 640x640 -> 320x320 (속도 4배 향상, 정확도 소폭 감소) model = YOLO("best.pt") results = model.predict(image, imgsz=320) # 4. FP16 (반정밀도) 사용 model.export(format="onnx", half=True) # 모델 크기 절반, 속도 향상
배포 아키텍처 비교
| 구성 | 장점 | 단점 |
|---|---|---|
| 클라우드 전용 | 강력한 GPU, 확장 쉬움 | 네트워크 지연, 비용 |
| 엣지 전용 | 즉시 응답, 오프라인 가능 | 하드웨어 제한, 업데이트 어려움 |
| 하이브리드 | 균형잡힌 구성 | 복잡한 관리 |
하이브리드 구성에서는 엣지에서 빠른 1차 인식을 하고, 확신이 낮은 경우만 클라우드로 보내 정밀 인식을 수행합니다.
배포 체크리스트
실제 서비스에 배포하기 전에 확인해야 할 항목들입니다.
| 항목 | 확인 내용 |
|---|---|
| 모델 버전 | 어떤 버전의 모델이 배포되었는가? |
| 에러 처리 | 잘못된 입력에 대해 적절한 응답을 하는가? |
| 로깅 | 요청/응답/에러가 기록되는가? |
| 보안 | API 인증이 설정되었는가? |
| 모니터링 | 응답 시간, 에러율을 추적하는가? |
| 롤백 | 문제 발생 시 이전 버전으로 돌아갈 수 있는가? |
핵심 정리
- •모델 저장: state_dict(유연), TorchScript(C++ 호환), ONNX(범용)
- •FastAPI: 비동기 REST API로 이미지를 받아 인식 결과를 JSON으로 반환
- •Docker: 코드, 모델, 의존성을 하나로 패키징하여 어디서든 동일하게 실행
- •엣지 배포: Jetson, Coral TPU 등 현장 디바이스에서 실시간 처리
- •최적화: TensorRT, FP16, 해상도 조정으로 추론 속도 향상
레슨 정보
- 레벨
- Level 9: 종합 프로젝트
- 예상 소요 시간
- 60분
- 참고 영상
- YouTube 링크
💡실습 환경 안내
이 레벨은 PyTorch/GPU가 필요하여 Google Colab 사용을 권장합니다.
Colab은 무료 GPU를 제공하여 PyTorch, CNN, Transformer 등을 실행할 수 있습니다.