Best Practices für die Optimierung der Inferenz von Large Language Models mit GPUs in der Google Kubernetes Engine (GKE)

Google Kubernetes Engine (GKE) bietet eine detaillierte Kontrolle für die Inferenz von Large Language Models (LLM) bei optimaler Leistung und Kosten. In diesem Leitfaden werden Best Practices für die Optimierung der Inferenz und Bereitstellung offener LLMs mit GPUs in der GKE mithilfe der Bereitstellungs-Frameworks vLLM und Text Generation Inference (TGI) beschrieben.

Eine zusammenfassende Checkliste mit den Best Practices finden Sie in der Zusammenfassung der Checkliste.

Eine konsolidierte Übersicht über alle GKE-Best Practices finden Sie unter Best Practices für GKE.

Ziele

Dieser Leitfaden richtet sich an Kunden von generativer KI, neue oder bestehende GKE-Nutzer, ML-Entwickler und LLMOps-Entwickler (DevOps), die ihre LLM-Arbeitslasten mit GPUs mit Kubernetes optimieren möchten.

Am Ende dieses Leitfadens können Sie:

  • Wählen Sie Techniken zur LLM-Optimierung nach dem Training aus, darunter Quantisierung, Tensorparallelität und Speicheroptimierung.
  • Wägen Sie die allgemeinen Vor- und Nachteile ab, wenn Sie diese Optimierungstechniken in Betracht ziehen.
  • Offene LLM-Modelle in GKE mit Bereitstellungs-Frameworks wie vLLM oder TGI mit aktivierten Optimierungseinstellungen bereitstellen.

Übersicht über Techniken zur Optimierung der LLM-Bereitstellung

Im Gegensatz zu Nicht-KI-Arbeitslasten weisen LLM-Arbeitslasten aufgrund ihrer Abhängigkeit von Matrixmultiplikationsvorgängen in der Regel eine höhere Latenz und einen geringeren Durchsatz auf. Um die LLM-Inferenzleistung zu verbessern, können Sie spezielle Hardwarebeschleuniger (z. B. GPUs und TPUs) und optimierte Bereitstellungs-Frameworks verwenden.

Sie können eine oder mehrere der folgenden Best Practices anwenden, um die Latenz von LLM-Arbeitslasten zu verringern und gleichzeitig den Durchsatz und die Kosteneffizienz zu verbessern:

In den Beispielen in diesem Leitfaden wird das Gemma 7B-LLM zusammen mit den vLLM- oder TGI-Bereitstellungs-Frameworks verwendet, um diese Best Practices anzuwenden. Die beschriebenen Konzepte und Funktionen sind jedoch auf die meisten gängigen offenen LLMs anwendbar.

Hinweise

Bevor Sie die Beispiele in diesem Leitfaden ausprobieren, müssen Sie die folgenden erforderlichen Aufgaben ausführen:

  1. Folgen Sie der Anleitung in diesen Leitfäden, um Zugriff auf das Gemma-Modell zu erhalten, Ihre Umgebung vorzubereiten und Cloud de Confiance by S3NS Ressourcen zu erstellen und zu konfigurieren:

    Speichern Sie das Hugging Face-Zugriffstoken in Ihrem Kubernetes-Secret.

  2. Klonen Sie das Beispiel-Repository https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/ in Ihre lokale Entwicklungsumgebung.

  3. Ändern Sie Ihr Arbeitsverzeichnis in /kubernetes-engine-samples/ai-ml/llm-serving-gemma/:

Best Practice: Quantisierung

Quantisierung ist eine Technik, die mit der verlustbehafteten Bildkomprimierung vergleichbar ist. Sie reduziert die Modellgröße, indem Gewichte in Formaten mit geringerer Genauigkeit (8 Bit oder 4 Bit) dargestellt werden, wodurch der Speicherbedarf sinkt. Wie bei der Bildkomprimierung ist die Quantisierung jedoch mit einem Kompromiss verbunden: Eine geringere Modellgröße kann zu einer geringeren Genauigkeit führen.

