Menyediakan LLM dengan beberapa GPU di GKE


Tutorial ini menunjukkan cara menyajikan model bahasa besar (LLM) dengan GPU di Google Kubernetes Engine (GKE). Tutorial ini membuat cluster GKE yang menggunakan beberapa GPU L4 dan menyiapkan infrastruktur GKE untuk menyalurkan salah satu model berikut:

Bergantung pada format data model, jumlah GPU bervariasi. Dalam tutorial ini, setiap model menggunakan dua GPU L4. Untuk mempelajari lebih lanjut, lihat Menghitung jumlah GPU.

Sebelum menyelesaikan tutorial ini di GKE, sebaiknya Anda mempelajari Tentang GPU di GKE.

Tujuan

Tutorial ini ditujukan bagi engineer MLOps atau DevOps, atau administrator platform yang ingin menggunakan kemampuan orkestrasi GKE untuk menyajikan LLM.

Tutorial ini membahas langkah-langkah berikut:

  1. Membuat cluster dan kumpulan node.
  2. Siapkan beban kerja Anda.
  3. Deploy workload Anda.
  4. Berinteraksi dengan antarmuka LLM.

Sebelum memulai

Sebelum memulai, pastikan Anda telah menjalankan tugas berikut:

  • Aktifkan Google Kubernetes Engine API.
  • Aktifkan Google Kubernetes Engine API
  • Jika ingin menggunakan Google Cloud CLI untuk tugas ini, instal lalu initialize gcloud CLI. Jika sebelumnya Anda telah menginstal gcloud CLI, dapatkan versi terbaru dengan menjalankan gcloud components update.
  • Jika Anda ingin menggunakan model Llama 2 70b, pastikan Anda memiliki hal berikut:

Menyiapkan lingkungan Anda

  1. Di konsol Google Cloud, mulai instance Cloud Shell:
    Buka Cloud Shell

  2. Tetapkan variabel lingkungan default:

    gcloud config set project PROJECT_ID
    export PROJECT_ID=$(gcloud config get project)
    export REGION=us-central1
    

    Ganti PROJECT_ID dengan project ID Google Cloud Anda.

Membuat cluster GKE dan node pool

Anda dapat menayangkan LLM di GPU dalam GKE Autopilot atau cluster Standar. Sebaiknya gunakan cluster Autopilot untuk mendapatkan pengalaman Kubernetes yang terkelola sepenuhnya. Untuk memilih mode operasi GKE yang paling sesuai dengan beban kerja Anda, lihat Memilih mode operasi GKE.

Autopilot

  1. Jalankan perintah berikut di Cloud Shell:

    gcloud container clusters create-auto l4-demo \
      --project=${PROJECT_ID} \
      --region=${REGION} \
      --release-channel=rapid
    

    GKE membuat cluster Autopilot dengan node CPU dan GPU seperti yang diminta oleh beban kerja yang di-deploy.

  2. Konfigurasi kubectl untuk berkomunikasi dengan cluster Anda:

    gcloud container clusters get-credentials l4-demo --region=${REGION}
    

Standar

  1. Di Cloud Shell, jalankan perintah berikut untuk membuat cluster Standar yang menggunakan Workload Identity Federation for GKE:

    gcloud container clusters create l4-demo --location ${REGION} \
      --workload-pool ${PROJECT_ID}.svc.id.goog \
      --enable-image-streaming \
      --node-locations=$REGION-a \
      --workload-pool=${PROJECT_ID}.svc.id.goog \
      --machine-type n2d-standard-4 \
      --num-nodes 1 --min-nodes 1 --max-nodes 5 \
      --release-channel=rapid
    

    Pembuatan cluster memerlukan waktu beberapa menit.

  2. Jalankan perintah berikut guna membuat kumpulan node untuk cluster Anda:

    gcloud container node-pools create g2-standard-24 --cluster l4-demo \
      --accelerator type=nvidia-l4,count=2,gpu-driver-version=latest \
      --machine-type g2-standard-24 \
      --enable-autoscaling --enable-image-streaming \
      --num-nodes=0 --min-nodes=0 --max-nodes=3 \
      --node-locations $REGION-a,$REGION-c --region $REGION --spot
    

    GKE membuat resource berikut untuk LLM:

    • Cluster Google Kubernetes Engine (GKE) Standard edisi publik.
    • Kumpulan node dengan jenis mesin g2-standard-24 yang diperkecil menjadi 0 node. Anda tidak akan dikenai biaya untuk GPU apa pun hingga Anda meluncurkan Pod. yang meminta GPU. Kumpulan node ini menyediakan Spot VM, yang harganya lebih rendah daripada VM Compute Engine standar default dan tidak memberikan jaminan ketersediaan. Anda dapat menghapus flag --spot dari perintah ini, dan pemilih node cloud.google.com/gke-spot dalam konfigurasi text-generation-inference.yaml untuk menggunakan VM on-demand.
  3. Konfigurasi kubectl untuk berkomunikasi dengan cluster Anda:

    gcloud container clusters get-credentials l4-demo --region=${REGION}
    

