모델 배포

KYYLE·2023년 10월 4일

ML Service

목록 보기
6/9
post-thumbnail

개요

구현한 ML 모델을 어떻게 배포해야 할까요? 단순한 프로젝트가 아니라, 수백만 명의 사람이 사용하고, 밀리초 단위의 레이턴시를 보장해야 하며 문제 발생 시 관리자에게 알림이 가도록 인프라를 설정하려면 어떻게 해야 할까요? 이번 포스팅에서는 ML 모델 배포에 대해 알아봅니다.

ML 배포에 대한 통념

ML 모델을 배포하는 일은 전통적인 소프트웨어 프로그램을 배포하는 일과 매우 다릅니다. 이번 섹션에서는 배포 프로세스에 대한 잘못된 통념을 다룹니다.

한 번에 한두 가지 머신러닝 모델만 배포한다
ML 프로덕션을 단순히 단일 모델 맥락에서 생각할 수 있습니다. 하지만, 기업에서는 수많은 ML 모델을 보유합니다. 실제 애플리케이션에는 다양한 기능이 있고, 각 기능에는 자체 모델이 필요합니다.

실제로 우버는 수천 개 모델을 프로덕션에 적용합니다. 2021년 연구에 따르면, 직원이 25,000명 이상인 조직 중 41%가 모델을 100개 이상 프로덕션에 적용하고 있습니다.

아무것도 하지 않으면 모델 성능은 변하지 않는다
시간에 따라 소프트웨어의 성능이 저하되는 현상을 소프트웨어 부패 또는 비트 부패라고 합니다. 이는 ML 시스템도 마찬가지입니다. 또한, ML 시스템은 프로덕션 데이터 분포가 훈련 데이터 분포와 달라지는 데이터 분포 시프트라는 문제를 겪습니다. 따라서, ML 모델은 훈련 직후에 가장 잘 수행되고 점점 성능이 저하되는 경향이 있습니다.

모델을 자주 업데이트할 필요가 없다
모델 성능은 시간에 따라 저하되므로 가능한 한 빨리 업데이트하면 좋습니다. 여전히 많은 회사가 한 달에 한 번 또는 분기에 한 번만 모델을 업데이트하지만, 웨이보에서는 일부 ML 모델을 10분마다 업데이트합니다.

대부분의 경우 스케일에 신경 쓰지 않아도 된다
스케일의 의미는 애플리케이션마다 다를 수 있지만, 초당 몇백 개의 쿼리를 처리하거나 한 달에 수백만 명의 사용자를 처리하는 시스템이 있습니다.

완벽한 상관관계는 아니지만, 직원이 100명 이상인 회사는 많은 사용자에게 서비스를 제공할 가능성이 높습니다. ML 관련 직업을 구하고 있다면 직원이 100명 이상인 회사에서 일할 가능성이 높으며, ML 애플리케이션을 확장할 수 있어야 합니다.

배치 예측과 온라인 예측

시스템이 예측 결과를 생성해 최종 사용자에게 서빙하는 방법은 최종 사용자와 개발자 모두에게 영향을 미칩니다. 다음과 같은 세 가지의 주요 예측 모드가 있습니다.

  • 배치 피처만 사용하는 배치 예측
  • 배치 피처만 사용하는 온라인 예측
  • 배치 피처와 스트리밍 피처를 모두 사용하는 온라인 예측(스트리밍 예측)

온라인 예측은 예측에 대한 요청이 도착하는 즉시 예측이 생성되고 반환됩니다(구글 번역 등). 온디맨드 예측, 동기 예측이라고도 합니다.

배치 예측은 예측이 주기적으로 혹은 트리거될 때마다 생성됩니다. 예측 결과는 DB 같은 곳에 저장되고 필요에 따라 검색됩니다(넷플릭스의 영화 추천. 사용자가 로그인할 때 사전 계산된 추천을 표시함). 배치 예측을 비동기 예측이라고도 합니다.

