Ajusta Gemma 4 en un clúster de GKE A4 de varios hosts

En este instructivo, se muestra cómo ajustar un modelo de lenguaje grande (google/gemma-4-31b-it) Gemma 4 de 31 mil millones de parámetros en un clúster de Autopilot de Google Kubernetes Engine (GKE) con varias GPU y varios hosts en Google Cloud. Este clúster usa dos instancias de máquina virtual (VM) A4 (a4-highgpu-8g) con un total de 16 GPUs NVIDIA B200.

Los tres procesos principales que se describen en este instructivo son los siguientes:

  1. Implementa un clúster de GKE de varios hosts en modo Autopilot.
  2. Compila una imagen de contenedor personalizada con las dependencias de ajuste necesarias con Cloud Build.
  3. Orquesta una carga de trabajo de ajuste de datos distribuida en varios hosts en las 16 GPUs con JobSet de Kubernetes y la biblioteca Hugging Face Accelerate con Fully Sharded Data Parallel v2 (FSDP v2), y envía los puntos de control a Hugging Face Hub.

Este instructivo está dirigido a ingenieros, investigadores, administradores y operadores de plataformas de aprendizaje automático (AA), y especialistas en datos y en IA que implementan clústeres de GKE en Google Cloud para ajustar LLMs en varios hosts.

Objetivos

  • Accede al modelo de Gemma 4 con Hugging Face.

  • Prepara tu entorno.

  • Crea e implementa un clúster de GKE A4 de varios hosts.

  • Ajusta el modelo Gemma 4 31B en 16 GPUs con Kubernetes JobSet y Hugging Face Accelerate con FSDP v2.

  • Supervisar tu trabajo

  • Consulta los pesos del adaptador ajustado en Hugging Face Hub.

  • Realizar una limpieza

Costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.

Es posible que los usuarios nuevos de Google Cloud cumplan con los requisitos para acceder a una prueba gratuita.

Antes de comenzar

Si quieres obtener los permisos que necesitas para completar este instructivo, pídele a tu administrador que te otorgue los siguientes roles de IAM en tu proyecto:

Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.

También puedes obtener los permisos necesarios a través de roles personalizados o cualquier otro rol predefinido.

  1. Habilita las APIs necesarias si aún no están habilitadas:

    Roles necesarios para habilitar las APIs

    Para habilitar APIs, necesitas el permiso serviceusage.services.enable. Si creaste el proyecto, es probable que ya tengas este permiso a través del rol de propietario (roles/owner). De lo contrario, puedes obtener este permiso a través del rol de administrador de Service Usage (roles/serviceusage.serviceUsageAdmin). Obtén más información para otorgar roles.

    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. Habilita la cuenta de servicio predeterminada de Compute Engine para tu proyectoGoogle Cloud :

    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. Otorga los roles de IAM con privilegios mínimos que la cuenta de servicio predeterminada de Compute Engine necesita para compilar la imagen del contenedor y ejecutar la carga de trabajo de ajuste:

    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. Verifica que los roles se hayan otorgado a la cuenta de servicio predeterminada de Compute Engine:

    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. Crea credenciales de autenticación locales para tu cuenta de usuario:

    gcloud auth application-default login
  6. Habilita el Acceso al SO para tu proyecto:

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

Accede a Gemma 4 con Hugging Face

Para usar Hugging Face y acceder a Gemma 4, completa los siguientes pasos:

  1. Accede a Hugging Face y acepta el contrato de licencia de Gemma 4.
  2. Crea un token de acceso de Hugging Face write.
    Haz clic en Tu perfil > Configuración > Tokens de acceso > +Crear token nuevo.
  3. Copia y guarda el valor del token de acceso write. Usarás este token para descargar el modelo base y enviar los puntos de control del adaptador ajustado a Hugging Face Hub antes de que GKE reduzca la escala verticalmente de los nodos de GPU.

Prepara el entorno

Para preparar tu entorno, configura las siguientes variables de entorno:

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}"

Reemplaza lo siguiente:

  • YOUR_PROJECT_ID: Es el ID del Google Cloud proyecto en el que deseas crear el clúster de GKE.

  • YOUR_CLUSTER_NAME: Es el nombre del clúster de GKE que se creará.

  • YOUR_REGION: Es la región en la que deseas crear tu clúster de GKE. Solo puedes crear el clúster en la región en la que existe tu reserva.

  • YOUR_RESERVATION_NAME: Es el identificador de tu capacidad reservada.

  • YOUR_HF_TOKEN: El token de acceso de Hugging Face write que creaste en la sección anterior.

  • YOUR_ARTIFACT_REGISTRY_LOCATION: La Google Cloud región (por ejemplo, us-central1) en la que deseas crear tu repositorio de Artifact Registry Para minimizar la latencia de extracción de imágenes, usa la misma región que especificaste para YOUR_REGION.

  • YOUR_NUMBER_OF_NODES: Es la cantidad de nodos de VM A4 en tu trabajo de ajuste. Para este instructivo de varios hosts con 16 GPUs NVIDIA B200 en dos instancias de a4-highgpu-8g, establece este valor en 2.

Crea un clúster de GKE de varios hosts en modo Autopilot

