1장: 신경망 직렬화 기초

모델 영속성의 기본 이해

弘益人間 · 널리 인간을 이롭게 하라

1.1 신경망 직렬화 소개

신경망 직렬화는 훈련된 모델을 메모리 내 표현에서 다양한 시스템과 프레임워크에서 저장, 전송 및 로드할 수 있는 영구 형식으로 변환하는 프로세스입니다. 이 기본 기능은 연구에서 프로덕션 배포까지 전체 AI/ML 생태계를 가능하게 합니다.

표준화된 직렬화 형식 없이는 각 프레임워크가 호환되지 않는 모델 파일을 생성하여 모델 공유, 배포 유연성 및 상호 운용성을 방해합니다. WIA-AI-014 표준은 범용 형식과 변환 프로토콜을 정의하여 이러한 중요한 요구를 해결합니다.

직렬화 과정은 단순히 데이터를 저장하는 것 이상입니다. 모델의 전체 지식과 능력을 보존하고, 다양한 환경에서 재현 가능한 결과를 보장하며, 효율적인 전송과 배포를 가능하게 합니다.

직렬화가 중요한 이유

1.2 모델 형식의 핵심 개념

신경망 모델은 직렬화 중에 보존되어야 하는 여러 구성 요소로 이루어져 있습니다:

모델 아키텍처

레이어를 통해 데이터가 흐르는 방식을 정의하는 계산 그래프:

학습된 파라미터

훈련 중에 학습된 가중치 및 바이어스. 일반적으로 다차원 텐서로 저장됩니다:

// 파라미터 구조 예시
{
  "layer1.weight": Tensor[64, 3, 7, 7],    // Conv2D 가중치 (출력, 입력, 높이, 너비)
  "layer1.bias": Tensor[64],                // Conv2D 바이어스
  "layer2.weight": Tensor[128, 64, 3, 3],  // 두 번째 Conv2D 가중치
  "layer2.bias": Tensor[128],              // 두 번째 Conv2D 바이어스
  "bn1.weight": Tensor[64],                // BatchNorm 감마
  "bn1.bias": Tensor[64],                  // BatchNorm 베타
  "bn1.running_mean": Tensor[64],          // BatchNorm 이동 평균
  "bn1.running_var": Tensor[64]            // BatchNorm 이동 분산
}

메타데이터 및 구성

1.3 텐서 표현 기본

텐서는 신경망의 기본 데이터 구조입니다. 직렬화된 형식에서 텐서가 어떻게 표현되는지 이해하는 것이 중요합니다:

텐서 속성

데이터 타입 고려사항

// 일반적인 텐서 데이터 타입
FP32 (float32):  32비트 부동소수점 (표준 훈련)
                 범위: ±3.4e38, 정밀도: ~7자리

FP16 (float16):  16비트 부동소수점 (혼합 정밀도)
                 범위: ±65,504, 정밀도: ~3자리

BF16 (bfloat16): 16비트 브레인 플로트 (Google TPU)
                 범위: FP32와 동일, 정밀도: ~3자리

INT8:            8비트 정수 (양자화 추론)
                 범위: -128~127 또는 0~255

INT4:            4비트 정수 (극단적 양자화)
                 범위: -8~7 또는 0~15

// 다양한 정밀도의 텐서 예시 (ResNet-50 기준)
FP32: 4 bytes/element → 모델 크기 ~100MB
FP16: 2 bytes/element → 모델 크기 ~50MB (2배 압축)
INT8: 1 byte/element  → 모델 크기 ~25MB (4배 압축)
INT4: 0.5 bytes/elem  → 모델 크기 ~12.5MB (8배 압축)

텐서 직렬화 예제

import numpy as np
import torch

# PyTorch 텐서 생성
tensor = torch.randn(3, 4, 5)

# 텐서 속성 확인
print(f"형상: {tensor.shape}")        # torch.Size([3, 4, 5])
print(f"데이터 타입: {tensor.dtype}")  # torch.float32
print(f"메모리 크기: {tensor.numel() * tensor.element_size()} bytes")

# NumPy로 변환 (직렬화 준비)
numpy_array = tensor.numpy()

# 바이너리 형식으로 저장
np.save('tensor.npy', numpy_array)

# 텍스트 형식으로 메타데이터 저장
metadata = {
    'shape': list(tensor.shape),
    'dtype': str(tensor.dtype),
    'min': float(tensor.min()),
    'max': float(tensor.max()),
    'mean': float(tensor.mean())
}
import json
with open('tensor_metadata.json', 'w') as f:
    json.dump(metadata, f, indent=2)

1.4 그래프 기반 모델 표현