배치 피처는 DB의 데이터 등 과거의 데이터에서 계산된 피처이고, 스트리밍 피처는 스트리밍 데이터에서 계산된 피처입니다. 온라인 예측에서는 배치 피처와 스트리밍 피처를 모두 사용할 수 있습니다.

많은 애플리케이션에서 온라인 예측과 배치 예측은 서로 다른 유스 케이스에 나란히 사용됩니다. 음식 배달 애플리케이션의 경우, 식당 추천을 생성할 때는 배치 예측을 사용합니다. 식당이 많기 때문에 온라인으로 추천을 생성하려면 너무 오래 걸리기 때문입니다. 반면, 특정 식당을 클릭하면 온라인 예측으로 음식 항목을 추천할 수 있습니다.

온라인 예측이 배치 예측보다 비용과 성능 면에서 비효율적이라고 생각할 수 있습니다. 하지만, 온라인 예측을 사용하면 사이트를 방문하지 않은 사용자에 대해 예측을 생성하지 않아도 됩니다. 어떤 애플리케이션에 매일 사용자의 2%만 로그인한다고 생각하면, 모든 사용자에 대해 생성한 예측 중 98%는 낭비인 셈입니다.

배치 예측에서 온라인 예측으로 전환

학계에서 ML을 접했다면 온라인 예측이 보다 자연스러울 수 있습니다. 모델에 입력을 제공하면 곧바로 예측이 생성됩니다. 이러한 방식은 처음 모델을 배포하는 회사에서도 수행하기 보다 쉽습니다.

모델을 내보내고 아마존 세이지메이커나 구글 앱 엔진에 업로드한 다음 노출된 엔드포인트를 반환합니다. 그리고 해당 엔드포인트에 입력이 포함된 요청을 보내면 엔드포인트에서 생성된 예측이 다시 전송됩니다.

온라인 예측은 모델이 예측을 생성하는 데 너무 오래 걸릴 수 있다는 문제가 있습니다. 예측을 미리 계산해 DB에 저장하고 요청이 도착할 때 가져오는 방법이 있습니다. 이 방법이 바로 배치 예측입니다.

배치 예측은 예측을 미리 계산하므로, 모델이 예측을 생성하는 시간을 걱정하지 않아도 됩니다. 따라서 이 방법을 추론 레이턴시를 줄이기 위한 트릭으로 볼 수도 있습니다. 다만, 배치 예측은 모델이 사용자의 선호도 변화에 덜 민감하다는 문제가 있습니다. 또한, 예측을 생성할 요청을 미리 알아야 한다는 문제도 있습니다.

강력한 하드웨어가 등장하고 기술이 발전함에 따라 온라인 예측이 기본이 되었습니다. 최근 몇 년 동안 기업들은 배치 예측에서 온라인 예측으로 전환하기 위해 상당한 투자를 하였습니다.

배치 파이프라인과 스트리밍 파이프라인의 통합

지난 10년 동안 빅데이터 프로세싱은 맵리듀스나 스파크 같은 배치 시스템으로 대량의 데이터를 매우 효율적이고 주기적으로 처리했습니다. 이러한 기업에서 온라인 예측에 스트리밍 기능을 사용하려면 별도의 스트리밍 파이프라인을 구축해야 합니다.

두 가지 파이프라인(배치 파이프라인과 스트리밍 파이프라인)으로 데이터를 처리하는 것은 ML 프로덕션에서 버그가 생기는 원인이 됩니다. 한 파이프라인의 변경 사항이 다른 파이프라인에 제대로 복제되지 않을 수 있습니다.

스트림 처리와 배치 처리를 통합하기 위한 인프라 구축은 최근 ML 커뮤니티에서 인기 있는 주제가 되었습니다. 일부 기업은 피처 스토어를 사용해 훈련에 사용되는 배치 피처와 예측에 사용되는 스트리밍 피처 간의 일관성을 보장합니다.

모델 압축

실시간에 가까운 파이프라인만으로는 온라인 예측에 충분하지 않을 수 있습니다. 이 섹션에서는 모델의 빠른 추론을 위한 기술을 살펴봅니다.

