- Published on
Edge AI 완전 가이드 2025: 온디바이스 추론, 모델 최적화, TensorRT/ONNX/CoreML
- Authors

- Name
- Youngju Kim
- @fjvbn20031
들어가며: 왜 Edge AI인가?
AI의 미래는 클라우드만이 아닙니다. 점점 더 많은 AI 추론이 데이터가 생성되는 곳, 즉 엣지 디바이스에서 실행되고 있습니다. Edge AI는 클라우드로 데이터를 보내지 않고 스마트폰, IoT 기기, 자동차, 의료 기기 등에서 직접 AI 모델을 실행하는 패러다임입니다.
Edge AI가 필요한 5가지 이유:
- 레이턴시: 클라우드 왕복 없이 밀리초 단위 응답. 자율주행차는 100ms 지연도 치명적입니다.
- 프라이버시: 민감한 데이터(얼굴, 음성, 의료)가 디바이스를 떠나지 않습니다.
- 대역폭 절감: 카메라가 초당 수 GB의 영상을 생성하지만, 추론 결과만 전송하면 됩니다.
- 비용 절감: 클라우드 GPU 비용 없이 로컬에서 추론을 실행합니다.
- 오프라인 동작: 네트워크 연결 없이도 AI 기능이 작동합니다.
1. Edge AI vs Cloud AI 비교
| 비교 항목 | Edge AI | Cloud AI |
|---|---|---|
| 레이턴시 | 1-10ms (로컬) | 50-200ms (네트워크 왕복) |
| 프라이버시 | 데이터가 디바이스에 유지 | 클라우드로 데이터 전송 필요 |
| 대역폭 | 최소 (결과만 전송) | 대량 (원본 데이터 전송) |
| 비용 | 초기 하드웨어 비용 | 지속적 클라우드 비용 |
| 오프라인 | 완전 지원 | 불가능 |
| 모델 크기 | 제한적 (MB~수GB) | 무제한 (수백GB 가능) |
| 컴퓨팅 파워 | 제한적 (NPU/GPU) | 거의 무제한 |
| 업데이트 | OTA 업데이트 필요 | 즉시 배포 가능 |
| 확장성 | 디바이스 수에 비례 | 클라우드 리소스로 탄력적 |
| 정확도 | 최적화로 인한 소폭 저하 가능 | 최대 정확도 |
2. 추론 런타임 비교
2.1 TensorRT (NVIDIA)
NVIDIA GPU 전용 고성능 추론 엔진입니다.
import tensorrt as trt
import numpy as np
# TensorRT 엔진 빌드
logger = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(logger)
network = builder.create_network(
1 << int(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
)
parser = trt.OnnxParser(network, logger)
# ONNX 모델 로드
with open("model.onnx", "rb") as f:
parser.parse(f.read())
# 최적화 프로필 설정
config = builder.create_builder_config()
config.set_memory_pool_limit(trt.MemoryPoolType.WORKSPACE, 1 << 30) # 1GB
# INT8 양자화 활성화
config.set_flag(trt.BuilderFlag.INT8)
config.int8_calibrator = MyCalibrator(calibration_data)
# FP16 활성화
config.set_flag(trt.BuilderFlag.FP16)
# 엔진 빌드 및 직렬화
serialized_engine = builder.build_serialized_network(network, config)
with open("model.engine", "wb") as f:
f.write(serialized_engine)
TensorRT의 주요 최적화 기법:
1. 레이어 퓨전: Conv + BatchNorm + ReLU를 단일 커널로 합침
2. 커널 오토튜닝: 하드웨어별 최적 CUDA 커널 자동 선택
3. 동적 텐서 메모리: 메모리 재사용으로 총 사용량 절감
4. 정밀도 캘리브레이션: INT8 양자화 시 정확도 손실 최소화
5. 다중 스트림 실행: 여러 추론을 병렬로 실행
2.2 ONNX Runtime
크로스 플랫폼 추론 엔진으로, 다양한 하드웨어에서 동작합니다.
import onnxruntime as ort
import numpy as np
# 세션 옵션 설정
sess_options = ort.SessionOptions()
sess_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL
sess_options.intra_op_num_threads = 4
sess_options.inter_op_num_threads = 2
# Execution Provider 선택
# CPU: CPUExecutionProvider
# GPU: CUDAExecutionProvider, TensorrtExecutionProvider
# 모바일: CoreMLExecutionProvider, NNAPIExecutionProvider
providers = [
('TensorrtExecutionProvider', {
'trt_max_workspace_size': 2147483648,
'trt_fp16_enable': True,
'trt_int8_enable': True,
}),
('CUDAExecutionProvider', {
'device_id': 0,
'arena_extend_strategy': 'kNextPowerOfTwo',
}),
'CPUExecutionProvider'
]
session = ort.InferenceSession("model.onnx", sess_options, providers=providers)
# 추론 실행
input_name = session.get_inputs()[0].name
output = session.run(None, {input_name: input_data})
2.3 TensorFlow Lite (TFLite)
모바일 및 임베디드 디바이스를 위한 경량 추론 엔진입니다.
import tensorflow as tf
# TFLite 모델 변환
converter = tf.lite.TFLiteConverter.from_saved_model("saved_model_dir")
# 양자화 설정
converter.optimizations = [tf.lite.Optimize.DEFAULT]
# 완전 정수 양자화 (INT8)
def representative_dataset():
for data in calibration_data:
yield [data.astype(np.float32)]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8
converter.inference_output_type = tf.int8
tflite_model = converter.convert()
# 모델 저장
with open("model_int8.tflite", "wb") as f:
f.write(tflite_model)
# TFLite 추론 실행
interpreter = tf.lite.Interpreter(model_path="model_int8.tflite")
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
interpreter.set_tensor(input_details[0]['index'], input_data)
interpreter.invoke()
output = interpreter.get_tensor(output_details[0]['index'])
2.4 CoreML (Apple)
Apple 디바이스 전용 추론 프레임워크입니다.
import coremltools as ct
# PyTorch -> CoreML 변환
model = torch.load("model.pt")
model.eval()
traced_model = torch.jit.trace(model, torch.randn(1, 3, 224, 224))
coreml_model = ct.convert(
traced_model,
inputs=[ct.ImageType(name="image", shape=(1, 3, 224, 224))],
compute_precision=ct.precision.FLOAT16,
compute_units=ct.ComputeUnit.ALL, # CPU + GPU + Neural Engine
)
# 메타데이터 추가
coreml_model.author = "ML Team"
coreml_model.short_description = "Image classifier"
coreml_model.save("MyModel.mlpackage")
// Swift에서 CoreML 사용
import CoreML
import Vision
let model = try! MyModel(configuration: MLModelConfiguration())
let request = VNCoreMLRequest(model: try! VNCoreMLModel(for: model.model))
let handler = VNImageRequestHandler(cgImage: image, options: [:])
try! handler.perform([request])
if let results = request.results as? [VNClassificationObservation] {
print("Top prediction: \(results.first!.identifier)")
}
2.5 OpenVINO (Intel)
Intel 하드웨어를 위한 추론 엔진입니다.
import openvino as ov
core = ov.Core()
# 모델 로드 및 컴파일
model = core.read_model("model.xml")
compiled_model = core.compile_model(model, "CPU", config={
"PERFORMANCE_HINT": "LATENCY",
"INFERENCE_NUM_THREADS": "4",
})
# INT8 양자화 (NNCF)
import nncf
calibration_dataset = nncf.Dataset(calibration_loader)
quantized_model = nncf.quantize(
model,
calibration_dataset,
preset=nncf.QuantizationPreset.MIXED,
subset_size=300,
)
# 양자화 모델 저장
ov.save_model(quantized_model, "model_int8.xml")
2.6 런타임 비교 요약
추론 런타임 비교:
========================================
런타임 | 플랫폼 | 주요 하드웨어 | 언어
TensorRT | Linux/Windows | NVIDIA GPU | C++, Python
ONNX Runtime | 크로스 플랫폼 | CPU/GPU/NPU | C++, Python, C#, Java
TFLite | 모바일/임베디드 | CPU/GPU/NPU | C++, Java, Swift, Python
CoreML | Apple 전용 | ANE/GPU/CPU | Swift, Objective-C
OpenVINO | Intel 전용 | CPU/iGPU/VPU | C++, Python
MLC LLM | 크로스 플랫폼 | CPU/GPU/NPU | C++, Python, Swift
3. 모델 최적화 기법
3.1 양자화 (Quantization)
양자화는 모델 가중치의 정밀도를 낮추어 크기와 추론 속도를 개선하는 핵심 기법입니다.
Post-Training Quantization (PTQ)
학습 후 양자화로, 추가 학습 없이 모델을 양자화합니다.
# PyTorch PTQ 예시
import torch
from torch.quantization import quantize_dynamic
# 동적 양자화 (가장 간단)
model_fp32 = load_model()
model_int8 = quantize_dynamic(
model_fp32,
{torch.nn.Linear, torch.nn.LSTM},
dtype=torch.qint8
)
# 정적 양자화 (더 높은 성능)
from torch.quantization import prepare, convert, get_default_qconfig
model_fp32.eval()
model_fp32.qconfig = get_default_qconfig('x86')
model_prepared = prepare(model_fp32)
# 캘리브레이션 데이터로 통계 수집
with torch.no_grad():
for batch in calibration_loader:
model_prepared(batch)
model_int8 = convert(model_prepared)
Quantization-Aware Training (QAT)
학습 과정에서 양자화 효과를 시뮬레이션하여 정확도 손실을 최소화합니다.
import torch
from torch.quantization import prepare_qat, convert
model.train()
model.qconfig = torch.quantization.get_default_qat_qconfig('fbgemm')
model_prepared = prepare_qat(model)
# QAT 학습 (일반 학습과 동일)
optimizer = torch.optim.Adam(model_prepared.parameters(), lr=1e-4)
for epoch in range(num_epochs):
for batch in train_loader:
output = model_prepared(batch)
loss = criterion(output, target)
loss.backward()
optimizer.step()
# 양자화 변환
model_prepared.eval()
model_int8 = convert(model_prepared)
LLM 양자화 기법
# GPTQ (GPU 기반 양자화)
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
quantize_config = BaseQuantizeConfig(
bits=4,
group_size=128,
desc_act=False,
)
model = AutoGPTQForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
quantize_config
)
model.quantize(calibration_data)
model.save_quantized("llama-3.1-8b-gptq-4bit")
# AWQ (Activation-aware Weight Quantization)
from awq import AutoAWQForCausalLM
model = AutoAWQForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B")
quant_config = {
"zero_point": True,
"q_group_size": 128,
"w_bit": 4,
"version": "GEMM"
}
model.quantize(tokenizer, quant_config=quant_config)
model.save_quantized("llama-3.1-8b-awq-4bit")
# bitsandbytes (간단한 양자화)
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B",
quantization_config=bnb_config,
device_map="auto",
)
양자화 정밀도별 비교:
정밀도 | 모델 크기 (7B 기준) | 메모리 | 속도 향상 | 정확도 손실
FP32 | 28GB | 28GB | 1x | 기준
FP16 | 14GB | 14GB | 2x | 무시 가능
INT8 | 7GB | 7GB | 3-4x | 미미함 (0.5% 이하)
INT4 | 3.5GB | 3.5GB | 4-6x | 소폭 (1-2%)
3.2 프루닝 (Pruning)
프루닝은 모델에서 불필요한 가중치나 뉴런을 제거하는 기법입니다.
비구조적 프루닝 (Unstructured Pruning)
개별 가중치를 0으로 만들어 희소(sparse) 모델을 생성합니다.
import torch.nn.utils.prune as prune
# 크기 기반 프루닝 (Magnitude-based)
model = load_model()
# 전체 모델에 50% 프루닝 적용
parameters_to_prune = [
(module, 'weight') for module in model.modules()
if isinstance(module, (torch.nn.Linear, torch.nn.Conv2d))
]
prune.global_unstructured(
parameters_to_prune,
pruning_method=prune.L1Unstructured,
amount=0.5, # 50% 프루닝
)
# 프루닝 마스크를 영구 적용
for module, name in parameters_to_prune:
prune.remove(module, name)
# 희소성 확인
total = 0
zero = 0
for p in model.parameters():
total += p.numel()
zero += (p == 0).sum().item()
print(f"Sparsity: {zero/total:.2%}")
구조적 프루닝 (Structured Pruning)
전체 채널이나 헤드를 제거하여 실제 속도 향상을 달성합니다.
# Attention Head 프루닝 예시
import torch.nn.utils.prune as prune
# 특정 레이어의 출력 채널 30% 프루닝
prune.ln_structured(
model.layer1.conv1,
name='weight',
amount=0.3,
n=2,
dim=0 # 출력 채널 차원
)
이동 프루닝 (Movement Pruning)
파인튜닝 과정에서 중요하지 않은 가중치를 식별하여 제거합니다.
프루닝 기법 비교:
========================================
기법 | 희소성 패턴 | 실제 속도 향상 | 정확도 보존
크기 기반 | 비구조적 | 제한적* | 높음
구조적 | 구조적 | 높음 | 중간
이동 프루닝 | 비구조적 | 제한적* | 매우 높음
* 비구조적 프루닝은 전용 하드웨어/라이브러리 필요
3.3 지식 증류 (Knowledge Distillation)
큰 교사(teacher) 모델의 지식을 작은 학생(student) 모델로 전달하는 기법입니다.
import torch
import torch.nn.functional as F
class DistillationLoss(torch.nn.Module):
def __init__(self, temperature=4.0, alpha=0.5):
super().__init__()
self.temperature = temperature
self.alpha = alpha
self.ce_loss = torch.nn.CrossEntropyLoss()
def forward(self, student_logits, teacher_logits, labels):
# 소프트 타겟 손실 (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)
# 하드 타겟 손실 (Cross-Entropy)
hard_loss = self.ce_loss(student_logits, labels)
return self.alpha * soft_loss + (1 - self.alpha) * hard_loss
# 학습 루프
teacher_model.eval()
student_model.train()
for batch in train_loader:
inputs, labels = batch
with torch.no_grad():
teacher_logits = teacher_model(inputs)
student_logits = student_model(inputs)
loss = distillation_loss(student_logits, teacher_logits, labels)
loss.backward()
optimizer.step()
지식 증류의 대표적 성공 사례:
교사 -> 학생 모델 예시:
BERT-base (110M) -> DistilBERT (66M): 40% 작고, 97% 성능 유지
GPT-4 -> Phi-3 Mini (3.8B): 대형 모델의 지식을 소형 모델로 전달
Llama 70B -> Llama 8B: 지식 증류 + 합성 데이터로 성능 극대화
3.4 Neural Architecture Search (NAS)
자동으로 최적의 모델 아키텍처를 탐색하는 기법입니다.
NAS로 발견된 효율적 아키텍처:
========================================
모델 | 파라미터 | Top-1 정확도 | 추론 속도
EfficientNet-B0| 5.3M | 77.3% | 매우 빠름
MobileNetV3 | 5.4M | 75.2% | 매우 빠름
EfficientNetV2| 21M | 85.7% | 빠름
MnasNet | 4.2M | 74.0% | 매우 빠름
4. 하드웨어 랜드스케이프
4.1 NVIDIA (Jetson, T4/L4)
NVIDIA 엣지 AI 하드웨어:
========================================
디바이스 | TOPS | 메모리 | TDP | 용도
Jetson Orin Nano | 40 | 4-8GB | 7-15W | 임베디드 AI
Jetson Orin NX | 100 | 8-16GB | 10-25W| 로봇, 드론
Jetson AGX Orin | 275 | 32-64GB| 15-60W| 자율주행, 고성능
T4 (데이터센터) | 130 | 16GB | 70W | 엣지 서버
L4 (데이터센터) | 120 | 24GB | 72W | 비디오 AI
# Jetson에서 TensorRT 추론 실행
# JetPack SDK 설치 후
# 모델 변환 (ONNX -> TensorRT)
/usr/src/tensorrt/bin/trtexec \
--onnx=model.onnx \
--saveEngine=model.engine \
--fp16 \
--workspace=2048 \
--minShapes=input:1x3x224x224 \
--optShapes=input:4x3x224x224 \
--maxShapes=input:8x3x224x224
# 벤치마크
/usr/src/tensorrt/bin/trtexec --loadEngine=model.engine --batch=4
4.2 Apple (Neural Engine, CoreML, MLX)
Apple Silicon AI 성능:
========================================
칩셋 | Neural Engine TOPS | GPU | 통합 메모리
M1 | 11 | 8코어 | 8-16GB
M2 | 15.8 | 10코어 | 8-24GB
M3 | 18 | 10코어 | 8-36GB
M4 | 38 | 10코어 | 16-64GB
A17 Pro | 35 | 6코어 | 8GB
A18 Pro | 35 | 6코어 | 8GB
# MLX 프레임워크 (Apple Silicon 네이티브)
import mlx.core as mx
import mlx.nn as nn
class SimpleModel(nn.Module):
def __init__(self):
super().__init__()
self.linear1 = nn.Linear(784, 256)
self.linear2 = nn.Linear(256, 10)
def __call__(self, x):
x = nn.relu(self.linear1(x))
return self.linear2(x)
model = SimpleModel()
input_data = mx.random.normal((1, 784))
output = model(input_data)
mx.eval(output) # 지연 평가 실행
4.3 Qualcomm (Snapdragon NPU)
Qualcomm AI Engine:
========================================
칩셋 | NPU TOPS | 용도
Snapdragon 8 Gen 3| 45 | 플래그십 스마트폰
Snapdragon 8 Gen 2| 36 | 프리미엄 스마트폰
Snapdragon 7+ Gen 2| 13 | 중급 스마트폰
QCS6490 | 12 | IoT, 카메라
4.4 Google (Edge TPU, MediaPipe)
# Edge TPU 모델 컴파일
edgetpu_compiler --min_runtime_version 15 model_int8.tflite
# 결과: model_int8_edgetpu.tflite
# MediaPipe 실시간 추론
import mediapipe as mp
import cv2
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
static_image_mode=False,
max_num_hands=2,
min_detection_confidence=0.5,
min_tracking_confidence=0.5,
)
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
results = hands.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
# 21개 랜드마크 처리
pass
4.5 Intel (OpenVINO, Movidius)
Intel AI 가속기:
========================================
하드웨어 | 성능 | 용도
Core Ultra NPU | 10-34 TOPS| 노트북/데스크탑 AI
Arc GPU | 가변 | 데스크탑/워크스테이션
Movidius VPU | 4 TOPS | IoT, 카메라 (단종)
Gaudi 2/3 | 서버급 | 엣지 서버
5. 온디바이스 LLM
5.1 llama.cpp
C/C++로 작성된 경량 LLM 추론 엔진입니다.
# 빌드
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make -j$(nproc)
# Metal 지원 (macOS)
make LLAMA_METAL=1 -j$(nproc)
# CUDA 지원
make LLAMA_CUDA=1 -j$(nproc)
# 모델 양자화 (GGUF 포맷)
./llama-quantize models/llama-3.1-8b-f16.gguf \
models/llama-3.1-8b-q4_k_m.gguf Q4_K_M
# 추론 실행
./llama-cli \
-m models/llama-3.1-8b-q4_k_m.gguf \
-p "Explain quantum computing in simple terms:" \
-n 256 \
-ngl 99 # GPU 레이어 수
5.2 GGUF 포맷 양자화 수준
GGUF 양자화 비교 (Llama 3.1 8B 기준):
========================================
양자화 | 크기 | 메모리 | 품질 | 속도
Q2_K | 2.96GB | 5.4GB | 낮음 | 매우 빠름
Q3_K_M | 3.52GB | 6.0GB | 보통 | 빠름
Q4_K_M | 4.58GB | 7.0GB | 좋음 | 빠름
Q5_K_M | 5.33GB | 7.8GB | 매우 좋음 | 보통
Q6_K | 6.14GB | 8.6GB | 우수 | 보통
Q8_0 | 7.95GB | 10.4GB | 거의 원본 | 느림
F16 | 15.0GB | 17.5GB | 원본 | 느림
5.3 MLC LLM
다양한 플랫폼에서 LLM을 실행할 수 있는 프레임워크입니다.
# MLC LLM 설치
pip install mlc-llm
# 모델 컴파일 (Vulkan 백엔드)
mlc_llm compile ./dist/Llama-3.1-8B-q4f16_1-MLC/ \
--device vulkan \
--output ./dist/Llama-3.1-8B-q4f16_1-vulkan/
# iOS/Android용 컴파일
mlc_llm compile ./dist/Llama-3.1-8B-q4f16_1-MLC/ \
--device iphone \
--output ./dist/Llama-3.1-8B-q4f16_1-ios/
5.4 MLX (Apple Silicon)
# MLX로 LLM 추론
from mlx_lm import load, generate
model, tokenizer = load("mlx-community/Llama-3.1-8B-Instruct-4bit")
prompt = "What is machine learning?"
response = generate(
model,
tokenizer,
prompt=prompt,
max_tokens=256,
temp=0.7,
)
print(response)
5.5 엣지 디바이스에서 실행 가능한 LLM
온디바이스 LLM 비교:
========================================
모델 | 크기 | RAM 요구 | 속도 (tok/s) | 품질
Phi-3 Mini (3.8B) | 2.3GB | 4GB | 20-40 | 우수
Gemma 2 (2B) | 1.4GB | 3GB | 30-50 | 좋음
Llama 3.2 (1B) | 0.7GB | 2GB | 40-60 | 보통
Llama 3.2 (3B) | 1.8GB | 3.5GB | 25-40 | 좋음
Qwen2.5 (3B) | 1.8GB | 3.5GB | 25-40 | 좋음
SmolLM (1.7B) | 1.0GB | 2.5GB | 35-55 | 보통
* Q4_K_M 양자화 기준, 스마트폰에서의 대략적 수치
6. Federated Learning (연합 학습)
6.1 FedAvg 알고리즘
연합 학습의 가장 기본적인 알고리즘입니다.
# FedAvg 의사코드
def federated_averaging(global_model, clients, rounds, local_epochs):
for round_num in range(rounds):
# 1. 글로벌 모델을 각 클라이언트에 배포
client_models = []
client_sizes = []
for client in selected_clients:
# 2. 각 클라이언트에서 로컬 학습
local_model = copy.deepcopy(global_model)
local_model = train_local(
local_model,
client.data,
epochs=local_epochs,
lr=0.01
)
client_models.append(local_model.state_dict())
client_sizes.append(len(client.data))
# 3. 가중 평균으로 글로벌 모델 업데이트
total_size = sum(client_sizes)
new_global = {}
for key in global_model.state_dict():
new_global[key] = sum(
client_models[i][key] * (client_sizes[i] / total_size)
for i in range(len(client_models))
)
global_model.load_state_dict(new_global)
return global_model
6.2 Flower 프레임워크
# Flower 서버
import flwr as fl
strategy = fl.server.strategy.FedAvg(
fraction_fit=0.3, # 30% 클라이언트 참여
fraction_evaluate=0.2, # 20% 클라이언트 평가
min_fit_clients=2, # 최소 참여 클라이언트
min_evaluate_clients=2,
min_available_clients=3,
)
fl.server.start_server(
server_address="0.0.0.0:8080",
config=fl.server.ServerConfig(num_rounds=10),
strategy=strategy,
)
# Flower 클라이언트
import flwr as fl
import torch
class FlowerClient(fl.client.NumPyClient):
def __init__(self, model, trainloader, testloader):
self.model = model
self.trainloader = trainloader
self.testloader = testloader
def get_parameters(self, config):
return [val.cpu().numpy() for val in self.model.parameters()]
def set_parameters(self, parameters):
for param, new_val in zip(self.model.parameters(), parameters):
param.data = torch.tensor(new_val)
def fit(self, parameters, config):
self.set_parameters(parameters)
train(self.model, self.trainloader, epochs=1)
return self.get_parameters(config), len(self.trainloader.dataset), {}
def evaluate(self, parameters, config):
self.set_parameters(parameters)
loss, accuracy = test(self.model, self.testloader)
return float(loss), len(self.testloader.dataset), {"accuracy": float(accuracy)}
fl.client.start_numpy_client(
server_address="localhost:8080",
client=FlowerClient(model, trainloader, testloader),
)
6.3 차분 프라이버시 (Differential Privacy)
# Opacus를 사용한 차분 프라이버시 학습
from opacus import PrivacyEngine
model = create_model()
optimizer = torch.optim.SGD(model.parameters(), lr=0.05)
privacy_engine = PrivacyEngine()
model, optimizer, train_loader = privacy_engine.make_private_with_epsilon(
module=model,
optimizer=optimizer,
data_loader=train_loader,
epochs=10,
target_epsilon=1.0, # 프라이버시 예산
target_delta=1e-5, # 실패 확률
max_grad_norm=1.0, # 그래디언트 클리핑
)
# 학습 (일반 학습과 동일)
for batch in train_loader:
output = model(batch)
loss = criterion(output, target)
loss.backward()
optimizer.step()
# 사용된 프라이버시 예산 확인
epsilon = privacy_engine.get_epsilon(delta=1e-5)
print(f"Epsilon: {epsilon:.2f}")
7. 프라이버시 보존 AI
7.1 온디바이스 처리
민감한 데이터를 디바이스 밖으로 보내지 않고 처리하는 접근법입니다.
온디바이스 프라이버시 보존 사례:
========================================
사례 | 기술 | 프라이버시 보장
Apple Face ID | Neural Engine + Secure Enclave | 얼굴 데이터 디바이스 내 처리
Google Keyboard 예측 | Federated Learning | 타이핑 데이터 서버 미전송
Apple Siri 음성 인식 | CoreML 온디바이스 | 음성 데이터 로컬 처리
Samsung Knox AI | NPU + TEE | 기업 데이터 격리
7.2 Secure Aggregation
연합 학습에서 개별 모델 업데이트를 서버도 볼 수 없게 암호화합니다.
Secure Aggregation 프로토콜:
========================================
1. 각 클라이언트가 마스크 생성 (페어와이즈 시드 교환)
2. 로컬 모델 업데이트에 마스크를 더해 전송
3. 서버는 마스크된 업데이트만 수집
4. 집계 시 마스크가 상쇄되어 합계만 복원
5. 개별 업데이트는 서버도 복원 불가
8. 배포 파이프라인
8.1 모델 변환 워크플로우
학습 프레임워크 → 중간 형식 → 추론 엔진 → 디바이스
========================================
PyTorch ─┐
├──► ONNX ──┬──► TensorRT (.engine) ──► NVIDIA GPU
TensorFlow┤ ├──► ONNX Runtime ──► 크로스 플랫폼
│ ├──► OpenVINO (.xml) ──► Intel
├──► TFLite ──► TFLite Runtime ──► 모바일/IoT
├──► CoreML ──► CoreML Runtime ──► Apple
└──► GGUF ──► llama.cpp ──► 모든 플랫폼
8.2 OTA (Over-The-Air) 모델 업데이트
# 모델 버전 관리 및 OTA 업데이트 예시
import hashlib
import json
import requests
class ModelManager:
def __init__(self, model_dir, manifest_url):
self.model_dir = model_dir
self.manifest_url = manifest_url
def check_update(self):
"""서버에서 최신 모델 매니페스트 확인"""
manifest = requests.get(self.manifest_url).json()
current_version = self.get_current_version()
if manifest["version"] > current_version:
return manifest
return None
def download_model(self, manifest):
"""델타 업데이트 또는 전체 다운로드"""
if manifest.get("delta_url"):
# 델타 패치 다운로드 (크기 절감)
patch = requests.get(manifest["delta_url"]).content
self.apply_delta(patch)
else:
# 전체 모델 다운로드
model_data = requests.get(manifest["model_url"]).content
self.save_model(model_data, manifest)
def validate_model(self, model_path, expected_hash):
"""SHA-256 해시로 무결성 검증"""
with open(model_path, "rb") as f:
file_hash = hashlib.sha256(f.read()).hexdigest()
return file_hash == expected_hash
def rollback(self):
"""문제 발생 시 이전 버전으로 롤백"""
# 이전 버전 복원 로직
pass
8.3 모델 패키징
# 모델 매니페스트 (model_manifest.json)
model_name: "image-classifier-v2"
version: "2.1.0"
framework: "tflite"
file: "model_int8.tflite"
input_shape: [1, 224, 224, 3]
input_type: "uint8"
output_shape: [1, 1000]
labels_file: "labels.txt"
hardware_requirements:
min_ram_mb: 256
supported_delegates: ["gpu", "nnapi", "xnnpack"]
metrics:
accuracy: 0.943
latency_ms: 12.5
model_size_mb: 4.2
9. 활용 사례
9.1 자율주행
자율주행 Edge AI 스택:
========================================
센서 | AI 작업 | 하드웨어 | 레이턴시 요구
카메라 (8-12대) | 객체 탐지/분류 | NVIDIA Orin | 10ms 이하
LiDAR | 3D 포인트 클라우드 | NVIDIA Orin | 20ms 이하
레이더 | 거리/속도 추정 | DSP | 5ms 이하
퓨전 | 센서 퓨전/판단 | NVIDIA Orin | 30ms 이하
계획 | 경로 계획 | CPU/GPU | 50ms 이하
9.2 스마트 카메라
# 엣지 디바이스에서 실시간 객체 탐지
import cv2
import numpy as np
# TFLite 모델 로드 (SSD MobileNet)
interpreter = tf.lite.Interpreter(
model_path="ssd_mobilenet_v2_int8.tflite",
num_threads=4
)
interpreter.allocate_tensors()
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
# 전처리
input_data = preprocess(frame, target_size=(300, 300))
# 추론
interpreter.set_tensor(input_details[0]['index'], input_data)
interpreter.invoke()
# 결과 파싱
boxes = interpreter.get_tensor(output_details[0]['index'])
classes = interpreter.get_tensor(output_details[1]['index'])
scores = interpreter.get_tensor(output_details[2]['index'])
# 높은 신뢰도 결과만 표시
for i in range(len(scores[0])):
if scores[0][i] > 0.5:
draw_box(frame, boxes[0][i], classes[0][i], scores[0][i])
9.3 음성 어시스턴트
온디바이스 음성 처리 파이프라인:
========================================
1. Wake Word 탐지: 작은 모델 (50KB-1MB), 항상 실행, NPU
2. 음성 활동 탐지(VAD): 음성 구간 식별, 매우 경량
3. 음성 인식(ASR): Whisper Tiny/Base (39M-74M 파라미터)
4. 자연어 이해(NLU): 의도 분류 + 개체명 인식
5. 응답 생성: 소형 LLM 또는 템플릿 기반
6. 음성 합성(TTS): 텍스트를 음성으로 변환
9.4 의료 기기
의료 Edge AI 활용:
========================================
기기 | AI 작업 | 규제 고려사항
스마트 워치 | ECG 부정맥 탐지 | FDA 클래스 II
청진기 | 심음/폐음 분석 | FDA 클래스 II
안저 카메라 | 당뇨 망막병증 스크리닝 | FDA 클래스 II
CT/MRI 보조 | 병변 탐지 하이라이트 | FDA 클래스 III
혈당 측정기 | 혈당 추세 예측 | FDA 클래스 II
9.5 산업 IoT
산업 Edge AI 활용:
========================================
영역 | AI 작업 | 이점
품질 검사 | 시각 결함 탐지 | 실시간, 100% 검사
예측 유지보수 | 진동/소음 이상 탐지 | 다운타임 40% 감소
에너지 최적화 | 소비 패턴 예측 | 에너지 15% 절감
안전 모니터링 | PPE 착용 여부 감지 | 사고 예방
로봇 제어 | 경로 계획/장애물 회피 | 자율 운영
10. 과제와 한계
10.1 전력 제약
전력 효율 비교:
========================================
디바이스 | 전력 | AI 성능 | TOPS/W
NVIDIA Jetson Orin Nano| 7-15W | 40 TOPS | 2.7-5.7
Apple A18 Pro | ~5W | 35 TOPS | 7.0
Google Edge TPU | 2W | 4 TOPS | 2.0
Qualcomm Snapdragon 8g3| ~5W | 45 TOPS | 9.0
Intel Core Ultra NPU | ~5W | 34 TOPS | 6.8
10.2 열 관리
모바일 디바이스에서 지속적인 AI 추론은 발열 문제를 일으킵니다. 서멀 스로틀링이 발생하면 성능이 30-50% 저하될 수 있습니다.
10.3 메모리 제한
디바이스별 메모리 제약:
========================================
디바이스 유형 | 일반적 RAM | AI 사용 가능 메모리
IoT 센서 | 256KB-4MB | 극히 제한
마이크로컨트롤러 | 2-16MB | 매우 제한
스마트 카메라 | 256MB-2GB | 수백 MB
스마트폰 | 6-16GB | 2-8GB
엣지 서버 | 16-128GB | 대부분 사용 가능
10.4 모델 업데이트의 어려움
OTA 모델 업데이트 과제:
========================================
- 대역폭 제한: 대용량 모델을 무선으로 전송
- 배터리 소모: 다운로드 + 변환 과정의 에너지
- A/B 테스트: 구버전/신버전 동시 보관 필요
- 롤백: 실패 시 이전 버전 복구 메커니즘
- 무결성: 모델 변조 방지 (서명/해시 검증)
퀴즈
Q1: Edge AI와 Cloud AI의 주요 차이점을 5가지 이상 설명하세요.
- 레이턴시: Edge AI는 1-10ms 로컬 추론, Cloud AI는 50-200ms 네트워크 왕복 필요
- 프라이버시: Edge AI는 데이터가 디바이스에 유지, Cloud AI는 데이터 전송 필요
- 대역폭: Edge AI는 결과만 전송(최소), Cloud AI는 원본 데이터 전송(대량)
- 오프라인: Edge AI는 네트워크 없이 동작 가능, Cloud AI는 불가능
- 컴퓨팅 파워: Edge AI는 제한적(NPU 수십 TOPS), Cloud AI는 거의 무제한
- 모델 크기: Edge AI는 MB에서 수 GB 제한, Cloud AI는 수백 GB 가능
- 비용 구조: Edge AI는 초기 하드웨어 비용, Cloud AI는 지속적 서비스 비용
Q2: PTQ와 QAT의 차이를 설명하고, 각각의 장단점을 비교하세요.
PTQ (Post-Training Quantization):
- 이미 학습된 모델을 추가 학습 없이 양자화
- 장점: 간편함, 학습 데이터 불필요 (캘리브레이션 데이터만 필요), 빠른 적용
- 단점: 정확도 손실이 QAT보다 클 수 있음, 특히 INT4에서
QAT (Quantization-Aware Training):
- 학습 과정에서 양자화 효과를 시뮬레이션
- 장점: 정확도 손실 최소화, INT4에서도 좋은 품질
- 단점: 추가 학습 필요 (학습 데이터, GPU, 시간), 구현 복잡
일반적으로 INT8에서는 PTQ만으로도 충분하고, INT4 이하에서는 QAT가 권장됩니다.
Q3: 연합 학습(Federated Learning)의 FedAvg 알고리즘을 설명하세요.
FedAvg (Federated Averaging)의 과정:
- 모델 배포: 서버가 글로벌 모델을 선택된 클라이언트들에게 전송
- 로컬 학습: 각 클라이언트가 자신의 로컬 데이터로 모델을 학습 (여러 에포크)
- 업데이트 수집: 학습된 모델의 파라미터를 서버로 전송 (원본 데이터는 전송하지 않음)
- 가중 평균: 서버가 각 클라이언트의 데이터 크기에 비례하여 가중 평균으로 글로벌 모델 업데이트
- 반복: 위 과정을 여러 라운드 반복
핵심: 데이터는 디바이스를 떠나지 않고, 모델 업데이트(가중치)만 서버와 주고받아 프라이버시를 보존합니다.
Q4: GGUF 양자화에서 Q4_K_M이 무엇을 의미하는지 설명하세요.
GGUF 양자화 명명 규칙:
- Q: Quantization (양자화)
- 4: 비트 수 (4비트). 가중치당 평균 4비트 사용
- K: K-quant 방식. 블록별로 다른 양자화 수준을 적용하여 중요한 레이어는 더 높은 정밀도 유지
- M: Medium quality. S(Small/저품질), M(Medium), L(Large/고품질) 중 중간 수준
Q4_K_M은 4비트 K-quant 중간 품질 양자화로, 모델 크기를 약 4-5배 줄이면서 품질 손실을 최소화하는 가장 인기 있는 양자화 수준입니다. 7B 모델 기준 약 4.58GB로 스마트폰에서도 실행 가능합니다.
Q5: 모델 프루닝에서 구조적 프루닝과 비구조적 프루닝의 차이는 무엇인가요?
비구조적 프루닝 (Unstructured Pruning):
- 개별 가중치를 0으로 설정하여 희소(sparse) 행렬 생성
- 높은 희소성 달성 가능 (90% 이상)
- 이론적 연산 절감은 크지만, 일반 하드웨어에서 실제 속도 향상은 제한적
- 전용 희소 행렬 연산 하드웨어/라이브러리가 필요
구조적 프루닝 (Structured Pruning):
- 전체 채널, 필터, Attention Head 등 구조적 단위를 제거
- 결과 모델이 일반적인 밀집(dense) 텐서 연산으로 동작
- 일반 하드웨어에서도 실제 속도 향상을 달성
- 희소성 수준은 비구조적보다 낮을 수 있음 (30-50% 정도)
실용적으로는 구조적 프루닝이 실제 추론 속도 향상에 더 효과적이고, 비구조적 프루닝은 NVIDIA의 Sparse Tensor Core 같은 전용 하드웨어에서 효과적입니다.
참고 자료
- TensorRT Developer Guide
- ONNX Runtime Documentation
- TensorFlow Lite Guide
- CoreML Documentation
- OpenVINO Documentation
- llama.cpp Repository
- MLC LLM Documentation
- MLX Documentation
- Flower Federated Learning
- Opacus Differential Privacy
- NVIDIA Jetson Developer
- MediaPipe Solutions
- Qualcomm AI Engine
- Edge AI and Vision Alliance