Gemma 4 in einem A4-GKE-Cluster mit mehreren Hosts abstimmen

In dieser Anleitung wird beschrieben, wie Sie ein Gemma 4-LLM (Large Language Model) mit 31 Milliarden Parametern (google/gemma-4-31b-it) in einem GKE-Autopilot-Cluster (Google Kubernetes Engine) mit mehreren Hosts und mehreren GPUs auf Google Cloudabstimmen. Dieser Cluster verwendet zwei virtuelle A4-Maschinen (VM) (a4-highgpu-8g) mit insgesamt 16 NVIDIA B200-GPUs.

Die drei Hauptprozesse, die in dieser Anleitung beschrieben werden, sind:

  1. Stellen Sie einen GKE-Cluster mit mehreren Hosts im Autopilot-Modus bereit.
  2. Erstellen Sie mit Cloud Build ein benutzerdefiniertes Container-Image mit den erforderlichen Abhängigkeiten für das Fine-Tuning.
  3. Orchestriert eine verteilte Multi-Host-Arbeitslast für das Fine-Tuning auf allen 16 GPUs mit Kubernetes JobSet und der Hugging Face Accelerate-Bibliothek mit Fully Sharded Data Parallel v2 (FSDP v2) und überträgt Checkpoints an den Hugging Face Hub.

Diese Anleitung richtet sich an Entwickler von maschinellem Lernen (ML), Forscher, Plattformadministratoren und ‑operatoren sowie Daten- und KI-Spezialisten, die GKE-Cluster auf Google Cloud bereitstellen, um LLMs auf mehreren Hosts abzustimmen.

Ziele

  • Über Hugging Face auf das Gemma 4-Modell zugreifen

  • Bereiten Sie Ihre Umgebung vor.

  • A4-GKE-Cluster mit mehreren Hosts erstellen und bereitstellen

  • Optimieren Sie das Gemma 4 31B-Modell auf 16 GPUs mit Kubernetes JobSet und Hugging Face Accelerate mit FSDP v2.

  • den Job überwachen

  • Die feinabgestimmten Adaptergewichte können Sie im Hugging Face-Hub ansehen.

  • bereinigen.

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen.

Neuen Nutzern von Google Cloud steht möglicherweise eine kostenlose Testversion zur Verfügung.

Hinweis

Bitten Sie Ihren Administrator, Ihnen die folgenden IAM-Rollen für Ihr Projekt zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Ausführen dieser Anleitung benötigen:

Weitere Informationen zum Zuweisen von Rollen finden Sie unter Zugriff auf Projekte, Ordner und Organisationen verwalten.

Sie können die erforderlichen Berechtigungen auch über benutzerdefinierte Rollen oder andere vordefinierte Rollen erhalten.

  1. Aktivieren Sie die erforderlichen APIs, falls noch nicht geschehen:

    Rollen, die zum Aktivieren von APIs erforderlich sind

    Zum Aktivieren von APIs benötigen Sie die Berechtigung serviceusage.services.enable. Wenn Sie das Projekt erstellt haben, haben Sie diese Berechtigung wahrscheinlich bereits über die Rolle „Inhaber“ (roles/owner). Andernfalls können Sie diese Berechtigung über die Rolle „Service Usage-Administrator“ (roles/serviceusage.serviceUsageAdmin) erhalten. Informationen zum Zuweisen von Rollen

    gcloud services enable compute.googleapis.com container.googleapis.com artifactregistry.googleapis.com cloudbuild.googleapis.com logging.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com
  2. Aktivieren Sie das Compute Engine-Standarddienstkonto für IhrGoogle Cloud -Projekt:

    export PROJECT_NUMBER="$(gcloud projects describe "YOUR_PROJECT_ID" --format "value(project_number)")"
    gcloud iam service-accounts enable "${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
        --project=YOUR_PROJECT_ID
  3. Weisen Sie dem Standard-Compute Engine-Dienstkonto die IAM-Rollen mit den geringsten Berechtigungen zu, die zum Erstellen des Container-Images und zum Ausführen des Fine-Tuning-Arbeitslast erforderlich sind:

    ROLES=(
      "roles/artifactregistry.writer"
      "roles/cloudbuild.builds.builder"
      "roles/logging.logWriter"
      "roles/monitoring.metricWriter"
      "roles/monitoring.viewer"
      "roles/stackdriver.resourceMetadata.writer"
      "roles/storage.objectViewer"
    )
    for role in "${ROLES[@]}"; do
      gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
          --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
          --role="${role}" 1>/dev/null
    done
    unset ROLES
  4. Prüfen Sie, ob die Rollen dem Compute Engine-Standarddienstkonto zugewiesen wurden:

    echo "Displaying roles for ${PROJECT_NUMBER}-compute@developer.gserviceaccount.com:"
    gcloud projects get-iam-policy YOUR_PROJECT_ID \
        --flatten="bindings[].members" \
        --filter="bindings.members:serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
        --format="table(bindings.role)"
  5. Erstellen Sie lokale Authentifizierungsdaten für Ihr Nutzerkonto:

    gcloud auth application-default login
  6. OS Login für Ihr Projekt aktivieren:

    gcloud compute project-info add-metadata \
        --metadata=enable-oslogin=TRUE \
        --project=YOUR_PROJECT_ID