Menyiapkan beban kerja Anda

Bagian berikut menunjukkan cara menyiapkan beban kerja Anda bergantung pada model yang ingin Anda gunakan:

Llama 2 70b

  1. Tetapkan variabel lingkungan default:

    export HF_TOKEN=HUGGING_FACE_TOKEN
    

    Ganti HUGGING_FACE_TOKEN dengan token HuggingFace Anda.

  2. Buat rahasia Kubernetes untuk token HuggingFace:

    kubectl create secret generic l4-demo \
        --from-literal=HUGGING_FACE_TOKEN=${HF_TOKEN} \
        --dry-run=client -o yaml > hf-secret.yaml
    
  3. Terapkan manifes:

    kubectl apply -f hf-secret.yaml
    
  4. Buat manifes text-generation-inference.yaml berikut:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: llm
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: llm
      template:
        metadata:
          labels:
            app: llm
        spec:
          containers:
          - name: llm
            image: ghcr.io/huggingface/text-generation-inference:1.4.3
            resources:
              requests:
                cpu: "10"
                memory: "60Gi"
                nvidia.com/gpu: "2"
              limits:
                cpu: "10"
                memory: "60Gi"
                nvidia.com/gpu: "2"
            env:
            - name: MODEL_ID
              value: meta-llama/Llama-2-70b-chat-hf
            - name: NUM_SHARD
              value: "2"
            - name: PORT
              value: "8080"
            - name: QUANTIZE
              value: bitsandbytes-nf4
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: l4-demo
                  key: HUGGING_FACE_TOKEN
            volumeMounts:
              - mountPath: /dev/shm
                name: dshm
              - mountPath: /data
                name: ephemeral-volume
          volumes:
            - name: dshm
              emptyDir:
                  medium: Memory
            - name: ephemeral-volume
              ephemeral:
                volumeClaimTemplate:
                  metadata:
                    labels:
                      type: ephemeral
                  spec:
                    accessModes: ["ReadWriteOnce"]
                    storageClassName: "premium-rwo"
                    resources:
                      requests:
                        storage: 150Gi
          nodeSelector:
            cloud.google.com/gke-accelerator: "nvidia-l4"
            cloud.google.com/gke-spot: "true"

    Dalam manifes ini:

    • NUM_SHARD harus 2 karena model memerlukan dua GPU NVIDIA L4.
    • QUANTIZE disetel ke bitsandbytes-nf4 yang berarti bahwa model dimuat dalam 4 bit, bukan 32 bit. Hal ini memungkinkan GKE mengurangi jumlah memori GPU yang diperlukan dan meningkatkan kecepatan inferensi. Namun, akurasi model dapat menurun. Untuk mempelajari cara menghitung GPU yang akan diminta, lihat Menghitung jumlah GPU.
  5. Terapkan manifes:

    kubectl apply -f text-generation-inference.yaml
    

    Outputnya mirip dengan hal berikut ini:

    deployment.apps/llm created
    
  6. Verifikasi status model:

    kubectl get deploy
    

    Outputnya mirip dengan hal berikut ini:

    NAME          READY   UP-TO-DATE   AVAILABLE   AGE
    llm           1/1     1            1           20m
    
  7. Lihat log dari deployment yang berjalan:

    kubectl logs -l app=llm
    

    Outputnya mirip dengan hal berikut ini:

    {"timestamp":"2024-03-09T05:08:14.751646Z","level":"INFO","message":"Warming up model","target":"text_generation_router","filename":"router/src/main.rs","line_number":291}
    {"timestamp":"2024-03-09T05:08:19.961136Z","level":"INFO","message":"Setting max batch total tokens to 133696","target":"text_generation_router","filename":"router/src/main.rs","line_number":328}
    {"timestamp":"2024-03-09T05:08:19.961164Z","level":"INFO","message":"Connected","target":"text_generation_router","filename":"router/src/main.rs","line_number":329}
    {"timestamp":"2024-03-09T05:08:19.961171Z","level":"WARN","message":"Invalid hostname, defaulting to 0.0.0.0","target":"text_generation_router","filename":"router/src/main.rs","line_number":343}
    