Crea un clúster de GKE de varios hosts en modo Autopilot:

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

La creación del clúster de GKE puede tardar varios minutos en completarse. Para verificar que Google Cloud haya terminado de crear tu clúster, ve a Clústeres de Kubernetes en la consola de Google Cloud .

Configura kubectl para comunicarse con tu clúster de GKE

Configura kubectl para comunicarse con tu clúster de GKE:

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

Crea un secreto de Kubernetes para las credenciales de Hugging Face

Crea un secreto de Kubernetes para almacenar tu token de Hugging Face:

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

Prepara tu carga de trabajo

Para preparar tu carga de trabajo, haz lo siguiente:

  1. Crea secuencias de comandos de carga de trabajo.

  2. Usa Docker y Cloud Build para crear un contenedor de ajuste.

Crea secuencias de comandos de cargas de trabajo

Para crear los archivos de configuración y las secuencias de comandos que usa tu carga de trabajo de ajuste, completa los siguientes pasos:

  1. Crea un directorio para las secuencias de comandos de la carga de trabajo. Usa este directorio como tu directorio de trabajo.

    mkdir llm-finetuning-gemma
    cd llm-finetuning-gemma
  2. Crea el archivo cloudbuild.yaml para compilar la imagen del contenedor de la carga de trabajo con Cloud Build y enviarla a Artifact Registry:

    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. Crea un archivo Dockerfile para definir el entorno y, luego, instala las dependencias necesarias para completar el trabajo de ajuste:

    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. Crea el archivo accel_fsdp_gemma4_config.yaml. Esta configuración dirige Hugging Face Accelerate para fragmentar Gemma4TextDecoderLayer en 16 GPUs en dos hosts con FSDP v2:

    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. Crea el manifiesto de finetune.yaml Kubernetes JobSet:

    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. Crea la secuencia de comandos de ajuste supervisado 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()

Usa Docker y Cloud Build para crear un contenedor de ajuste

  1. Crea un repositorio de Docker de Artifact Registry:

    gcloud artifacts repositories create gemma \
        --repository-format=docker \
        --location="${ARTIFACT_REPO_LOCATION}" \
        --description="Repository for Gemma fine tuning workload containers" || true
  2. Instala las definiciones de recursos personalizados (CRD) de JobSet necesarias para organizar cargas de trabajo de varios hosts:

    kubectl apply --server-side \
        -f https://github.com/kubernetes-sigs/jobset/releases/download/v0.12.0/manifests.yaml
  3. En el directorio llm-finetuning-gemma que creaste en un paso anterior, envía la compilación del contenedor a Cloud Build:

    gcloud builds submit . \
        --substitutions=_ARTIFACT_REPO_LOCATION="${ARTIFACT_REPO_LOCATION}"
  4. Exporta la URL de la imagen del contenedor de varios hosts. La usarás en un paso posterior de este instructivo, cuando implementes el manifiesto JobSet:

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

Inicia tu carga de trabajo de ajuste

Para implementar y supervisar tu carga de trabajo de ajuste distribuido, completa los siguientes pasos:

  1. Sustituye las variables de entorno en el manifiesto de ajuste para crear el trabajo de ajuste:

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

    Dado que tu clúster se ejecuta en el modo Autopilot de GKE, es posible que tarde unos minutos en aprovisionar los dos nodos A4 habilitados para GPU y extraer la imagen del contenedor.

  2. Observa los pods de trabajador hasta que ambos pasen al estado Running:

    watch kubectl get pods
  3. Después de que los Pods de trabajador pasen a Running, transmite los registros de entrenamiento:

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

Supervisa tu carga de trabajo

Puedes supervisar el uso de la GPU en tu clúster de GKE para verificar que las 16 GPU de los dos hosts A4 estén procesando de forma activa los pasos de entrenamiento. Genera y abre el vínculo de observabilidad en tu navegador:

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\"))"

Cuando supervises tu carga de trabajo, espera el siguiente comportamiento:

  • Utilización de la GPU: Para un trabajo de ajuste fino distribuido en buen estado, puedes esperar ver que la utilización de la GPU en las 16 GPU NVIDIA B200 aumente y se estabilice cerca del 95% al 100% durante los pasos de entrenamiento.
  • Duración del trabajo: En dos nodos a4-highgpu-8g (16 GPUs B200), el trabajo de ajuste de 3 épocas tarda aproximadamente 2 horas y media en completarse.

Cómo ver los pesos del adaptador ajustado

Cuando finalice el entrenamiento, consulta los pesos y los puntos de control del adaptador LoRA ajustado en Hugging Face Hub en https://huggingface.co/YOUR_HF_USERNAME/gemma-31b-text-to-sql.

Realiza una limpieza

Para evitar que se generen cargos adicionales, borra los recursos que creaste durante este instructivo.

Borra tus recursos

  1. Borra el JobSet del ajuste:

    kubectl delete jobset finetune-jobset
  2. Borra tu clúster de GKE:

    gcloud container clusters delete "${CLUSTER_NAME}" \
        --region="${CLUSTER_REGION}"
  3. Borra tu repositorio de Artifact Registry:

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

¿Qué sigue?