Google Kubernetes Engine(GKE)에서 GPU를 사용하여 대규모 언어 모델 추론을 최적화하기 위한 권장사항


Google Kubernetes Engine(GKE)은 최적의 성능과 비용으로 대규모 언어 모델(LLM) 추론에 대한 세분화된 제어 기능을 지원합니다. 이 가이드에서는 vLLM텍스트 생성 추론(TGI) 서빙 프레임워크를 사용하여 GKE에서 GPU를 통해 개방형 LLM의 추론 및 제공을 최적화하기 위한 권장사항을 설명합니다.

모든 권장사항을 요약한 체크리스트는 체크리스트 요약을 참조하세요.

목표

이 가이드는 Kubernetes에서 GPU를 사용하여 LLM 워크로드를 최적화하는 데 관심이 있는 생성형 AI 고객, 신규 또는 기존 GKE 사용자, ML 엔지니어, LLMOps(DevOps) 엔지니어를 대상으로 합니다.

이 가이드가 끝나면 다음을 수행할 수 있습니다.

  • 양자화, 텐서 동시 로드, 메모리 최적화를 포함하여 학습 후 LLM 최적화 기법을 선택합니다.
  • 이러한 최적화 기법을 고려할 때 높은 수준의 절충을 고려합니다.
  • 최적화 설정이 사용 설정된 vLLM 또는 TGI와 같은 서빙 프레임워크를 사용하여 GKE에 개방형 LLM 모델을 배포합니다.

LLM 서빙 최적화 기법 개요

AI가 아닌 워크로드와 달리 LLM 워크로드는 일반적으로 행렬 곱셈 연산에 대한 의존성으로 인해 지연 시간이 높고 처리량이 낮습니다. LLM 추론 성능을 개선하려면 특수 하드웨어 가속기(예: GPU 및 TPU)와 최적화된 게재 프레임워크를 사용하면 됩니다.

다음 권장사항 중 하나 이상을 적용하여 처리량과 비용 효율성을 개선하는 동시에 LLM 워크로드 지연 시간을 줄일 수 있습니다.

이 가이드의 예시에서는 Gemma 7B LLM을 vLLM 또는 TGI 서빙 프레임워크와 함께 사용하여 이러한 권장사항을 적용합니다. 하지만 설명된 개념과 기능은 가장 인기 있는 개방형 LLM에 적용될 수 있습니다.

시작하기 전에

이 가이드의 예시를 시도하기 전에 다음 기본 요건 태스크를 완료합니다.

  1. 다음 가이드의 안내에 따라 Gemma 모델에 액세스하고, 환경을 준비하고, Google Cloud 리소스를 만들고 구성합니다.

    Hugging Face 액세스 토큰을 Kubernetes 보안 비밀에 저장해야 합니다.

  2. https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/ 샘플 저장소를 로컬 개발 환경에 클론합니다.

  3. 작업 디렉터리를 /kubernetes-engine-samples/ai-ml/llm-serving-gemma/으로 변경합니다.

권장사항: 양자화

양자화는 손실(lossy) 이미지 압축과 유사한 기술로, 낮은 정밀도 형식(8비트 또는 4비트)으로 가중치를 표현하여 모델 크기를 줄여 메모리 요구사항을 낮춰줍니다. 그러나 이미지 압축과 마찬가지로 양자화에는 단점이 있습니다. 모델 크기를 줄이면 정확성이 떨어질 수 있습니다.

다양한 양자화 방법이 존재하며 각각 고유한 장단점이 있습니다. AWQ 및 GPTQ와 같은 일부는 사전 양자화가 필요하며 Hugging Face 또는 Kaggle과 같은 플랫폼에서 사용할 수 있습니다. 예를 들어 Llama-2 13B 모델에 GPTQ를 적용하고 Gemma 7B 모델에 AWQ를 적용하면 양자화 없이 L4 GPU 2개 대신 단일 L4 GPU에서 모델을 제공할 수 있습니다.

AutoAWQAutoGPTQ와 같은 도구를 사용하여 양자화를 수행할 수도 있습니다. 이러한 메서드는 지연 시간과 처리량을 개선할 수 있습니다. 반면 EETQ 및 정규화에 bitsandbytes 라이브러리를 사용하는 기법은 사전 정규화된 모델이 필요하지 않으므로 사전 정규화된 버전을 사용할 수 없는 경우에 적합한 선택일 수 있습니다.