Mixtral 8x7b

  1. Buat manifes text-generation-inference.yaml berikut:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: llm
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: llm
      template:
        metadata:
          labels:
            app: llm
        spec:
          containers:
          - name: llm
            image: ghcr.io/huggingface/text-generation-inference:1.4.3
            resources:
              requests:
                cpu: "5"
                memory: "40Gi"
                nvidia.com/gpu: "2"
              limits:
                cpu: "5"
                memory: "40Gi"
                nvidia.com/gpu: "2"
            env:
            - name: MODEL_ID
              value: mistralai/Mixtral-8x7B-Instruct-v0.1
            - name: NUM_SHARD
              value: "2"
            - name: PORT
              value: "8080"
            - name: QUANTIZE
              value: bitsandbytes-nf4
            volumeMounts:
              - mountPath: /dev/shm
                name: dshm
              - mountPath: /data
                name: ephemeral-volume
          volumes:
            - name: dshm
              emptyDir:
                  medium: Memory
            - name: ephemeral-volume
              ephemeral:
                volumeClaimTemplate:
                  metadata:
                    labels:
                      type: ephemeral
                  spec:
                    accessModes: ["ReadWriteOnce"]
                    storageClassName: "premium-rwo"
                    resources:
                      requests:
                        storage: 100Gi
          nodeSelector:
            cloud.google.com/gke-accelerator: "nvidia-l4"
            cloud.google.com/gke-spot: "true"

    Dalam manifes ini:

    • NUM_SHARD harus 2 karena model memerlukan dua GPU NVIDIA L4.
    • QUANTIZE disetel ke bitsandbytes-nf4 yang berarti bahwa model dimuat dalam 4 bit, bukan 32 bit. Hal ini memungkinkan GKE mengurangi jumlah memori GPU yang diperlukan dan meningkatkan kecepatan inferensi. Namun, hal ini dapat mengurangi akurasi model. Untuk mempelajari cara menghitung GPU yang akan diminta, lihat Menghitung jumlah GPU.
  2. Terapkan manifes:

    kubectl apply -f text-generation-inference.yaml
    

    Outputnya mirip dengan hal berikut ini:

    deployment.apps/llm created
    
  3. Verifikasi status model:

    watch kubectl get deploy
    

    Output-nya akan terlihat seperti berikut saat deployment siap. Untuk keluar dari smartwatch, ketik CTRL + C:

    NAME          READY   UP-TO-DATE   AVAILABLE   AGE
    llm           1/1     1            1           10m
    
  4. Lihat log dari deployment yang berjalan:

    kubectl logs -l app=llm
    

    Outputnya mirip dengan hal berikut ini:

    {"timestamp":"2024-03-09T05:08:14.751646Z","level":"INFO","message":"Warming up model","target":"text_generation_router","filename":"router/src/main.rs","line_number":291}
    {"timestamp":"2024-03-09T05:08:19.961136Z","level":"INFO","message":"Setting max batch total tokens to 133696","target":"text_generation_router","filename":"router/src/main.rs","line_number":328}
    {"timestamp":"2024-03-09T05:08:19.961164Z","level":"INFO","message":"Connected","target":"text_generation_router","filename":"router/src/main.rs","line_number":329}
    {"timestamp":"2024-03-09T05:08:19.961171Z","level":"WARN","message":"Invalid hostname, defaulting to 0.0.0.0","target":"text_generation_router","filename":"router/src/main.rs","line_number":343}
    