Über Hugging Face auf Gemma 4 zugreifen

So greifen Sie über Hugging Face auf Gemma 4 zu:

  1. Melden Sie sich bei Hugging Face an und akzeptieren Sie die Lizenzvereinbarung für Gemma 4.
  2. Erstellen Sie ein Hugging Face-Zugriffstoken für write.
    Klicken Sie auf Profil > Einstellungen > Zugriffstokens > + Neues Token erstellen.
  3. Kopieren und speichern Sie den Wert für das write-Zugriffstoken. Sie verwenden dieses Token, um das Basismodell herunterzuladen und optimierte Adapter-Checkpoints in den Hugging Face Hub zu übertragen, bevor GKE die GPU-Knoten herunterskaliert.

Umgebung vorbereiten

Legen Sie die folgenden Umgebungsvariablen fest, um die Umgebung vorzubereiten:

export PROJECT_ID="YOUR_PROJECT_ID"
export CLUSTER_NAME="YOUR_CLUSTER_NAME"
export CLUSTER_REGION="YOUR_REGION"
export RESERVATION="YOUR_RESERVATION_NAME"
export HF_TOKEN="YOUR_HF_TOKEN"
export ARTIFACT_REPO_LOCATION="YOUR_ARTIFACT_REGISTRY_LOCATION"
export NUM_NODES="YOUR_NUMBER_OF_NODES"

gcloud config set project "${PROJECT_ID}"
gcloud config set billing/quota_project "${PROJECT_ID}"

Ersetzen Sie Folgendes:

  • YOUR_PROJECT_ID: die ID des Google Cloud Projekts, in dem Sie den GKE-Cluster erstellen möchten.

  • YOUR_CLUSTER_NAME: Der Name des GKE-Cluster, der erstellt werden soll.

  • YOUR_REGION: die Region, in der Sie Ihren GKE-Cluster erstellen möchten. Sie können den Cluster nur in der Region erstellen, in der Ihre Reservierung vorhanden ist.

  • YOUR_RESERVATION_NAME: Die Kennung für Ihre reservierte Kapazität.

  • YOUR_HF_TOKEN: Das Hugging Face-write-Zugriffstoken, das Sie im vorherigen Abschnitt erstellt haben.

  • YOUR_ARTIFACT_REGISTRY_LOCATION: die Google Cloud Region (z. B. us-central1), in der Sie Ihr Artifact Registry -Repository erstellen möchten. Verwenden Sie dieselbe Region, die Sie für YOUR_REGION angegeben haben, um die Latenz beim Abrufen von Bildern zu minimieren.

  • YOUR_NUMBER_OF_NODES: die Anzahl der A4-VM-Knoten in Ihrem Fine-Tuning-Job. Für dieses Tutorial mit mehreren Hosts mit 16 NVIDIA B200-GPUs auf zwei a4-highgpu-8g-Instanzen legen Sie diesen Wert auf 2 fest.

GKE-Cluster mit mehreren Hosts im Autopilot-Modus erstellen

Erstellen Sie einen GKE-Cluster mit mehreren Hosts im Autopilot-Modus:

gcloud container clusters create-auto "${CLUSTER_NAME}" \
    --project="${PROJECT_ID}" \
    --location="${CLUSTER_REGION}"

Das Erstellen des GKE-Cluster kann einige Minuten dauern. Rufen Sie in der Google Cloud Console die Seite Kubernetes-Cluster auf, um zu prüfen, ob Google Cloud das Erstellen Ihres Clusters abgeschlossen hat.

kubectl für die Kommunikation mit Ihrem GKE-Cluster konfigurieren

Konfigurieren Sie kubectl für die Kommunikation mit Ihrem GKE-Cluster:

gcloud container clusters get-credentials "${CLUSTER_NAME}" \
    --location="${CLUSTER_REGION}"

Kubernetes-Secret für Hugging Face-Anmeldedaten erstellen

Erstellen Sie ein Kubernetes-Secret zum Speichern Ihres Hugging Face-Tokens:

kubectl create secret generic hf-secret \
    --from-literal=hf_api_token="${HF_TOKEN}" \
    --dry-run=client -o yaml | kubectl apply -f -

Arbeitslast vorbereiten

So bereiten Sie Ihre Arbeitslast vor:

  1. Arbeitslastskripts erstellen:

  2. Container für die Feinabstimmung mit Docker und Cloud Build erstellen

Arbeitslastskripts erstellen