사용할 최적의 양자화 기법은 구체적인 목표와 기법이 사용하려는 게재 프레임워크와의 호환성에 따라 다릅니다. 자세한 내용은 Hugging Face의 양자화 가이드를 참조하세요.

TGI 또는 vLLM 프레임워크를 사용하여 정규화를 적용하는 예시를 보려면 다음 탭 중 하나를 선택합니다.

TGI

GKE는 TGI를 통해 다음과 같은 양자화 옵션을 지원합니다.

  • awq
  • gptq
  • eetq
  • bitsandbytes
  • bitsandbytes-nf4
  • bitsandbytes-fp4

AWQ 및 GPTQ 양자화 방법에는 사전 양자화된 모델이 필요하지만 EETQ 및 bitsandbytes 양자화는 모든 모델에 적용할 수 있습니다. 이러한 옵션에 관한 자세한 내용은 이 Hugging Face 자료를 참고하세요.

양자화를 사용하려면 모델 서버를 시작할 때 -–quantize 매개변수를 설정합니다.

다음 스니펫은 GKE에서 TGI를 사용하여 bitsandbytes 양자화로 Gemma 7B를 최적화하는 방법을 보여줍니다.

args:
- --model-id=$(MODEL_ID)
- --num-shard=2
- --quantize=bitsandbytes

이 구성을 적용하려면 다음 명령어를 사용하세요.

kubectl apply -f tgi/tgi-7b-bitsandbytes.yaml

vLLM

GKE는 vLLM에서 다음과 같은 양자화 옵션을 지원합니다.

vLLM에서 모델 양자화를 사용하려면 모델을 사전 양자화해야 합니다. 런타임을 시작할 때 –quantization 매개변수를 설정합니다.

다음 스니펫은 GKE에서 vLLM을 사용하여 awq 양자화로 Gemma 7B 모델을 최적화하는 방법을 보여줍니다.

args:
- --model=$(MODEL_ID)
- --tensor-parallel-size=1
- --quantization=awq
env:
- name: MODEL_ID
  value: google/gemma-7b-AWQ
resources:
  requests:
    nvidia.com/gpu: 1
  limits:
    nvidia.com/gpu: 1

이 구성을 적용하려면 다음 명령어를 사용하세요.

kubectl apply -f vllm/vllm-7b-awq.yaml

KV 캐시 양자화를 사용하여 지연 시간 개선

특히 대규모 배치 크기의 경우 FP8 E5M2 KV 캐시 양자화를 사용하여 KV 캐시 메모리 사용 공간을 크게 줄이고 지연 시간을 개선할 수 있습니다. 하지만 이렇게 하면 추론 정확성이 떨어집니다.

FP8 E5M2 KV 캐시 양자화를 사용 설정하려면 --kv-cache-dtype fp8_e5m2 매개변수를 설정하세요.

args:
- --model=$(MODEL_ID)
- --tensor-parallel-size=1
- --kv-cache-dtype=fp8_e5m2
- --max-model-len=1200
resources:
  requests:
    cpu: "2"
    memory: "25Gi"
    ephemeral-storage: "25Gi"
    nvidia.com/gpu: 1
  limits:
    cpu: "2"
    memory: "25Gi"
    ephemeral-storage: "25Gi"
    nvidia.com/gpu: 1

이 구성을 적용하려면 다음 명령어를 사용하세요.

kubectl apply -f vllm/vllm-7b-kvcache.yaml

권장사항: 텐서 동시 로드

텐서 동시 로드는 여러 GPU에 계산 부하를 분산하는 기법으로, 단일 GPU 메모리 용량을 초과하는 대규모 모델을 실행할 때 필수적입니다. 이 접근 방식은 비용이 많이 드는 단일 GPU 대신 여러 저렴한 GPU를 사용할 수 있으므로 더 비용 효율적일 수 있습니다. 모델 추론 처리량도 향상될 수 있습니다. 텐서 병렬 처리는 텐서 작업이 더 작은 데이터 청크에서 독립적으로 실행될 수 있다는 사실을 활용합니다.

이 기법에 대한 자세한 내용은 Hugging Face의 텐서 동시 로드 가이드를 참조하세요.