Es gibt verschiedene Quantisierungsmethoden, die jeweils ihre eigenen Vor- und Nachteile haben. Für einige, z. B. AWQ und GPTQ, ist eine Vorquantisierung erforderlich. Sie sind auf Plattformen wie Hugging Face oder Kaggle verfügbar. Wenn Sie beispielsweise GPTQ auf das Llama-2-13B-Modell und AWQ auf das Gemma-7B-Modell anwenden, können Sie die Modelle auf einer einzelnen L4-GPU anstelle von zwei L4-GPUs ohne Quantisierung bereitstellen.

Sie können die Quantisierung auch mit Tools wie AutoAWQ und AutoGPTQ durchführen. Diese Methoden können die Latenz und den Durchsatz verbessern. Im Gegensatz dazu erfordern Techniken mit EETQ und der Bibliothek bitsandbytes für die Quantisierung keine vorab quantisierten Modelle. Daher können sie eine geeignete Wahl sein, wenn keine vorab quantisierten Versionen verfügbar sind.

Die beste Quantisierungstechnik hängt von Ihren spezifischen Zielen und der Kompatibilität der Technik mit dem Serving-Framework ab, das Sie verwenden möchten. Weitere Informationen finden Sie im Quantisierungsleitfaden von Hugging Face.

Wählen Sie einen dieser Tabs aus, um ein Beispiel für die Anwendung der Quantisierung mit den TGI- oder vLLM-Frameworks zu sehen:

TGI

GKE unterstützt die folgenden Quantisierungsoptionen mit TGI:

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

Für die AWQ- und GPTQ-Quantisierungsmethoden sind vorab quantisierte Modelle erforderlich, während die EETQ- und bitsandbytes-Quantisierung auf jedes Modell angewendet werden kann. Weitere Informationen zu diesen Optionen finden Sie in diesem Hugging Face-Artikel.

Wenn Sie die Quantisierung verwenden möchten, legen Sie beim Starten des Modell-Servers den Parameter -–quantize fest.

Das folgende Snippet zeigt, wie Sie Gemma 7B mit bitsandbytes-Quantisierung mit TGI in GKE optimieren.

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

Verwenden Sie den folgenden Befehl, um diese Konfiguration anzuwenden:

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

vLLM

GKE unterstützt die folgenden Quantisierungsoptionen mit vLLM:

Wenn Sie die Modellquantisierung mit vLLM verwenden möchten, müssen die Modelle vorquantisiert werden. Legen Sie beim Starten der Laufzeit den Parameter –quantization fest.

Das folgende Snippet zeigt, wie Sie das Gemma 7B-Modell mit der awq-Quantisierung mithilfe von vLLM in der GKE optimieren:

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

Verwenden Sie den folgenden Befehl, um diese Konfiguration anzuwenden:

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

Latenz durch KV-Cache-Quantisierung verbessern

Mit der FP8 E5M2-Quantisierung des KV-Caches können Sie den Speicherbedarf des KV-Caches erheblich verringern und die Latenz verbessern, insbesondere bei großen Batchgrößen. Dies verringert jedoch die Genauigkeit der Inferenz.

Wenn Sie die FP8 E5M2-Quantisierung für den KV-Cache aktivieren möchten, legen Sie den Parameter --kv-cache-dtype fp8_e5m2 fest:

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

Verwenden Sie den folgenden Befehl, um diese Konfiguration anzuwenden:

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

Best Practice: Tensor-Parallelität

Tensor-Parallelität ist eine Technik, die die Rechenlast auf mehrere GPUs verteilt. Dies ist wichtig, wenn Sie große Modelle ausführen, die die Arbeitsspeicherkapazität einer einzelnen GPU überschreiten. Dieser Ansatz kann kostengünstiger sein, da Sie mehrere erschwingliche GPUs anstelle einer einzelnen teuren GPU verwenden können. Außerdem kann der Durchsatz der Modellinferenz erhöht werden. Beim Tensor-Parallelismus wird die Tatsache genutzt, dass Tensor-Operationen unabhängig voneinander für kleinere Datenblöcke ausgeführt werden können.

Weitere Informationen zu dieser Technik finden Sie im Leitfaden zur Tensorparallelität von Hugging Face.

Wählen Sie einen dieser Tabs aus, um ein Beispiel für die Anwendung von Tensorparallelität mit den TGI- oder vLLM-Frameworks zu sehen:

TGI

Bei TGI verwendet die Bereitstellungs-Laufzeit standardmäßig alle GPUs, die für den Pod verfügbar sind. Sie können die Anzahl der zu verwendenden GPUs festlegen, indem Sie den Parameter --num-shard mit der Anzahl der GPUs als Wert angeben.

