작성자: Megha Agarwal, Asfandyar Qureshi, Nikhil Sardana, Linden Li, Julian Quevedo , Daya Khudia
In this blog post, the MosaicML engineering team shares best practices for how to capitalize on popular open source large language models (LLMs) for production usage. We also provide guidelines for deploying inference services built around these models to help users in their selection of models and deployment hardware. We have worked with multiple PyTorch-based backends in production; these guidelines are drawn from our experience with FasterTransformers, vLLM, NVIDIA's soon-to-be-released TensorRT-LLM, and others.
Large Language Models (LLMs)는 두 단계 프로세스를 통해 텍스트를 생성합니다. 첫 번째 단계는 입력 프롬프트의 토큰을 병렬로 처리하는 "prefill"이고, 두 번째 단계는 텍스트를 '토큰' 단위로 순환적으로 생성하는 "decoding"입니다. 생성된 각 토큰은 입력에 추가되어 다음 토큰을 생성하기 위해 모델에 다시 입력됩니다. LLM이 특수 중지 토큰을 출력하거나 사용자가 정의한 조건(예: 최대 토큰 수 생성)이 충족되면 생성이 중지됩니다. LLM이 디코더 블록을 사용하는 방법에 대한 자세한 내용은 이 블로그 게시물을 참조하세요.
토큰은 단어 또는 하위 단어일 수 있습니다. 텍스트를 토큰으로 분할하는 정확한 규칙은 모델마다 다릅니다. 예를 들어, Llama 모델이 텍스트를 토큰화하는 방식과 OpenAI 모델이 텍스트를 토큰화하는 방식을 비교할 수 있습니다. LLM 추론 제공업체는 종종 토큰 기반 지표(예: 초당 토큰 수)로 성능을 이야기하지만, 이러한 변형으로 인해 이 수치가 모델 유형 간에 항상 비교 가능한 것은 아닙니다. 구체적인 예로, Anyscale 팀은 Llama 2 토큰화가 ChatGPT 토큰화보다 19% 더 길다는 것을 발견했습니다(하지만 전체 비용은 훨씬 낮습니다). HuggingFace의 연구원들은 또한 Llama 2가 GPT-4와 동일한 양의 텍스트를 학습하는 데 약 20% 더 많은 토큰이 필요하다는 것을 발견했습니다.
그렇다면 추론 속도에 대해 정확히 어떻게 생각해야 할까요?
저희 팀은 LLM 서빙에 네 가지 주요 지표를 사용합니다.
저희의 목표는 무엇일까요? 최초 토큰까지의 가장 빠른 시간, 가장 높은 처리량, 그리고 가장 빠른 출력 토큰당 시간입니다. 즉, 가능한 한 많은 사용자를 지원하기 위해 가능한 한 빨리 텍스트를 생성하는 모델을 원합니다.
특히, 처리량과 출력 토큰당 시간 사이에는 절충점이 있습니다. 16개의 사용자 쿼리를 동시에 처리하면 순차적으로 쿼리를 실행하는 것보다 더 높은 처리량을 얻을 수 있지만, 각 사용자에 대한 출력 토큰 생성에는 더 오래 걸립니다.
전체 추론 지연 시간 목표가 있다면, 모델을 평가하는 데 유용한 몇 가지 휴리스틱이 있습니다.
잠재 고객으로부터 평균 추론 지연 시간을 제공해 달라는 요청을 자주 받습니다. 특정 지연 시간 목표("토큰당 20ms 미만이 필요합니다")에 자신을 고정하기 전에 예상 입력 길이와 원하는 출력 길이를 파악하는 데 시간을 할애하는 것이 좋습니다.
LLM 추론 최적화는 다음과 같은 일반적인 기술의 이점을 얻습니다.
이러한 방법 외에도 Transformer별로 중요한 최적화가 많이 있습니다. 그중 대표적인 예가 KV(키-값) 캐싱입니다. 디코더 전용 Transformer 기반 모델의 어텐션(Attention) 메커니즘은 계산적으로 비효율적입니다. 각 토큰은 이전에 본 모든 토큰에 주의를 기울이므로, 새 토큰이 생성될 때마다 동일한 값을 많이 다시 계산합니다. 예를 들어, N번째 토큰을 생성하는 동안 (N-1)번째 토큰은 (N-2)번째, (N-3)번째… 1번째 토큰에 주의를 기울입니다. 마찬가지로, (N+1)번째 토큰을 생성하는 동안 N번째 토큰에 대한 어텐션은 다시 (N-1)번째, (N-2)번째, (N-3)번째… 1번째 토큰을 살펴봐야 합니다. KV 캐싱, 즉 어텐션 레이어의 중간 키/값을 저장하는 것은 나중에 재사용하기 위해 해당 결과를 보존하여 반복적인 계산을 피하는 데 사용됩니다.
LLM의 계산은 주로 행렬-행렬 곱셈 연산에 의해 지배됩니다. 작은 차원을 가진 이러한 연산은 대부분의 하드웨어에서 일반적으로 메모리 대역폭에 의해 제한됩니다. 순환 방식으로 토큰을 생성할 때, 활성화 행렬 차원 중 하나(배치 크기와 시퀀스의 토큰 수로 정의됨)는 작은 배치 크기에서 작습니다. 따라서 속도는 로드된 데이터에 대해 얼마나 빨리 계산할 수 있는지보다 GPU 메모리에서 로컬 캐시/레지스터로 모델 파라미터를 얼마나 빨리 로드할 수 있는지에 따라 달라집니다. 추론 하드웨어의 사용 가능한 메모리 대역폭과 달성된 메모리 대역폭은 피크 컴퓨팅 성능보다 토큰 생성 속도를 더 잘 예측합니다.
추론 하드웨어 활용도는 서빙 비용 측면에서 매우 중요합니다. GPU는 비싸며 최대한 많은 작업을 수행하도록 해야 합니다. 공유 추론 서비스는 여러 사용자의 워크로드를 결합하고 개별 간격을 채우고 중복 요청을 일괄 처리하여 비용을 낮게 유지할 것을 약속합니다. Llama2-70B와 같은 대형 모델의 경우 대규모 배치 크기에서만 좋은 비용/성능을 달성할 수 있습니다. 대규모 배치 크기에서 작동할 수 있는 추론 서빙 시스템을 갖추는 것이 비용 효율성에 중요합니다. 그러나 큰 배치는 더 큰 KV 캐시 크기를 의미하며, 이는 모델을 서빙하는 데 필요한 GPU 수를 증가시킵니다. 여기서 밀고 당기는 힘이 있으며 공유 서비스 운영자는 비용 절충 을 하고 시스템 최적화를 구현해야 합니다.
LLM 추론 서버는 얼마나 최적화되었을까요?
앞서 간략하게 설명했듯이, 작은 배치 크기에서의 LLM 추론, 특히 디코드 시에는 장치 메모리에서 컴퓨팅 유닛으로 모델 파라미터를 얼마나 빨리 로드할 수 있는지에 따라 병목 현상이 발생합니다. 메모리 대역폭은 데이터 이동이 얼마나 빨리 발생하는지를 결정합니다. 기본 하드웨어의 활용도를 측정하기 위해 모델 대역폭 활용도(MBU)라는 새로운 지표를 도입합니다. MBU는 (달성된 메모리 대역폭) / (최대 메모리 대역폭)으로 정의되며, 여기서 달성된 메모리 대역폭은 ((총 모델 파라미터 크기 + KV 캐시 크기) / TPOT)입니다.
예를 들어, 16비트 정밀도로 실행되는 7B 매개변수 모델의 TPOT가 14ms라면, 이는 14GB의 매개변수를 14ms 동안 이동시키는 것으로 초당 1TB의 대역폭 사용량을 의미합니다. 머신의 최대 대역폭이 2TB/sec라면, 우리는 50%의 MBU로 실행 중인 것입니다. 단순화를 위해, 이 예제에서는 배치 크기가 작고 시퀀스 길이가 짧을 때 작은 KV 캐시 크기는 무시합니다. 100%에 가까운 MBU 값은 추론 시스템이 사용 가능한 메모리 대역폭을 효과적으로 활용하고 있음을 의미합니다. MBU는 또한 서로 다른 추론 시스템(하드웨어 + 소프트웨어)을 정규화된 방식으로 비교하는 데 유용합니다. MBU는 계산 집약적인 환경에서 중요한 지표인 모델 연산 활용률(MFU; PaLM 논문에서 소개됨) 지표를 보완합니다.
그림 1은 루프라인 플롯과 유 사한 플롯에서 MBU를 시각적으로 표현한 것입니다. 주황색 음영 영역의 기울어진 실선은 메모리 대역폭이 100% 포화되었을 때 가능한 최대 처리량을 보여줍니다. 그러나 실제로는 낮은 배치 크기(흰색 점)의 경우 관찰된 성능이 최대치보다 낮으며, 얼마나 낮은지가 MBU의 척도입니다. 큰 배치 크기(노란색 영역)의 경우 시스템은 계산 집약적이며, 가능한 최대 처리량 대비 달성된 처리량 비율은 모델 연산 활용률(MFU)로 측정됩니다.

MBU와 MFU는 주어진 하드웨어 설정에서 추론 속도를 얼마나 더 높일 수 있는지를 결정합니다. 그림 2는 TensorRT-LLM 기반 추론 서버에서 다양한 수준의 텐서 병렬 처리에 대한 측정된 MBU를 보여줍니다. 최대 메모리 대역폭 활용률은 크고 연속적인 메모리 청크를 전송할 때 달성됩니다. MPT-7B와 같이 더 작은 모델이 여러 GPU에 분산될 때, 각 GPU에서 더 작은 메모리 청크를 이동시키므로 MBU가 낮아지는 것을 관찰할 수 있습니다.