TGI 또는 vLLM 프레임워크를 사용하여 텐서 동시 로드를 적용하는 예시를 보려면 다음 탭 중 하나를 선택합니다.

TGI

TGI를 사용하면 제공 런타임이 기본적으로 포드에서 사용할 수 있는 모든 GPU를 사용합니다. GPU 수를 값으로 --num-shard 매개변수를 지정하여 사용할 GPU 수를 설정할 수 있습니다.

텐서 병렬 처리에 지원되는 모델 목록은 Hugging Face 문서를 참고하세요.

다음 스니펫은 텐서 동시 로드와 2개의 L4 GPU를 사용하여 Gemma 7B 명령 조정 모델을 최적화하는 방법을 보여줍니다.

args:
- --model-id=$(MODEL_ID)
- --num-shard=2

이 구성을 적용하려면 다음 명령어를 사용하세요.

kubectl apply -f tgi/tgi-7b-it-tensorparallelism.yaml

GKE Autopilot 클러스터에서 이 명령어를 실행하면 최소 리소스 요구사항이 vCPU 21개와 메모리 78GiB인 포드가 생성됩니다.

vLLM

vLLM은 분산 텐서 병렬 추론을 지원합니다. vLLM은 사용 가능한 GPU가 두 개 이상인 경우 기본적으로 이 기능을 사용 설정합니다.

다음 스니펫은 텐서 병렬 처리와 2개의 L4 GPU를 사용하여 Gemma 7B 명령 조정 모델을 최적화하는 방법을 보여줍니다.

args:
- --model=$(MODEL_ID)
- --tensor-parallel-size=2

이 구성을 적용하려면 다음 명령어를 사용하세요.

kubectl apply -f vllm/vllm-7b-it-tensorparallelism.yaml

GKE Autopilot 클러스터에서 이 명령어를 실행하면 최소 리소스 요구사항이 vCPU 21개와 메모리 78GiB인 포드가 생성됩니다.

권장사항: 모델 메모리 최적화

LLM의 메모리 사용량을 최적화하는 것은 효율적인 추론을 위해 매우 중요합니다. 이 섹션에서는 페이징된 어텐션 및 플래시 어텐션과 같은 어텐션 레이어 최적화 전략을 소개합니다. 이러한 전략은 메모리 효율성을 높여 입력 시퀀스를 늘리고 GPU 유휴 시간을 줄일 수 있습니다. 또한 이 섹션에서는 메모리 제약조건에 맞게 모델 입력 및 출력 크기를 조정하고 특정 서빙 프레임워크에 맞게 최적화하는 방법을 설명합니다.

주의 레이어 최적화

자체 주의 레이어를 사용하면 모델이 언어 처리 작업에서 문맥을 이해할 수 있습니다. 단어의 의미는 문맥에 따라 달라질 수 있기 때문입니다. 그러나 이러한 레이어는 입력 토큰 가중치, 키(K), 값(V)을 GPU vRAM에 저장합니다. 따라서 입력 시퀀스가 길어질수록 크기와 계산 시간이 이차적으로 증가합니다.

KV 캐싱은 자체 주의 오버헤드가 커질 수 있는 긴 입력 시퀀스를 처리할 때 특히 유용합니다. 이 최적화 접근 방법은 연산 처리를 선형적으로 줄여줍니다.

LLM에서 주의 메커니즘을 최적화하기 위한 구체적인 기술은 다음과 같습니다.

  • 페이지 어텐션: 페이지 어텐션은 OS 가상 메모리와 유사한 페이징 기법을 사용하여 대형 모델 및 긴 입력 시퀀스의 메모리 관리를 개선합니다. 이렇게 하면 KV 캐시의 파편화와 중복이 효과적으로 줄어들어 GPU 메모리가 부족해지지 않고 더 긴 입력 시퀀스를 사용할 수 있습니다.
  • 플래시 어텐션: 플래시 어텐션은 토큰 생성 중에 GPU RAM과 L1 캐시 간의 데이터 전송을 최소화하여 GPU 메모리 병목 현상을 줄입니다. 이렇게 하면 코어 컴퓨팅의 유휴 시간이 없어 GPU의 추론 및 학습 성능이 크게 향상됩니다.

모델 입력 및 출력 크기 조정