추론 레이턴시를 줄이기 위한 세 가지 주요 접근 방식이 있습니다. 추론을 더 빠르게 하거나, 모델을 더 작게 만들거나, 배포된 하드웨어가 더 빠르게 실행되도록 하는 것입니다.

모델을 작게 만드는 과정을 모델 압축이라고 하며 추론을 더 빠르게 하는 과정을 추론 최적화라고 합니다. 이 섹션에서는 모델 압축에 대해 알아봅니다.

저차원 인수분해

저차원 인수분해의 핵심 아이디어는 고차원 텐서를 저차원 텐서로 대체하는 것입니다. 한 가지 유형은 소형 합성곱 필터(compact convolutional filter)로, 매개변수 개수를 줄이고 속도를 높이기 위해 3×33 \times 3 합성곱을 1×11 \times 1 합성곱으로 대체하는 등 합성곱 필터를 소형 블록으로 대체합니다.

모바일넷의 경우, K×K×CK \times K \times C인 표준 합성곱을 깊이별 합성곱과 점별 합성곱으로 분해합니다. KK는 커널 크기, CC는 채널 개수입니다. 이를 통해 각각의 합성곱 매개변수를 K2CK^2C개에서 K2+CK^2+C개로 줄일 수 있습니다. K=3K=3이면 매개변수 개수가 8~9배 감소합니다.

이러한 방법은 표준 모델에 비해 작은 모델을 빠른 속도로 개발하는 데 사용되고 있습니다.

지식 증류

지식 증류는 작은 모델(학생)이 큰 모델이나 모델의 앙상블(교사)을 모방하도록 훈련하는 방법으로, 배포할 대상은 더 작은 모델입니다. 프로덕션에 사용되는 증류 네트워크로 DistilBERT가 있으며, 이는 BERT 모델보다 매개변수는 40% 적으면서 언어 이해 능력은 성능을 유지하고 60% 더 빠릅니다.

이 접근 방식의 장점은 두 네트워크(작은 모델과 큰 모델) 간에 아키텍처가 달라도 관계없이 작동한다는 점입니다. 랜덤 포레스트와 트랜스포머를 함께 훈련하여 사용할 수 있습니다. 다만, 사용 가능한 교사 모델이 없다면 학생 네트워크를 훈련하기 전에 교사 네트워크를 훈련해야 하므로, 훈련에 오랜 시간이 걸릴 수 있습니다. 또한, 애플리케이션과 모델 아키텍처에도 민감합니다.

가지치기

결정 트리에서 가지치기는 중요하지 않거나 중복된 트리 부분을 제거하는 것입니다. 신경망이 널리 채택됨에 따라, 신경망의 워크로드를 줄일 방법을 찾고자 합니다.

신경망 맥락에서 가지치기에는 두 가지 의미가 있습니다. 신경망 전체 노드를 제거함으로써 아키텍처를 변경하고 매개변수를 줄이는 것입니다. 보다 일반적인 방법으로는 예측에 덜 유용한 매개변수를 0으로 설정하고, 0이 아닌 매개변수 개수를 줄입니다. 즉, 모델의 아키텍처는 그대로 유지됩니다.

가지치기를 하면 신경망이 더 희소해지므로 저장 공간이 덜 필요하여 모델 크기를 줄이는 데 도움이 됩니다. 전체 정확도를 손상하지 않으면서 스토리지 요구 사항을 줄이고, 추론 계산 성능을 개선한 실험 결과가 존재합니다.

양자화

양자화는 가장 일반적으로 사용되는 모델 압축 방법입니다. 양자화는 매개변수를 나타내는 데 더 적은 비트를 사용함으로써 모델 크기를 줄입니다. 기본적으로 소프트웨어 패키지는 32비트로 부동 소수점 수를 표시하는데, 이를 단정밀도 부동 소수점(FP32)이라고 합니다.