현대 신경망은 계산 그래프로 표현됩니다. 노드는 연산을 나타내고 엣지는 데이터 흐름을 나타냅니다:

// 단순화된 그래프 구조 (ResNet 블록 예시)
{
  "nodes": [
    {
      "id": "input",
      "op": "Input",
      "shape": [1, 3, 224, 224],
      "dtype": "float32"
    },
    {
      "id": "conv1",
      "op": "Conv2D",
      "inputs": ["input"],
      "attributes": {
        "kernel_size": [7, 7],
        "stride": [2, 2],
        "padding": [3, 3],
        "out_channels": 64
      },
      "weights": "conv1.weight"
    },
    {
      "id": "bn1",
      "op": "BatchNorm2d",
      "inputs": ["conv1"],
      "attributes": {
        "num_features": 64,
        "eps": 1e-5,
        "momentum": 0.1
      }
    },
    {
      "id": "relu1",
      "op": "ReLU",
      "inputs": ["bn1"],
      "attributes": {
        "inplace": false
      }
    },
    {
      "id": "maxpool1",
      "op": "MaxPool2D",
      "inputs": ["relu1"],
      "attributes": {
        "kernel_size": [3, 3],
        "stride": [2, 2],
        "padding": [1, 1]
      }
    }
  ],
  "edges": [
    {"from": "input", "to": "conv1"},
    {"from": "conv1", "to": "bn1"},
    {"from": "bn1", "to": "relu1"},
    {"from": "relu1", "to": "maxpool1"}
  ]
}

그래프 표현의 장점

1.5 형식 카테고리 및 트레이드오프

신경망 형식은 설계 목표와 사용 사례에 따라 분류할 수 있습니다:

프레임워크별 형식

PyTorch (.pt, .pth): Python pickle 기반, Python 객체 보존, 동적 그래프 지원

TensorFlow SavedModel: Protocol buffers, 서빙 시그니처 포함, 정적 그래프

Keras (.h5, .keras): HDF5 기반, 계층적 모델 구조, 고수준 API

JAX (Flax): MessagePack, 함수형 프로그래밍 패러다임

교환 형식

ONNX: 프레임워크 독립적, 연산자 기반 그래프 표현, 광범위한 지원

CoreML: Apple 생태계, iOS/macOS 최적화, 신경 엔진 지원

TFLite: 모바일/엣지 배포, 크기 최적화, 하드웨어 가속

GGUF: LLM 특화, 양자화 지원, llama.cpp 생태계

형식 비교

// 형식별 특징 비교
형식          크기      로딩속도    호환성    최적화    사용처
─────────────────────────────────────────────────────────
.pt/.pth     중간      빠름        낮음      중간      PyTorch 연구
SavedModel   큼        느림        중간      높음      TF 프로덕션
ONNX         중간      중간        높음      높음      크로스 플랫폼
TFLite       작음      매우빠름    낮음      매우높음  모바일
CoreML       작음      매우빠름    낮음      매우높음  iOS/macOS
GGUF         작음      빠름        중간      높음      LLM 추론

1.6 직렬화 도전과제

신경망 직렬화 시 해결해야 할 몇 가지 기술적 과제:

사용자 정의 연산

모델이 표준 형식에서 지원하지 않는 사용자 정의 레이어나 연산을 사용할 수 있습니다. 해결책:

동적 형상

일부 모델은 가변 입력 크기를 허용하거나 동적 제어 흐름을 사용합니다. 대응 방법:

버전 호환성

프레임워크 버전 변경으로 인한 문제:

1.7 WIA-AI-014 표준 개요

WIA-AI-014 신경망 형식 표준이 제공하는 것:

핵심 원칙

WIA-AI-014 구조

// WIA-AI-014 모델 패키지 구조
model.wia/
├── manifest.json          # 모델 메타데이터 및 인덱스
├── architecture.json      # 계산 그래프 정의
├── weights/
│   ├── layer1.bin        # 바이너리 가중치 데이터
│   ├── layer2.bin
│   └── ...
├── config/
│   ├── preprocessing.json # 전처리 설정
│   ├── postprocessing.json# 후처리 설정
│   └── deployment.json   # 배포 설정
└── metadata/
    ├── training.json      # 훈련 정보
    ├── performance.json   # 벤치마크 결과
    └── license.txt        # 라이선스 정보

1.8 모델 직렬화 모범 사례

항상 메타데이터 포함

{
  "model_name": "ResNet50-ImageNet",
  "version": "1.0.0",
  "framework": "pytorch",
  "framework_version": "2.0.1",
  "created_date": "2025-01-15T10:30:00Z",
  "author": "WIA Research Team",
  "input_shape": [1, 3, 224, 224],
  "input_preprocessing": {
    "mean": [0.485, 0.456, 0.406],
    "std": [0.229, 0.224, 0.225],
    "resize": 256,
    "center_crop": 224
  },
  "output_classes": 1000,
  "accuracy": {
    "top1": 0.761,
    "top5": 0.931
  },
  "dataset": "ImageNet-1K",
  "license": "MIT"
}