메모리 요구사항은 입력 및 출력 크기에 따라 다릅니다. 출력이 길고 컨텍스트가 많을수록 더 많은 리소스가 필요하고, 출력이 짧고 컨텍스트가 작으면 더 작고 저렴한 GPU를 사용하여 비용을 절약할 수 있습니다.

TGI 또는 vLLM 프레임워크에서 모델 입력 및 출력 메모리 요구사항을 조정하는 예시를 보려면 다음 탭 중 하나를 선택합니다.

TGI

TGI 제공 런타임은 시작 중에 메모리 요구사항을 확인하고 가능한 최대 모델 메모리 사용량이 사용 가능한 GPU 메모리에 맞지 않으면 시작하지 않습니다. 이 검사는 메모리 집약적인 워크로드에서 메모리 부족(OOM) 비정상 종료를 제거합니다.

GKE는 모델 메모리 요구사항을 최적화하기 위해 다음 TGI 매개변수를 지원합니다.

다음 스니펫은 매개변수 설정 --max-total-tokens=3072, --max-batch-prefill-tokens=512, --max-input-length=512를 사용하여 단일 L4 GPU로 Gemma 7B 명령 조정 모델을 서빙하는 방법을 보여줍니다.

args:
- --model-id=$(MODEL_ID)
- --num-shard=1
- --max-total-tokens=3072 
- --max-batch-prefill-tokens=512
- --max-input-length=512
env:
- name: MODEL_ID
  value: google/gemma-7b

이 구성을 적용하려면 다음 명령어를 사용하세요.

kubectl apply -f tgi/tgi-7b-token.yaml

vLLM

vLLM에서 KV 캐시 크기 및 GPU RAM 요구사항에 직접 영향을 미치는 모델의 컨텍스트 길이를 구성합니다. 컨텍스트 길이가 짧을수록 더 저렴한 GPU를 사용할 수 있습니다. 기본값은 모델이 허용하는 최대 토큰 수입니다. 필요한 경우 --max-model-len MAX_MODEL_LEN를 사용하여 최대 컨텍스트 길이를 제한합니다.

예를 들어 기본 컨텍스트 길이가 8192인 Gemma 7B 명령 조정 모델은 단일 NVIDIA L4 GPU의 메모리 용량을 초과합니다. L4에 배포하려면 --max-model-len를 640 미만의 값으로 설정하여 프롬프트 및 출력을 통합한 길이를 제한합니다. 이 조정을 통해 기본 컨텍스트 길이가 길더라도 단일 L4 GPU에서 모델을 실행할 수 있습니다.

수정된 토큰 한도를 사용하여 배포하려면 다음 스니펫을 사용합니다.

args:
- --model=$(MODEL_ID)
- --tensor-parallel-size=1
- --max-model-len=600

이 구성을 적용하려면 다음 명령어를 사용하세요.

kubectl apply -f vllm/vllm-7b-token.yaml

체크리스트 요약

최적화 목표 연습
지연 시간
  • 강력한 GPU 우선순위 지정: 더 높은 연산 기능과 메모리 I/O 처리량을 제공하는 GPU로 업그레이드하는 것이 좋습니다.
  • 양자화 살펴보기: AWQ와 같은 기법은 지연 시간을 개선할 수 있지만 잠재적인 정확도 손실을 유의해야 합니다.
처리량
  • 수평 확장: 서비스 복제본(포드) 수를 늘려 워크로드를 분산합니다.
  • 텐서 동시 로드 사용: 단일 GPU 용량을 초과하는 대규모 모델의 경우 텐서 동시 로드를 사용하여 여러 GPU에 걸쳐 계산을 분산합니다. 소형 모델의 경우 오버헤드를 방지하기 위해 텐서 병렬 처리가 `1`인 복제본을 여럿 고려하세요.
  • 요청 일괄 처리 및 양자화: 요청을 결합하고 허용 가능한 정확성을 유지하는 양자화 기법을 살펴봅니다.
비용 효율성
  • 더 작은 모델 선택: 계열 내에서 리소스 제약조건 및 예산에 맞는 모델을 선택합니다.
  • 양자화 적용: 양자화를 사용하여 메모리 요구사항을 줄입니다(특히 대규모 모델을 처리할 때).
  • 컨텍스트 길이 제한: 메모리 사용량을 더욱 줄이고 더 작고 비용 효율적인 GPU에서 실행을 사용 설정하도록 컨텍스트 길이를 제한합니다.

다음 단계