Eine Liste der Modelle, die für Tensorparallelität unterstützt werden, finden Sie in der Hugging Face-Dokumentation.

Das folgende Snippet zeigt, wie Sie das für die Anleitung abgestimmte Modell Gemma 7B mit Tensor-Parallelität und zwei L4-GPUs optimieren:

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

Verwenden Sie den folgenden Befehl, um diese Konfiguration anzuwenden:

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

Wenn Sie diesen Befehl in GKE Autopilot-Clustern ausführen, wird ein Pod mit Mindestanforderungen an Ressourcen von 21 vCPUs und 78 GiB Arbeitsspeicher erstellt.

vLLM

vLLM unterstützt die verteilte Tensor-parallele Inferenz. vLLM aktiviert die Funktion standardmäßig, wenn mehr als eine GPU verfügbar ist.

Das folgende Snippet zeigt, wie Sie das auf Anweisungen abgestimmte Gemma 7B-Modell mithilfe von Tensorparallelität und zwei L4-GPUs optimieren können:

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

Verwenden Sie den folgenden Befehl, um diese Konfiguration anzuwenden:

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

In GKE Autopilot-Clustern wird durch Ausführen dieses Befehls ein Pod mit Mindestressourcenanforderungen von 21 vCPUs und 78 GiB Arbeitsspeicher erstellt.

Best Practice: Optimierung des Modellspeichers

Die Optimierung der Arbeitsspeichernutzung von LLMs ist entscheidend für eine effiziente Inferenz. In diesem Abschnitt werden Optimierungsstrategien für die Aufmerksamkeitsebene vorgestellt, z. B. Paged Attention und Flash Attention. Diese Strategien verbessern die Speichereffizienz, was längere Eingabesequenzen und eine geringere Inaktivitätszeit der GPU ermöglicht. In diesem Abschnitt wird auch beschrieben, wie Sie die Größe der Modellein- und ‑ausgabe an die Arbeitsspeicherbeschränkungen anpassen und für bestimmte Bereitstellungsframeworks optimieren können.

Optimierung der Aufmerksamkeitsebene

Self-Attention-Ebenen ermöglichen es Modellen, den Kontext bei Sprachverarbeitungsaufgaben zu verstehen, da sich die Bedeutung von Wörtern je nach Kontext ändern kann. In diesen Layern werden jedoch Gewichte für Eingabetokens, Schlüssel (K) und Werte (V) im GPU-vRAM gespeichert. Mit zunehmender Länge der Eingabesequenz führt dies zu einem quadratischen Wachstum der Größe und der Rechenzeit.

Die Verwendung von KV-Caching ist besonders nützlich, wenn Sie mit langen Eingabesequenzen arbeiten, bei denen der Overhead der Self-Attention erheblich sein kann. Durch diesen Optimierungsansatz wird die Rechenleistung auf eine lineare Komplexität reduziert.

Spezifische Techniken zur Optimierung von Aufmerksamkeitsmechanismen in LLMs sind:

  • Paged Attention: Paged Attention verbessert die Speicherverwaltung für große Modelle und lange Eingabesequenzen durch Auslagerungstechniken, ähnlich dem virtuellen Arbeitsspeicher des Betriebssystems. Dadurch werden Fragmentierung und Duplizierung im KV-Cache effektiv reduziert, was längere Eingabesequenzen ermöglicht, ohne dass der GPU-Arbeitsspeicher aufgebraucht wird.
  • Flash Attention: Flash Attention verringert GPU-Arbeitsspeicherengpässe, indem die Datenübertragungen zwischen GPU-RAM und L1-Cache während der Tokengenerierung minimiert werden. Dadurch werden Leerlaufzeiten für Rechenkerne vermieden, was die Inferenz- und Trainingsleistung für GPUs deutlich verbessert.

Feinabstimmung der Modelleingabe und -ausgabe

Die Arbeitsspeicheranforderungen hängen von der Größe der Ein- und Ausgabe ab. Längere Ausgaben und mehr Kontext erfordern mehr Ressourcen, während kürzere Ausgaben und weniger Kontext Kosten sparen können, da eine kleinere, günstigere GPU verwendet wird.