변환 후 검증

변환된 모델이 동일한 출력을 생성하는지 항상 확인하세요:

import numpy as np
import torch

def validate_conversion(original_model, converted_model, num_tests=10):
    """모델 변환 검증"""
    original_model.eval()
    converted_model.eval()

    max_diff = 0.0
    for i in range(num_tests):
        # 랜덤 입력 생성
        test_input = np.random.randn(1, 3, 224, 224).astype(np.float32)

        # 원본 모델 실행
        with torch.no_grad():
            output_original = original_model(torch.from_numpy(test_input))

        # 변환된 모델 실행
        with torch.no_grad():
            output_converted = converted_model(torch.from_numpy(test_input))

        # 차이 계산
        diff = np.abs(
            output_original.numpy() - output_converted.numpy()
        )
        current_max = np.max(diff)
        max_diff = max(max_diff, current_max)

        print(f"테스트 {i+1}: 최대 차이 = {current_max:.2e}")

    print(f"\n전체 최대 차이: {max_diff:.2e}")
    assert max_diff < 1e-5, f"차이가 너무 큼: {max_diff}"
    print("✓ 검증 성공!")

    return max_diff

# 사용 예
validate_conversion(original_model, converted_model)

1.9 일반적인 직렬화 워크플로우

연구에서 프로덕션까지 파이프라인

1. 모델 훈련 (Research Phase)
   - 선호하는 프레임워크에서 모델 개발 (PyTorch/TensorFlow)
   - 실험 추적 및 버전 관리 (Weights & Biases, MLflow)
   - 최적 체크포인트 선택

2. 프레임워크 형식으로 내보내기 (Export Phase)
   - PyTorch: .pt, .pth, TorchScript
   - TensorFlow: SavedModel, .h5
   - 메타데이터 및 훈련 정보 포함

3. 중간 형식으로 변환 (Conversion Phase)
   - 프레임워크 독립성을 위해 ONNX로 변환
   - 형상 및 출력 검증
   - 성능 벤치마킹

4. 최적화 (Optimization Phase)
   - 양자화 (FP32 → INT8)
   - 프루닝 (가중치 제거)
   - 그래프 최적화 (연산 융합)
   - 지식 증류 (선택사항)

5. 타겟 형식으로 변환 (Target Deployment)
   - 모바일: TFLite, CoreML
   - 서버: TensorRT, OpenVINO
   - 웹: ONNX.js, TensorFlow.js
   - LLM: GGUF, AWQ

6. 검증 및 테스트 (Validation Phase)
   - 정확도 검증 (원본과 비교)
   - 성능 측정 (지연시간, 처리량)
   - 메모리 사용량 확인
   - 엣지 케이스 테스트

7. 프로덕션 배포 (Production Phase)
   - 모니터링 설정
   - A/B 테스트
   - 점진적 롤아웃
   - 성능 추적

1.10 모델 형식의 미래 트렌드

새로운 형식 및 기술

대형 언어 모델 (LLM) 시대

수십억 파라미터 모델의 등장으로 새로운 요구사항이 생겼습니다:

요약

복습 문제

  1. 신경망 직렬화가 필요한 이유를 세 가지 이상 설명하세요.
  2. 모델을 구성하는 핵심 요소(아키텍처, 파라미터, 메타데이터)를 각각 설명하고 예를 드세요.
  3. FP32, FP16, INT8의 차이점과 각각의 사용 사례를 설명하세요.
  4. 계산 그래프 기반 모델 표현의 장점은 무엇인가요?
  5. PyTorch .pt 형식과 ONNX 형식의 차이점을 설명하고, 각각 언제 사용해야 하는지 설명하세요.
  6. 사용자 정의 연산을 포함한 모델을 직렬화할 때 어떤 문제가 발생할 수 있고, 어떻게 해결할 수 있나요?
  7. 모델 변환 후 검증이 중요한 이유는 무엇이며, 어떻게 수행하나요?
  8. WIA-AI-014 표준의 핵심 원칙 다섯 가지를 나열하고 각각을 설명하세요.
  9. 연구 단계에서 프로덕션 배포까지의 전형적인 모델 직렬화 워크플로우를 단계별로 설명하세요.
  10. 대형 언어 모델(LLM) 시대에 새롭게 등장한 직렬화 요구사항과 기술을 설명하세요.
弘益人間 (홍익인간) · 널리 인간을 이롭게 하라