
1. 모델 배포의 딜레마: 탐색(Exploration)과 수확(Exploitation)
새로운 머신러닝 모델을 개발한 후, 이를 실제 서비스에 적용할 때 우리는 큰 고민에 빠집니다. "새 모델이 정말 기존 모델보다 나은가?"라는 의문을 해결하기 위해 트래픽을 나누어 테스트해야 합니다. 이때 가장 대중적인 A/B Testing과 동적인 최적화 방식인 Multi-Armed Bandit (MAB) 알고리즘은 각각 뚜렷한 차이점과 활용 사례를 가집니다.
2. A/B Testing과 Multi-Armed Bandit 핵심 차이 해결 및 비교
두 전략의 기회비용과 통계적 유의성 확보 방식을 상세히 비교합니다.
| 항목 | A/B Testing (고정 할당) | Multi-Armed Bandit (동적 할당) |
|---|---|---|
| 트래픽 배분 방식 | 50:50 또는 고정된 비율로 유지 | 성능에 따라 실시간으로 비율 조정 |
| 최적화 시점 | 실험 종료 후 분석 단계에서 결정 | 실험 진행 중 실시간 최적화 |
| 기회비용(Regret) | 높음 (성능 낮은 모델에도 트래픽 유지) | 낮음 (우수한 모델에 트래픽 집중) |
| 통계적 엄밀함 | 매우 높음 (P-value 계산 용이) | 낮음 (결과에 편향 발생 가능) |
| 주요 용도 | 새로운 기능의 인과관계 증명 | 광고 클릭률, 추천 시스템 수익 최적화 |
3. 실무자를 위한 7가지 Python 기반 트래픽 제어 예제
개발자가 실무 서버 시스템에 즉시 도입할 수 있는 다양한 알고리즘과 해결 코드를 제공합니다.
Example 1: 해시 함수를 이용한 고정 A/B 테스팅 트래픽 분할
사용자 ID를 기반으로 항상 동일한 모델을 경험하게 하는 세션 유지 방식입니다.
import hashlib
def get_model_assignment(user_id, salt="experiment_v1"):
# 사용자 ID와 소금을 결합하여 해시 생성
hash_val = hashlib.md5(f"{user_id}{salt}".encode()).hexdigest()
# 해시값을 숫자로 변환 후 100으로 나눈 나머지 계산
score = int(hash_val, 16) % 100
if score < 50:
return "Model_A (Champion)"
else:
return "Model_B (Challenger)"
# 사용 예시
print(get_model_assignment("user_123"))
Example 2: Epsilon-Greedy 알고리즘 기반 MAB 구현
가장 간단하면서도 강력한 MAB 방식으로, 일정 비율(epsilon)로 탐색을 수행합니다.
import numpy as np
class EpsilonGreedy:
def __init__(self, epsilon=0.1, n_models=2):
self.epsilon = epsilon
self.counts = np.zeros(n_models)
self.values = np.zeros(n_models)
def select_model(self):
if np.random.random() < self.epsilon:
return np.random.randint(len(self.values)) # 탐색(Exploration)
return np.argmax(self.values) # 수확(Exploitation)
def update(self, model_idx, reward):
self.counts[model_idx] += 1
n = self.counts[model_idx]
# 점진적 평균 업데이트 식
self.values[model_idx] = ((n - 1) / n) * self.values[model_idx] + (1 / n) * reward
# 0번 모델 성능이 더 좋은 환경 시뮬레이션
mab = EpsilonGreedy()
mab.update(0, 1) # 모델 0 성공
mab.update(1, 0) # 모델 1 실패
Example 3: 톰슨 샘플링(Thompson Sampling)을 이용한 고차원 최적화
베이지안 사후 확률을 이용하여 더 지능적으로 트래픽을 전환하는 해결 방법입니다.
import random
class ThompsonSampling:
def __init__(self, n_models=2):
self.alphas = [1] * n_models # 성공 횟수 초기화
self.betas = [1] * n_models # 실패 횟수 초기화
def select_model(self):
# 베타 분포에서 샘플링하여 가장 높은 값 선택
samples = [random.betavariate(self.alphas[i], self.betas[i]) for i in range(len(self.alphas))]
return samples.index(max(samples))
def update(self, model_idx, success):
if success:
self.alphas[model_idx] += 1
else:
self.betas[model_idx] += 1
Example 4: 시간에 따른 가중치 감쇠(Time Decay) 전략
과거의 데이터보다 최신 데이터의 성능 지표에 가중치를 두어 모델을 전환합니다.
def calculate_decayed_score(history, decay_factor=0.9):
"""
history: [1, 0, 1, 1, 0] (최신이 마지막)
"""
score = 0
weight = 1
for outcome in reversed(history):
score += outcome * weight
weight *= decay_factor
return score
Example 5: 카나리 배포(Canary Deployment) 트래픽 전환기
특정 비율만큼 조금씩 트래픽을 늘려가며 모델의 에러율을 모니터링합니다.
def canary_router(traffic_pct):
import random
if random.uniform(0, 100) < traffic_pct:
return "v2_new_model"
return "v1_stable_model"
# 실무 예시: 에러가 없으면 10분마다 traffic_pct를 10씩 증가
Example 6: 상한 신뢰 구간(UCB) 기반 모델 선택
불확실성이 높은 모델에게 기회를 주어 탐색 손실을 최소화하는 알고리즘입니다.
import math
def ucb_score(value, count, total_trials):
if count == 0: return float('inf')
# 보상 평균 + 탐색 보너스
return value + math.sqrt(2 * math.log(total_trials) / count)
Example 7: FastAPI와 결합한 실시간 모델 서빙 라우터
실제 API 엔드포인트에서 모델 선택 로직을 통합하는 구조입니다.
from fastapi import FastAPI
app = FastAPI()
mab_strategy = ThompsonSampling(n_models=2)
@app.get("/predict")
async def predict(user_id: str):
idx = mab_strategy.select_model()
model = [model_a, model_b][idx]
result = model.predict(user_id)
# 실제 비즈니스 결과(클릭 여부 등)를 비동기로 피드백 받아 업데이트 수행
return {"prediction": result, "model_version": idx}
4. 결론: 어떤 전략을 선택해야 하는가?
단순히 어떤 모델이 '왜' 좋은지 학술적으로 증명해야 한다면 A/B Testing이 정답입니다. 하지만 전자상거래 추천이나 광고와 같이 실험 중 발생하는 수익 손실을 최소화해야 한다면 Multi-Armed Bandit이 훨씬 경제적인 해결 방법이 됩니다. 최근 MLOps 트렌드는 두 방식을 혼합하여, 초기에는 A/B 테스트로 안전성을 검증하고 이후 MAB로 전환하여 수익을 극대화하는 하이브리드 전략을 취하고 있습니다.
'Artificial Intelligence > 60. Python' 카테고리의 다른 글
| [PYTHON] Serverless AI : AWS Lambda와 GCP Functions의 5가지 추론 레이턴시 해결 방법 (0) | 2026.04.20 |
|---|---|
| [PYTHON] GPU 노드 Horizontal Pod Autoscaling (HPA) 적용을 위한 3가지 커스텀 메트릭 설정 및 해결 방법 (0) | 2026.04.20 |
| [PYTHON] MLOps의 핵심, DVC로 데이터와 모델 버전을 완벽하게 관리하는 7가지 방법 (0) | 2026.04.20 |
| [PYTHON] ONNX 변환 시 프레임워크 간 오퍼레이터 호환성 문제 해결을 위한 7가지 방법 (0) | 2026.04.20 |
| [PYTHON] TensorRT FP16 양자화 오차를 해결하는 3가지 Calibration 데이터 선정 방법 (0) | 2026.04.20 |