Wählen Sie einen dieser Tabs aus, um ein Beispiel für die Feinabstimmung der Arbeitsspeicheranforderungen der Modelleingabe- und -ausgabe in den TGI- oder vLLM-Frameworks zu sehen:

TGI

Die TGI-Bereitstellungslaufzeit prüft die Arbeitsspeicheranforderungen beim Start und startet nicht, wenn der maximal mögliche Modellspeicherbedarf nicht in den verfügbaren GPU-Arbeitsspeicher passt. Durch diese Prüfung werden Abstürze aufgrund von Arbeitsspeichermangel bei arbeitsspeicherintensiven Arbeitslasten vermieden.

GKE unterstützt die folgenden TGI-Parameter zum Optimieren der Arbeitsspeicheranforderungen von Modellen:

Im folgenden Snippet sehen Sie, wie Sie ein Gemma 7B-Modell, das auf Anweisungen abgestimmt ist, mit einer einzelnen L4-GPU und den Parametereinstellungen --max-total-tokens=3072, --max-batch-prefill-tokens=512, --max-input-length=512 bereitstellen können:

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

Verwenden Sie den folgenden Befehl, um diese Konfiguration anzuwenden:

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

vLLM

Konfigurieren Sie in vLLM die Kontextlänge des Modells, die sich direkt auf die Größe des KV-Cache und die GPU-RAM-Anforderungen auswirkt. Kleinere Kontextlängen ermöglichen die Verwendung günstigerer GPUs. Der Standardwert ist die maximale Anzahl von Tokens, die das Modell akzeptiert. Begrenzen Sie die maximale Kontextlänge bei Bedarf mit --max-model-len MAX_MODEL_LEN.

So übersteigt z. B. das für Gemma 7B optimierte Modell mit einer Standardkontextlänge von 8.192 die Arbeitsspeicherkapazität einer einzelnen NVIDIA L4-GPU. Wenn Sie auf einem L4-Gerät bereitstellen möchten, begrenzen Sie die kombinierte Länge von Prompts und Ausgaben, indem Sie --max-model-len auf einen Wert unter 640 festlegen. Durch diese Anpassung kann das Modell trotz seiner großen Standardkontextlänge auf einer einzelnen L4-GPU ausgeführt werden.

Verwenden Sie das folgende Snippet, um mit dem geänderten Tokenlimit bereitzustellen:

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

Verwenden Sie den folgenden Befehl, um diese Konfiguration anzuwenden:

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

Zusammenfassung der Checkliste

Optimierungsziel Übung
Latenz
  • Leistungsstarke GPUs priorisieren: Sie sollten ein Upgrade auf GPUs mit höherer Rechenleistung und höherem Arbeitsspeicher-E/A-Durchsatz in Betracht ziehen.
  • Quantisierung: Techniken wie AWQ können die Latenz verbessern, aber achten Sie auf mögliche Kompromisse bei der Genauigkeit.
Durchsatz
  • Horizontal skalieren: Erhöhen Sie die Anzahl der Serving-Replikate (Pods), um die Arbeitslast zu verteilen.
  • Tensor-Parallelität verwenden: Verwenden Sie für große Modelle, die die Kapazität einer einzelnen GPU überschreiten, Tensor-Parallelität, um Berechnungen auf mehrere GPUs zu verteilen. Bei kleineren Modellen sollten Sie mehrere Replikate mit Tensorparallelität von „1“ in Betracht ziehen, um Mehraufwand zu vermeiden.
  • Batchanfragen und Quantisierung: Kombinieren Sie Anfragen und testen Sie Quantisierungstechniken, die eine akzeptable Genauigkeit beibehalten.
Kosteneffizienz
  • Kleinere Modelle auswählen: Wählen Sie Modelle innerhalb einer Familie aus, die Ihren Ressourcenbeschränkungen und Ihrem Budget entsprechen.
  • Quantisierung anwenden: Verwenden Sie die Quantisierung, um den Speicherbedarf zu reduzieren, insbesondere bei größeren Modellen.
  • Kontextlänge begrenzen: Begrenzen Sie die Kontextlänge, um die Arbeitsspeichernutzung weiter zu reduzieren und die Ausführung auf kleineren, kostengünstigeren GPUs zu ermöglichen.

Nächste Schritte