Führen Sie die folgenden Schritte aus, um die Konfigurationsdateien und ‑skripts zu erstellen, die von Ihrer Arbeitslast zum Feinabstimmen verwendet werden:

  1. Erstellen Sie ein Verzeichnis für die Arbeitslastskripts. Verwenden Sie dieses Verzeichnis als Arbeitsverzeichnis.

    mkdir llm-finetuning-gemma
    cd llm-finetuning-gemma
  2. Erstellen Sie die Datei cloudbuild.yaml, um das Container-Image für Ihre Arbeitslast mit Cloud Build zu erstellen und per Push in Artifact Registry zu übertragen:

    steps:
    - name: 'gcr.io/cloud-builders/docker'
      args:
      - 'build'
      - '-t'
      - '$_ARTIFACT_REPO_LOCATION-docker.pkg.dev/$PROJECT_ID/gemma/finetune-gemma-multihost-gpu:2.0.0'
      - '.'
    images:
    - '$_ARTIFACT_REPO_LOCATION-docker.pkg.dev/$PROJECT_ID/gemma/finetune-gemma-multihost-gpu:2.0.0'
    options:
      logging: CLOUD_LOGGING_ONLY
  3. Erstellen Sie eine Dockerfile-Datei, um die Umgebung zu definieren und die Abhängigkeiten zu installieren, die für den Fine-Tuning-Job erforderlich sind:

    FROM nvidia/cuda:12.8.1-cudnn-devel-ubuntu24.04
    RUN apt-get update && \
        apt-get -y install python3 python3-dev gcc python3-pip \
            python3-venv git curl vim && \
        rm -rf /var/lib/apt/lists/*
    RUN python3 -m venv /opt/venv
    ENV PATH="/opt/venv/bin:/usr/local/nvidia/bin:$PATH"
    ENV LD_LIBRARY_PATH="/usr/local/nvidia/lib64:$LD_LIBRARY_PATH"
    RUN pip3 install setuptools wheel packaging ninja
    RUN pip3 install torch torchvision torchaudio \
        --index-url https://download.pytorch.org/whl/cu128
    RUN pip3 install \
        "transformers>=5.5.0" \
        trl==0.29.1 \
        peft==0.18.1 \
        accelerate==1.13.0 \
        bitsandbytes==0.49.2 \
        datasets==4.8.4 \
        evaluate==0.4.5 \
        tensorboard==2.20.0 \
        protobuf==6.31.1 \
        sentencepiece==0.2.0
    WORKDIR /workspace
    COPY finetune.py /workspace/finetune.py
    COPY accel_fsdp_gemma4_config.yaml /workspace/accel_fsdp_gemma4_config.yaml
    CMD ["accelerate", "launch", "--config_file", "/workspace/accel_fsdp_gemma4_config.yaml", "/workspace/finetune.py"]
  4. Erstellen Sie die Datei accel_fsdp_gemma4_config.yaml. Mit dieser Konfiguration wird Hugging Face Accelerate angewiesen, Gemma4TextDecoderLayer mit FSDP v2 auf 16 GPUs auf zwei Hosts aufzuteilen:

    compute_environment: LOCAL_MACHINE
    debug: false
    distributed_type: FSDP
    downcast_bf16: 'no'
    enable_cpu_affinity: false
    fsdp_config:
      fsdp_activation_checkpointing: false
      fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
      fsdp_cpu_ram_efficient_loading: false
      fsdp_offload_params: true
      fsdp_reshard_after_forward: true
      fsdp_state_dict_type: FULL_STATE_DICT
      fsdp_transformer_layer_cls_to_wrap: Gemma4TextDecoderLayer
      fsdp_version: 2
    machine_rank: 0
    main_training_function: main
    mixed_precision: bf16
    num_machines: 2
    num_processes: 16
    rdzv_backend: static
    same_network: true
    tpu_env: []
    tpu_use_cluster: false
    tpu_use_sudo: false
    use_cpu: false
  5. Erstellen Sie das finetune.yamlKubernetes-ManifestJobSet:

    apiVersion: resource.k8s.io/v1
    kind: ResourceClaimTemplate
    metadata:
      name: mrdma
    spec:
      spec:
        devices:
          requests:
          - name: mrdma
            exactly:
              deviceClassName: mrdma.google.com
    ---
    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: finetune-jobset
      namespace: default
    spec:
      failurePolicy:
        maxRestarts: 2
      replicatedJobs:
      - name: workers
        replicas: 1
        template:
          spec:
            parallelism: ${NUM_NODES}
            completions: ${NUM_NODES}
            backoffLimit: 0
            template:
              metadata:
                annotations:
                  kubectl.kubernetes.io/default-container: finetuner
              spec:
                terminationGracePeriodSeconds: 600
                restartPolicy: OnFailure
                nodeSelector:
                  cloud.google.com/compute-class: "Accelerator"
                  cloud.google.com/gke-accelerator: "nvidia-b200"
                  cloud.google.com/reservation-name: ${RESERVATION}
                  cloud.google.com/reservation-affinity: "specific"
                  cloud.google.com/gke-gpu-driver-version: latest
                containers:
                - name: finetuner
                  image: $IMAGE_URL
                  command: ["bash", "-c"]
                  args:
                  - |
                    NUM_PROCESSES=$(( ${NUM_NODES} * 8 ))
                    accelerate launch \
                      --config_file /workspace/accel_fsdp_gemma4_config.yaml \
                      --num_machines ${NUM_NODES} \
                      --num_processes ${NUM_PROCESSES} \
                      --machine_rank ${JOB_COMPLETION_INDEX} \
                      --main_process_ip finetune-jobset-workers-0-0.finetune-jobset.default.svc.cluster.local \
                      --main_process_port 29500 \
                      /workspace/finetune.py \
                      --base_model google/gemma-4-31b-it \
                      --new_model gemma-31b-text-to-sql \
                      --per_device_train_batch_size 4 \
                      --gradient_accumulation_steps 4 \
                      --num_train_epochs 3 \
                      --learning_rate 1e-5 \
                      --save_strategy steps \
                      --save_steps 15 \
                      --push_to_hub
                  resources:
                    limits:
                      nvidia.com/gpu: "8"
                      memory: "1000Gi"
                      ephemeral-storage: "350Gi"
                    requests:
                      nvidia.com/gpu: "8"
                      memory: "1000Gi"
                      ephemeral-storage: "350Gi"
                  env:
                  - name: HF_TOKEN
                    valueFrom:
                      secretKeyRef:
                        name: hf-secret
                        key: hf_api_token
                  - name: NUM_NODES
                    value: "${NUM_NODES}"
                  volumeMounts:
                  - mountPath: /dev/shm
                    name: dshm
                volumes:
                - name: dshm
                  emptyDir:
                    medium: Memory
                    sizeLimit: 64Gi
  6. Erstellen Sie das Skript für die überwachte Feinabstimmung für finetune.py:

    import argparse
    import torch
    from datasets import load_dataset
    from huggingface_hub import login
    from peft import LoraConfig
    from transformers import AutoConfig, AutoModelForCausalLM, AutoTokenizer
    from trl import SFTConfig, SFTTrainer
    
    
    def get_args():
        def str2bool(v):
            if isinstance(v, bool):
                return v
            return v.lower() in ("yes", "true", "t", "1")
    
        parser = argparse.ArgumentParser()
        parser.add_argument(
            "--base_model",
            "--model_id",
            dest="base_model",
            type=str,
            default="google/gemma-4-31b-it",
            help="Hugging Face model ID",
        )
        parser.add_argument(
            "--hf_token",
            type=str,
            default=None,
            help="Hugging Face token for gated models and Hub uploads",
        )
        parser.add_argument(
            "--trust_remote",
            type=str2bool,
            default=False,
            help="Trust remote code when loading tokenizer",
        )
        parser.add_argument(
            "--use_fast",
            type=str2bool,
            default=True,
            help="Determines if a fast Rust-based tokenizer should be used",
        )
        parser.add_argument(
            "--dataset_name",
            type=str,
            default="philschmid/gretel-synthetic-text-to-sql",
            help="Hugging Face dataset name",
        )
        parser.add_argument(
            "--new_model",
            "--output_dir",
            dest="new_model",
            type=str,
            default="gemma-31b-text-to-sql",
            help="Directory and repository name to save model checkpoints",
        )
    
        # LoRA arguments
        parser.add_argument(
            "--lora_r", type=int, default=16, help="LoRA attention dimension"
        )
        parser.add_argument(
            "--lora_alpha", type=int, default=32, help="LoRA alpha scaling factor"
        )
        parser.add_argument(
            "--lora_dropout",
            type=float,
            default=0.05,
            help="LoRA dropout probability",
        )
        # SFTConfig arguments
        parser.add_argument(
            "--max_length",
            type=int,
            default=1024,
            help="Maximum sequence length",
        )
        parser.add_argument(
            "--num_train_epochs",
            type=int,
            default=3,
            help="Number of training epochs",
        )
        parser.add_argument(
            "--per_device_train_batch_size",
            type=int,
            default=4,
            help="Batch size per device during training",
        )
        parser.add_argument(
            "--gradient_accumulation_steps",
            type=int,
            default=4,
            help="Gradient accumulation steps",
        )
        parser.add_argument(
            "--learning_rate", type=float, default=1e-5, help="Learning rate"
        )
        parser.add_argument(
            "--logging_steps", type=int, default=10, help="Log every X steps"
        )
        parser.add_argument(
            "--save_strategy",
            type=str,
            default="steps",
            help="Checkpoint save strategy",
        )
        parser.add_argument(
            "--save_steps",
            type=int,
            default=15,
            help="Save checkpoint every X steps",
        )
        parser.add_argument(
            "--push_to_hub",
            action="store_true",
            help="Push model back up to Hugging Face Hub",
        )
        parser.add_argument(
            "--hub_private_repo",
            type=str2bool,
            default=True,
            help="Push to a private repository on Hugging Face Hub",
        )
        return parser.parse_args()
    
    
    def main():
        args = get_args()
        # --- 1. Setup and Login ---
        if args.hf_token:
            login(args.hf_token)
        # --- 2. Create and prepare the fine-tuning dataset ---
        dataset = load_dataset(args.dataset_name, split="train")
        dataset = dataset.shuffle().select(range(12500))
        dataset = dataset.train_test_split(test_size=2500 / 12500)
        # --- 3. Configure Model and Tokenizer ---
        if torch.cuda.is_available() and torch.cuda.get_device_capability()[0] >= 8:
            torch_dtype_obj = torch.bfloat16
        else:
            torch_dtype_obj = torch.float16
        tokenizer = AutoTokenizer.from_pretrained(
            args.base_model,
            trust_remote_code=args.trust_remote,
            use_fast=args.use_fast,
        )
        if tokenizer.pad_token is None:
            tokenizer.pad_token = tokenizer.eos_token
    
        # --- 4. Define the Formatting Function ---
        def formatting_func(example):
            system_message = (
                "You are a text to SQL query translator. Users will ask you "
                "questions in English and you will generate a SQL query based "
                "on the provided SCHEMA."
            )
            user_prompt = (
                "Given the <USER_QUERY> and the <SCHEMA>, generate the "
                "corresponding SQL command to retrieve the desired data, "
                "considering the query's syntax, semantics, and schema "
                "constraints.\n\n<SCHEMA>\n{context}\n</SCHEMA>\n\n"
                "<USER_QUERY>\n{question}\n</USER_QUERY>\n"
            )
    
            messages = [
                {"role": "system", "content": system_message},
                {
                    "role": "user",
                    "content": user_prompt.format(
                        question=example["sql_prompt"],
                        context=example["sql_context"],
                    ),
                },
                {"role": "assistant", "content": example["sql"]},
            ]
            return tokenizer.apply_chat_template(messages, tokenize=False)
    
        # --- 5. Load Model and Configure LoRA ---
        config = AutoConfig.from_pretrained(args.base_model)
        config.use_cache = False
        print("Loading base model...")
        model = AutoModelForCausalLM.from_pretrained(
            args.base_model,
            config=config,
            attn_implementation="sdpa",
            torch_dtype=torch_dtype_obj,
        )
    
        peft_config = LoraConfig(
            lora_alpha=args.lora_alpha,
            lora_dropout=args.lora_dropout,
            r=args.lora_r,
            bias="none",
            target_modules=[
                "q_proj",
                "k_proj",
                "v_proj",
                "o_proj",
                "gate_proj",
                "up_proj",
                "down_proj",
            ],
            exclude_modules=r".*(vision_tower|embed_vision|audio_tower|embed_audio).*",
            task_type="CAUSAL_LM",
        )
        # --- 6. Configure Training Arguments ---
        training_args = SFTConfig(
            output_dir=args.new_model,
            max_length=args.max_length,
            num_train_epochs=args.num_train_epochs,
            per_device_train_batch_size=args.per_device_train_batch_size,
            gradient_accumulation_steps=args.gradient_accumulation_steps,
            learning_rate=args.learning_rate,
            logging_steps=args.logging_steps,
            save_strategy=args.save_strategy,
            save_steps=args.save_steps,
            packing=False,
            label_names=["domain"],
            gradient_checkpointing=True,
            gradient_checkpointing_kwargs={"use_reentrant": False},
            optim="adamw_torch",
            fp16=torch_dtype_obj == torch.float16,
            bf16=torch_dtype_obj == torch.bfloat16,
            max_grad_norm=0.3,
            warmup_steps=0.03,
            lr_scheduler_type="constant",
            push_to_hub=args.push_to_hub,
            hub_private_repo=args.hub_private_repo,
            report_to="tensorboard",
        )
        # --- 7. Create Trainer and Start Training ---
        trainer = SFTTrainer(
            model=model,
            args=training_args,
            peft_config=peft_config,
            train_dataset=dataset["train"],
            eval_dataset=dataset["test"],
            processing_class=tokenizer,
            formatting_func=formatting_func,
        )
        print("Starting training...")
        trainer.train()
        print("Training finished.")
        # --- 8. Save the final model ---
        print(f"Saving final model to {args.new_model}")
        if trainer.is_fsdp_enabled:
            trainer.accelerator.state.fsdp_plugin.set_state_dict_type(
                "FULL_STATE_DICT"
            )
        trainer.save_model(args.new_model)
        if torch.distributed.is_initialized():
            torch.distributed.destroy_process_group()
    
    
    if __name__ == "__main__":
        main()

Container für die Feinabstimmung mit Docker und Cloud Build erstellen

  1. Artifact Registry-Docker-Repository erstellen:

    gcloud artifacts repositories create gemma \
        --repository-format=docker \
        --location="${ARTIFACT_REPO_LOCATION}" \
        --description="Repository for Gemma fine tuning workload containers" || true
  2. Installieren Sie die benutzerdefinierten Ressourcendefinitionen (CRDs) JobSet, die für die Orchestrierung von Arbeitslasten mit mehreren Hosts erforderlich sind:

    kubectl apply --server-side \
        -f https://github.com/kubernetes-sigs/jobset/releases/download/v0.12.0/manifests.yaml
  3. Senden Sie den Container-Build an Cloud Build. Verwenden Sie dazu das Verzeichnis llm-finetuning-gemma, das Sie in einem vorherigen Schritt erstellt haben:

    gcloud builds submit . \
        --substitutions=_ARTIFACT_REPO_LOCATION="${ARTIFACT_REPO_LOCATION}"
  4. Exportieren Sie die Container-Image-URL für mehrere Hosts. Sie benötigen sie später in dieser Anleitung, wenn Sie das JobSet-Manifest bereitstellen:

    IMAGE_REGISTRY="${ARTIFACT_REPO_LOCATION}-docker.pkg.dev/${PROJECT_ID}"
    export IMAGE_URL="${IMAGE_REGISTRY}/gemma/finetune-gemma-multihost-gpu:2.0.0"

Fine-Tuning-Arbeitslast starten

Führen Sie die folgenden Schritte aus, um Ihre verteilte Arbeitslast für das Fine-Tuning bereitzustellen und zu überwachen:

  1. Ersetzen Sie Umgebungsvariablen im Manifest für die Feinabstimmung, um den Job für die Feinabstimmung zu erstellen:

    envsubst '${RESERVATION} ${IMAGE_URL} ${NUM_NODES}' < finetune.yaml \
        | kubectl apply -f -

    Da Ihr Cluster im GKE Autopilot-Modus ausgeführt wird, kann es einige Minuten dauern, bis die beiden GPU-fähigen A4-Knoten bereitgestellt und das Container-Image abgerufen werden.

  2. Beobachten Sie die Worker-Pods, bis beide den Status Running haben:

    watch kubectl get pods
  3. Nachdem die Worker-Pods in den Status Running gewechselt sind, streamen Sie die Trainingslogs:

    kubectl logs -l "job-name=finetune-jobset-workers-0" -f

Arbeitslast überwachen

Sie können die GPU-Auslastung in Ihrem GKE-Cluster überwachen, um zu prüfen, ob alle 16 GPUs auf beiden A4-Hosts aktiv Trainingsschritte verarbeiten. Generieren Sie den Observability-Link und öffnen Sie ihn in Ihrem Browser:

echo "https://console.cloud.google.com/kubernetes/clusters/details/${CLUSTER_REGION}/${CLUSTER_NAME}/observability?mods=monitoring_api_prod&project=${PROJECT_ID}&pageState=(\"timeRange\":(\"duration\":\"PT1H\"),\"nav\":(\"section\":\"gpu\"),\"groupBy\":(\"groupByType\":\"namespacesTop5\"))"

Wenn Sie Ihre Arbeitslast überwachen, sollten Sie mit folgendem Verhalten rechnen:

  • GPU-Auslastung: Bei einem fehlerfreien verteilten Feinabstimmungsjob sollte die GPU-Auslastung aller 16 NVIDIA B200-GPUs während der Trainingsschritte ansteigen und sich bei 95–100 % stabilisieren.
  • Jobdauer: Auf zwei a4-highgpu-8g-Knoten (16 B200-GPUs) dauert der Fine-Tuning-Job mit 3 Epochen etwa 2,5 Stunden.

Abgestimmte Adaptergewichte ansehen

Wenn das Training abgeschlossen ist, können Sie sich die abgestimmten LoRA-Adaptergewichte und Checkpoints auf Hugging Face Hub unter https://huggingface.co/YOUR_HF_USERNAME/gemma-31b-text-to-sql ansehen.

Bereinigen

Löschen Sie die in dieser Anleitung erstellten Ressourcen, um zusätzliche Gebühren zu vermeiden.

Ressourcen löschen

  1. Löschen Sie die Abstimmung JobSet:

    kubectl delete jobset finetune-jobset
  2. So löschen Sie den GKE-Cluster:

    gcloud container clusters delete "${CLUSTER_NAME}" \
        --region="${CLUSTER_REGION}"
  3. Löschen Sie Ihr Artifact Registry-Repository:

    gcloud artifacts repositories delete gemma \
        --location="${ARTIFACT_REPO_LOCATION}" \
        --quiet

Nächste Schritte