모델의 매개변수가 1억 개이고 각각을 32비트로 저장하면 400MB를 점유합니다. 이때 매개변수를 16비트로 표현하면(반정밀도, FP16) 메모리 공간을 절반으로 줄일 수 있습니다.

부동 소수점을 사용하는 대신 모델을 정수로만 구성할 수도 있습니다. 정수를 나타내는 데는 8비트만 사용합니다(고정 소수점).

양자화는 메모리 풋프린트(프로그램이 실행되는 동안 사용하거나 참조하는 메인 메모리의 양)를 줄일 뿐 아니라 계산 속도도 향상합니다. 배치 크기를 늘릴 수 있으며, 정밀도가 낮을수록 계산 속도가 빨라져 훈련 시간과 추론 레이턴시가 단축됩니다. 단순히 비트 단위의 덧셈을 생각해 보면, 1비트 덧셈 당 1나노초가 걸린다면 32비트 숫자는 32ns, 16비트 숫자는 16ns가 걸립니다.

양자화의 단점은 비트 수를 줄임으로 표현할 수 있는 값의 범위가 줄어든다는 것입니다. 범위를 벗어난 값은 반올림하거나 범위 내로 스케일링해야 합니다. 이 때문에 오차가 발생할 수 있는데, 작은 오차가 성능을 크게 변화시킬 수 있습니다.

양자화는 훈련 과정 혹은 사후 훈련에서 수행할 수 있습니다. 훈련 과정의 경우 모델을 낮은 정밀도로 훈련하며, 사후 훈련의 경우 FP32로 훈련된 모델을 추론을 위해 양자화합니다. 훈련 중 양자화를 사용하면 각 매개변수에 더 적은 메모리를 사용하므로 동일한 하드웨어에서 더 큰 모델을 훈련할 수 있습니다.

최근에는 하드웨어의 지원으로 저정밀도 훈련이 인기를 끌고 있습니다. 엔비디아는 혼합 정밀도 훈련을 지원하는 텐서 코어를 도입하였으며, 구글의 TPU는 Bfloat16을 사용한 훈련을 지원합니다. 고정 소수점 훈련은 아직 대중적이지는 않지만, 좋은 성과를 거두고 있습니다.

고정 소수점 추론은 업계의 표준이 되었습니다. 일부 에지 디바이스는 고정 소수점 추론만 지원합니다. 로블록스의 경우, FP32를 8비트 정수로 변환하면서 레이턴시가 7배 감소하고 스루풋이 8배 증가하였습니다(품질 변화에 대한 언급은 없었습니다).

클라우드와 에지에서의 머신러닝

모델 계산을 클라우드와 에지 중 어디에서 수행할지도 고려해야 합니다. 에지에서 계산을 수행함은 소비자 디바이스(에지 디바이스. 브라우저, 노트북, 휴대 전화, 자동차 등)에서 많은 계산이 수행됨을 의미합니다.

가장 쉬운 방법은 AWS, GCP 같은 클라우드 서비스로 모델을 패키징하고 배포하는 것입니다. 다만, 큰 비용이 들 수 있습니다. 클라우드 비용이 증가함에 따라 많은 기업이 에지 디바이스에서 컴퓨팅을 수행할 방법을 찾고 있습니다. 계산을 에지에서 많이 수행할수록 서버 비용이 적게 들어갑니다.

에지 컴퓨팅은 비용 측면 외에도 많은 특장점이 있습니다. 클라우드 컴퓨팅이 불가능한 곳에서 애플리케이션을 실행할 수 있고, 네트워크 레이턴시에 대한 우려가 줄어듭니다. 많은 사례에서 네트워크 레이턴시가 추론 레이턴시보다 큰 병목입니다. 또한, 민감한 사용자 데이터를 처리할 때도 문제가 적습니다.

에지 컴퓨팅이 많은 이점을 가지고 있으므로, 기업들은 다양한 에지 디바이스를 개발하고 있습니다. 기존 업체들은 자체 칩을 만들 계획을 발표하였으며, ML 하드웨어 스타트업들은 더 나은 AI 칩을 개발하기 위해 수십억 달러를 투자받았습니다.