Falcon 40b

  1. Buat manifes text-generation-inference.yaml berikut:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: llm
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: llm
      template:
        metadata:
          labels:
            app: llm
        spec:
          containers:
          - name: llm
            image: ghcr.io/huggingface/text-generation-inference:1.4.3
            resources:
              requests:
                cpu: "10"
                memory: "60Gi"
                nvidia.com/gpu: "2"
              limits:
                cpu: "10"
                memory: "60Gi"
                nvidia.com/gpu: "2"
            env:
            - name: MODEL_ID
              value: tiiuae/falcon-40b-instruct
            - name: NUM_SHARD
              value: "2"
            - name: PORT
              value: "8080"
            - name: QUANTIZE
              value: bitsandbytes-nf4
            volumeMounts:
              - mountPath: /dev/shm
                name: dshm
              - mountPath: /data
                name: ephemeral-volume
          volumes:
            - name: dshm
              emptyDir:
                  medium: Memory
            - name: ephemeral-volume
              ephemeral:
                volumeClaimTemplate:
                  metadata:
                    labels:
                      type: ephemeral
                  spec:
                    accessModes: ["ReadWriteOnce"]
                    storageClassName: "premium-rwo"
                    resources:
                      requests:
                        storage: 175Gi
          nodeSelector:
            cloud.google.com/gke-accelerator: "nvidia-l4"
            cloud.google.com/gke-spot: "true"

    Dalam manifes ini:

    • NUM_SHARD harus 2 karena model memerlukan dua GPU NVIDIA L4.
    • QUANTIZE disetel ke bitsandbytes-nf4 yang berarti bahwa model dimuat dalam 4 bit, bukan 32 bit. Hal ini memungkinkan GKE mengurangi jumlah memori GPU yang diperlukan dan meningkatkan kecepatan inferensi. Namun, akurasi model dapat menurun. Untuk mempelajari cara menghitung GPU yang akan diminta, lihat Menghitung jumlah GPU.
  2. Terapkan manifes:

    kubectl apply -f text-generation-inference.yaml
    

    Outputnya mirip dengan hal berikut ini:

    deployment.apps/llm created
    
  3. Verifikasi status model:

    watch kubectl get deploy
    

    Output-nya akan terlihat seperti berikut saat deployment siap. Untuk keluar dari smartwatch, ketik CTRL + C:

    NAME          READY   UP-TO-DATE   AVAILABLE   AGE
    llm           1/1     1            1           10m
    
  4. Lihat log dari deployment yang berjalan:

    kubectl logs -l app=llm
    

    Outputnya mirip dengan hal berikut ini:

    {"timestamp":"2024-03-09T05:08:14.751646Z","level":"INFO","message":"Warming up model","target":"text_generation_router","filename":"router/src/main.rs","line_number":291}
    {"timestamp":"2024-03-09T05:08:19.961136Z","level":"INFO","message":"Setting max batch total tokens to 133696","target":"text_generation_router","filename":"router/src/main.rs","line_number":328}
    {"timestamp":"2024-03-09T05:08:19.961164Z","level":"INFO","message":"Connected","target":"text_generation_router","filename":"router/src/main.rs","line_number":329}
    {"timestamp":"2024-03-09T05:08:19.961171Z","level":"WARN","message":"Invalid hostname, defaulting to 0.0.0.0","target":"text_generation_router","filename":"router/src/main.rs","line_number":343}
    

Membuat Layanan jenis ClusterIP

  1. Buat manifes llm-service.yaml berikut:

    apiVersion: v1
    kind: Service
    metadata:
      name: llm-service
    spec:
      selector:
        app: llm
      type: ClusterIP
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
    
  2. Terapkan manifes:

    kubectl apply -f llm-service.yaml
    

Men-deploy antarmuka chat

Gunakan Gradio untuk membangun aplikasi web yang memungkinkan Anda berinteraksi dengan model Anda. Gradio adalah library Python yang memiliki wrapper ChatInterface yang membuat antarmuka pengguna untuk chatbot.

Llama 2 70b

  1. Buat file bernama gradio.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: gradio
      labels:
        app: gradio
    spec:
      strategy:
        type: Recreate
      replicas: 1
      selector:
        matchLabels:
          app: gradio
      template:
        metadata:
          labels:
            app: gradio
        spec:
          containers:
          - name: gradio
            image: us-docker.pkg.dev/google-samples/containers/gke/gradio-app:v1.0.0
            resources:
              requests:
                cpu: "512m"
                memory: "512Mi"
              limits:
                cpu: "1"
                memory: "512Mi"
            env:
            - name: CONTEXT_PATH
              value: "/generate"
            - name: HOST
              value: "http://llm-service"
            - name: LLM_ENGINE
              value: "tgi"
            - name: MODEL_ID
              value: "llama-2-70b"
            - name: USER_PROMPT
              value: "[INST] prompt [/INST]"
            - name: SYSTEM_PROMPT
              value: "prompt"
            ports:
            - containerPort: 7860
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: gradio-service
    spec:
      type: LoadBalancer
      selector:
        app: gradio
      ports:
      - port: 80
        targetPort: 7860
  2. Terapkan manifes:

    kubectl apply -f gradio.yaml
    
  3. Temukan alamat IP eksternal Layanan:

    kubectl get svc
    

    Outputnya mirip dengan hal berikut ini:

    NAME             TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
    gradio-service   LoadBalancer   10.24.29.197   34.172.115.35   80:30952/TCP   125m
    
  4. Salin alamat IP eksternal dari kolom EXTERNAL-IP.

  5. Lihat antarmuka model dari browser web Anda menggunakan alamat IP eksternal dengan port yang diekspos:

    http://EXTERNAL_IP
    

