본 포스팅은 한빛미디어의 [머신러닝 시스템 설계] Chapter 7을 읽으면서 모델 배포 관련 내용을 정리한 글입니다.
머신러닝 모델을 배포하는 것은 ‘어려운 부분을 모두 무시하면’ 매우 간단하다.
Flask나 FastAPI를 통해 POST 요청 엔드포인트로 예측 함수를 래핑하고, 예측 함수가 컨테이너에서 실행하는 데 필요한 종속성 패키지들을 배치한다. 그리고 모델 및 관련 컨테이너를 AWS나 GCP 같은 클라우드 서비스에 푸시해 엔드포인트를 노출하면 된다.
엔드포인트란?
사용자가 요청(입력 데이터)을 보내고 ML 모델의 추론 결과값을 수신하는 인터페이스(ex. HTTPS)를 제공하는 엔트리포인트 URL
# FastAPI를 사용해 예측함수를 POST 엔드포인트로 변환하는 방법 예시
@app.route('/predict', methods=['POST'])
def predict():
X = request.get_json()['X']
y = MODEL.predict(X).tolist()
return json.dumps({'y':y}), 200
이렇게 노출된 엔드포인트를 downstream application에 사용한다. 예를 들어, application이 사용자에게서 예측 요청을 수신하면 이 요청이 노출된 엔드포인트로 전송되어 예측을 반환한다.
하지만 사용자 수백만 명이 모델을 밀리초 단위 latency와 99% 가동 시간으로 사용하도록 하고, 문제 발생 시 적절한 사람에게 즉시 알리도록 인프라를 설정하고, 업데이트를 원활하게 배포하는 것은 다양한 요인들을 고려해야 한다.
머신러닝 모델 배포에 대한 통념
ML 모델 배포 프로세스에는 여러가지 잘못된 통념들이 있다. 하나씩 짚어보자.
1. 한 번에 한두 가지 머신러닝 모델만 배포한다.
학술 프로젝트를 진행할 때는 대부분 목적에 맞는 단일 모델을 배포한다. 따라서 ML 프로덕션을 단일 모델 맥락에서 생각하는 경향이 있다. 하지만 기업에서는 수많은 ML 모델을 보유한다. 실제 애플리케이션에는 다양한 기능이 있고 각 기능에는 자체 모델이 필요하기 때문이다. (최근 각광받는 GPT 같은 모델을 적용하면 한 번에 여러 기능을 처리 가능할 지도 모른다.)
우버 같은 승차 공유 앱을 예로 들어보자. 이 앱에는 이동 수요, 운전자 가용성, 예상 도착 시간, 동적 가격 책정, 이상 거래, 고객 이탈 등 각 요소를 예측하는 모델이 필요하다. 게다가 앱이 20개 국가에서 운영된다면 국가마다 고유한 모델 set이 필요하다.
2. 아무것도 하지 않으면 모델 성능은 변하지 않는다.
ML 시스템은 프로덕션에서 모델이 접하는 데이터 분포가 훈련된 데이터 분포와 다를 때 data distribution shift라는 문제를 겪는다. 따라서 ML 모델은 학습 직후에 가장 잘 수행되고, 시간이 지남에따라 점점 성능이 저하되는 경향이 있다.
3. 모델을 자주 업데이트할 필요가 없다.
모델 성능은 시간에 따라 저하되므로 최대한 자주 업데이트하면 좋다. (상황마다 다르므로 무조건적인 것은 아니다.) 많은 회사가 여전히 한 달에 한 번 또는 분기에 한 번만 모델을 업데이트하지만 웨이보에서는 일부 ML 모델은 10분마다 업데이트한다고 한다. 알리바바나 틱톡 등에서도 비슷하게 적용한다.
4. 대부분의 ML 엔지니어들은 스케일에 신경 쓰지 않아도 된다.
‘스케일’이 의미하는 바는 어플리케이션마다 다르지만, 예로는 초당 수백 개의 쿼리를 처리하거나 한 달에 수백만 명의 사용자를 처리하는 시스템이 있다.
이러면 사용자가 많은 소수의 회사들만 스케일링에 신경 쓰면 된다고 생각할 수 있다. 하지만 대부분의 회사에서 ML 모델을 배포하는 궁극적인 목표는 결국 사용자의 경험을 개선시켜 사용자가 늘어나는 것이기 때문에 스케일에 신경을 쓰며 ML 애플리케이션을 확장할 수 있도록 구축해야 한다.
배치 예측 vs 온라인 예측
시스템이 예측 결과를 생성해 최종 사용자에게 서빙하는 방법은 크게 배치 예측과 온라인 예측이 있다.
표준화된 용어가 없기 때문에 이 책에서는 다음과 같이 세 가지 주요 예측 모드를 정의한다.
- 배치 피처만 사용하는 배치 예측
- 배치 피처만 사용하는 온라인 예측 (ex. 사전 계산된 임베딩)
- 배치 피처와 스트리밍 피처를 모두 사용하는 온라인 예측 (=스트리밍 예측)
온라인 예측은 예측에 대한 요청이 도착하는 즉시 예측이 생성되고 반환되는 경우이다. 예를 들어 구글 번역에 영어 문장을 입력하는 즉시 한국어 번역문이 돌아오는 경우를 생각해보 수 있다. 일반적으로 온라인 예측을 수행할 때는 RESTful API를 통해 요청이 예측 서비스로 전송된다. 예측이 HTTP 요청을 통해 전송될 때 온라인 예측은 요청과 동기식으로 생성되므로 동기(synchronous) 예측이라고도 한다.
배치 예측은 예측이 주기적으로 혹은 트리거될 때마다 생성되는 경우이다. 예측 결과는 SQL 테이블이나 in-memory 데이터베이스 같은 곳에 저장되고 필요에 따라 검색된다. 예를 들어, 넷플릭스는 네 시간마다 모든 사용자에 대한 영화 추천을 생성하며 사용자가 넷플릭스에 로그인할 때 사전 계산된 추천을 가져와서 표시한다. 배치 예측은 요청과 비동기식으로 생성되므로 비동기(asynchronous) 예측이라고도 한다.
배치 피처는 데이터베이스나 데이터 웨어하우스의 데이터 같은 과거 데이터에서 계산된 피처이다.
스트리밍 피처는 스트리밍 데이터에서 계산된 치퍼, 즉 실시간 전송 데이터이다.
배치 예측에서는 배치 피처만 사용하며, 온라인 예측에서는 배치 피처와 스트리밍 피처를 모두 사용할 수 있다.
예를 들어, 음식 배달 플랫폼에서 사용자가 음식을 주문했다면 배송 시간을 추정하는 데는 다음 피처가 필요하다.
- 배치 피처 : 과거 이 식당의 평균 음식 준비 시간
- 스트리밍 피처 : 지난 10분 동안 해당 건 외에 들어온 주문 건수, 가용한 배달 인력 명수
온라인 예측과 배치 예측이 상호 배타적일 필요는 없다. 인기 있는 쿼리에 대한 예측을 미리 계산한 다음 덜 인기 있는 쿼리에 대한 예측을 온라인으로 생성하는 것도 가능하다.
배치 예측과 온라인 예측의 주요 차이점을 표로 정리하면 다음과 같다.
배치 예측 (동기) | 온라인 예측 (비동기) | |
얼마나 자주 처리? | 주기적으로 처리 (ex. 4시간마다) | 요청이 오면 바로 처리 |
어디에 사용? | 즉각적인 결과가 필요하지 않아 누적된 데이터를 처리하는 경우 (ex. 추천시스템) | 데이터 샘플이 생성디는 즉시 예측해야 하는 경우 (ex. 이상 탐지) |
무엇을 최적화? | 높은 throughput | 짧은 latency |
배치 예측은 온라인 예측이 충분히 저렴하지 않거나 충분히 빠르지 않을 때 유용하다. 비용과 속도는 동일하면서 필요에 따라 예측을 생성할 수 있다면, 굳이 예측을 백만 개씩 미리 생성하면서 저장과 검색에 공들일 필요가 없다.
최근에는 더 맞춤화되고 강력한 하드웨어가 등장하고 기술이 발전함에 따라 더 빠르고 저렴한 온라인 예측이 가능해지면서 온라인 예측이 기본이 되었다고 한다.
이때, 온라인 예측의 latency 난제를 극복하려면 두 가지 요소가 필요하다.
- 실시간 파이프라인
- 최종 사용자가 만족할 만한 속도로 예측을 생성하는 모델