ML 모델을 실행할 하드웨어는 종류가 매우 많습니다. 임의의 하드웨어에서 모델을 효율적으로 실행하려면 어떻게 해야 할까요?

에지 디바이스용 모델 컴파일과 최적화

모델 컴파일
특정 프레임워크(텐서플로, 파이토치 등)로 빌드한 모델이 하드웨어 백엔드에서 실행되려면 하드웨어 공급업체에서 해당 프레임워크를 지원해야 합니다. 하드웨어 백엔드에서 프레임워크에 대한 지원을 제공하는 것은 엔지니어링 노력이 많이 들어갑니다.

ML 워크로드에서 하드웨어 백엔드로 매핑하려면 해당 하드웨어의 설계를 이해하고 활용할 줄 알아야 하는데, 하드웨어 백엔드에 따라 메모리 레이아웃과 계산 기본 단위가 다릅니다. 예를 들어, CPU의 계산 기본 단위는 스칼라이고 GPU는 1차원 벡터이며 TPU는 2차원 벡터(텐서)입니다.

모든 신규 하드웨어 백엔드를 위한 새로운 컴파일러와 라이브러리를 직접 개발하는 대신, 프레임워크와 플랫폼을 연결할 중개자(middleman)를 만들 수 있습니다. 프레임워크 코드를 중개자로 변환하기만 하면 됩니다.

이러한 중개자를 중간 표현(IR)이라고 합니다. 모델의 원래 코드에서 컴파일러는 하드웨어 백엔드에 네이티브 코드를 생성하기 전에 일련의 고수준 및 저수준 IR을 생성합니다. 고수준 IR은 일반적으로 ML 모델의 계산 그래프입니다. 계산 그래프는 계산 실행 순서를 설명하는 그래프입니다.

모델 최적화
하드웨어에서 모델을 실행하기 위해 코드를 낮추고 나면 성능 문제가 발생할 수 있습니다. 생성된 기계 코드는 하드웨어 백엔드에서 실행될 수는 있지만, 효율적이지 않을 수 있습니다. 데이터 지역성, 캐시, 병렬 작업 등을 활용하지 않을 수 있습니다.

ML 워크플로는 많은 프레임워크, 라이브러리로 구성됩니다. 판다스로 데이터를 추출하고 넘파이로 벡터화를 한 후, XGBoost 등을 사용하여 예측을 수행합니다. 프레임워크 내 개별 함수들은 최적화되어도 프레임워크 전반에 걸친 최적화는 거의 혹은 전혀 수행되지 않을 수 있습니다.

계산을 위해 이러한 함수들 간에 데이터를 나이브하게 이동시키면 전체 워크플로에 엄청난 속도 저하를 초래합니다. 넘파이, 판다스, 텐서플로를 사용하는 일반 ML 워크로드는 수동으로 최적화된 코드에 비해 단일 스레드에서 23배 느리게 실행된다는 연구 결과가 있습니다.

ML 모델을 최적화하는 방법은 로컬과 전역으로 두 가지입니다. 로컬 최적화는 모델의 연산자 또는 연산자 집합을 최적화하며 전역 최적화는 전체 계산 그래프를 end-to-end로 최적화합니다.

표준 로컬 최적화 기법들은 보통 작업을 병렬화하거나 칩의 메모리 액세스를 줄입니다. 일반적으로 다음과 같은 방법이 있습니다.

  • 벡터화: 루프, 중첩 루프가 있는 경우 한 번에 한 항목씩 실행하는 대신 메모리에서 인접한 여러 요소를 동시에 실행합니다.
  • 병렬화: 입력 배열이 주어지면 이를 독립적인 작업 청크로 나눠, 각 청크가 개별적으로 수행될 수 있도록 합니다.
  • 루프 타일링: 루프에서 데이터 액세스 순서를 변경해 하드웨어의 메모리 레이아웃과 캐시를 활용합니다.
  • 연산자 융합: 중복 메모리 액세스를 방지하기 위해 여러 연산자를 하나로 통합합니다.