Mixtral 8x7b

  1. Buat file bernama gradio.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: gradio
      labels:
        app: gradio
    spec:
      strategy:
        type: Recreate
      replicas: 1
      selector:
        matchLabels:
          app: gradio
      template:
        metadata:
          labels:
            app: gradio
        spec:
          containers:
          - name: gradio
            image: us-docker.pkg.dev/google-samples/containers/gke/gradio-app:v1.0.0
            resources:
              requests:
                cpu: "512m"
                memory: "512Mi"
              limits:
                cpu: "1"
                memory: "512Mi"
            env:
            - name: CONTEXT_PATH
              value: "/generate"
            - name: HOST
              value: "http://llm-service"
            - name: LLM_ENGINE
              value: "tgi"
            - name: MODEL_ID
              value: "mixtral-8x7b"
            - name: USER_PROMPT
              value: "[INST] prompt [/INST]"
            - name: SYSTEM_PROMPT
              value: "prompt"
            ports:
            - containerPort: 7860
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: gradio-service
    spec:
      type: LoadBalancer
      selector:
        app: gradio
      ports:
      - port: 80
        targetPort: 7860
  2. Terapkan manifes:

    kubectl apply -f gradio.yaml
    
  3. Temukan alamat IP eksternal Layanan:

    kubectl get svc
    

    Outputnya mirip dengan hal berikut ini:

    NAME             TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
    gradio-service   LoadBalancer   10.24.29.197   34.172.115.35   80:30952/TCP   125m
    
  4. Salin alamat IP eksternal dari kolom EXTERNAL-IP.

  5. Lihat antarmuka model dari browser web Anda menggunakan alamat IP eksternal dengan port yang diekspos:

    http://EXTERNAL_IP
    

Falcon 40b

  1. Buat file bernama gradio.yaml:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: gradio
      labels:
        app: gradio
    spec:
      strategy:
        type: Recreate
      replicas: 1
      selector:
        matchLabels:
          app: gradio
      template:
        metadata:
          labels:
            app: gradio
        spec:
          containers:
          - name: gradio
            image: us-docker.pkg.dev/google-samples/containers/gke/gradio-app:v1.0.0
            resources:
              requests:
                cpu: "512m"
                memory: "512Mi"
              limits:
                cpu: "1"
                memory: "512Mi"
            env:
            - name: CONTEXT_PATH
              value: "/generate"
            - name: HOST
              value: "http://llm-service"
            - name: LLM_ENGINE
              value: "tgi"
            - name: MODEL_ID
              value: "falcon-40b-instruct"
            - name: USER_PROMPT
              value: "User: prompt"
            - name: SYSTEM_PROMPT
              value: "Assistant: prompt"
            ports:
            - containerPort: 7860
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: gradio-service
    spec:
      type: LoadBalancer
      selector:
        app: gradio
      ports:
      - port: 80
        targetPort: 7860
  2. Terapkan manifes:

    kubectl apply -f gradio.yaml
    
  3. Temukan alamat IP eksternal Layanan:

    kubectl get svc
    

    Outputnya mirip dengan hal berikut ini:

    NAME             TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
    gradio-service   LoadBalancer   10.24.29.197   34.172.115.35   80:30952/TCP   125m
    
  4. Salin alamat IP eksternal dari kolom EXTERNAL-IP.

  5. Lihat antarmuka model dari browser web Anda menggunakan alamat IP eksternal dengan port yang diekspos:

    http://EXTERNAL_IP
    

Menghitung jumlah GPU

Jumlah GPU bergantung pada nilai flag QUANTIZE. Dalam tutorial ini, QUANTIZE ditetapkan ke bitsandbytes-nf4, yang berarti model dimuat dalam 4 bit.

Model parameter 70 miliar akan memerlukan minimal 40 GB memori GPU yang setara dengan 70 miliar kali 4 bit (70 miliar x 4 bit= 35 GB) dan mempertimbangkan overhead 5 GB. Dalam hal ini, satu GPU L4 tidak akan memiliki cukup memori. Oleh karena itu, contoh dalam tutorial ini menggunakan dua memori L4 GPU (2 x 24 = 48 GB). Konfigurasi ini cukup untuk menjalankan Falcon 40b atau Llama 2 70b di GPU L4.

Pembersihan

Agar tidak dikenakan biaya pada akun Google Cloud Anda untuk resource yang digunakan dalam tutorial ini, hapus project yang berisi resource tersebut, atau simpan project dan hapus setiap resource-nya.

Menghapus cluster

Agar tidak menimbulkan biaya pada akun Google Cloud Anda untuk resource yang Anda buat dalam panduan ini, hapus cluster GKE:

gcloud container clusters delete l4-demo --region ${REGION}

Langkah selanjutnya