머신러닝을 사용한 모델 최적화
전통적으로 프레임워크 및 하드웨어 공급업체에서는 경험을 바탕으로 모델의 계산 그래프를 가장 잘 실행하는 방법에 대한 휴리스틱을 생각해 내는 최적화 엔지니어를 고용합니다. 다만 수작업으로 만든 휴리스틱에는 몇 가지 단점이 있는데, 휴리스틱은 비최적(nonoptimal)이고 비적응적(nonadaptive)입니다. 신규 프레임워크나 하드웨어에서 프로세스를 반복하려면 엄청난 노력이 필요합니다.

좋은 휴리스틱을 생각하는 대신, 가능한 모든 방법으로 계산 그래프를 실행해 보고 가장 좋은 방법을 선택할 수도 있습니다. 가능한 경로 조합이 너무 많아 전체 경로를 탐색할 수는 없지만, ML은 난해한 문제에 대한 솔루션을 잘 근사화할 수 있습니다.

파이토치의 torch.backends.cudnn.benchmark를 True로 설정하면, cuDNN 자동 튜닝이 활성화됩니다. cuDNN 자동 튜닝은 미리 결정된 옵션 집합을 검색해 합성곱 연산자를 실행한 다음 가장 빠른 방법을 선택합니다. cuDNN 자동 튜닝은 효율적이지만 합성곱 연산자에만 작동합니다. 그보다 일반적인 솔루션은 오픈소스 컴파일러 스택 TVM의 일부인 autoTVM입니다.

ML 기반 컴파일러는 결과가 인상적이지만 속도가 느리다는 단점이 있습니다. ML 모델이 복잡하다면 이 과정에 몇 시간에서 며칠까지도 걸립니다. 다만 이는 일회성 작업이며, 최적화 검색 결과를 캐시해 기존 모델을 최적화하는 데 사용하거나 향후 추가 개선 시에 시작점으로 사용할 수 있습니다. 즉, 하드웨어 백엔드 하나에 대한 모델을 한 번 최적화한 다음 하드웨어 유형이 동일한 여러 디바이스에서 사용하는 것입니다.

브라우저에서의 머신러닝

브라우저에서 실행함으로써 어떤 하드웨어 백엔드에서든 실행 가능한 코드를 생성할 수도 있습니다. 모델을 브라우저에서 실행할 수 있다면 해당 브라우저를 지원하는 모든 기기에서 실행 가능합니다.

브라우저에 대해 이야기하면, 자바스크립트를 떠올리기 쉽습니다. TensorFlow.js와 같은 도구는 모델을 자바스크립트로 컴파일할 때 도움은 되지만, 자바스크립트는 느릴뿐더러 복잡한 로직에는 기능이 제한적입니다.

보다 유망한 접근 방식으로는 웹어셈블리(WASM)가 있습니다. WASM은 다양한 언어로 작성된 프로그램을 웹 브라우저상에서 실행하도록 해주는 개방형 표준입니다. 사이킷런, 파이토치 등에서 모델을 빌드하고 특정 하드웨어에서 실행되도록 컴파일하는 대신 모델을 WASM으로 컴파일합니다. 그러면 자바스크립트와 함께 사용하는 실행 파일을 얻게 됩니다.

WASM의 주요 단점은 브라우저에서 실행되어 속도가 느리다는 점입니다. 자바스크립트보다는 훨씬 빠르지만, WASM으로 컴파일된 애플리케이션은 네이티브 애플리케이션보다 평균 45%에서 55%까지 느리게 실행됩니다.


이번 포스팅에서는 모델 배포에 대해 알아보았습니다. 다음 포스팅에서는 시스템 모니터링에 대해 논의해 보겠습니다.

profile
딥러닝 / 머신러닝 공부하는 대학원생입니다

0개의 댓글