1. Einführung
Übersicht
In diesem Codelab verwenden Sie Cloud Run-Jobs, um ein Gemma 3-Modell abzustimmen und das Ergebnis dann mit vLLM in Cloud Run bereitzustellen.
Aufgaben
Trainieren Sie ein Modell, um mit einem bestimmten Ergebnis auf einen bestimmten Ausdruck zu reagieren. Verwenden Sie dazu das Dataset KomeijiForce/Text2Emoji, das im Rahmen von EmojiLM: Modeling the New Emoji Language erstellt wurde.
Nach dem Training reagiert das Modell auf einen Satz, dem „Translate to emoji: “ vorangestellt ist, mit einer Reihe von Emojis, die dem Satz entsprechen.
Lerninhalte
- Fine-Tuning mit Cloud Run Jobs GPU durchführen
- Modell mit Cloud Run und vLLM bereitstellen
- Konfiguration für die direkte VPC für einen GPU-Job verwenden, um das Modell schneller hochzuladen und bereitzustellen
2. Hinweis
APIs aktivieren
Bevor Sie mit diesem Codelab beginnen können, müssen Sie die folgenden APIs aktivieren:
gcloud services enable run.googleapis.com \
compute.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
secretmanager.googleapis.com \
artifactregistry.googleapis.com
GPU-Kontingent
In der Dokumentation zum GPU-Kontingent finden Sie Informationen zum Anfordern von Kontingenten.
Wenn Sie auf Fehler vom Typ „Sie haben kein Kontingent für die Verwendung von GPUs“ stoßen, prüfen Sie Ihr Kontingent unter g.co/cloudrun/gpu-quota.
Hinweis: Wenn Sie ein neues Projekt verwenden, kann es einige Minuten dauern, bis die Kontingente auf der Kontingentseite angezeigt werden.
Hugging Face
In diesem Codelab wird ein Modell verwendet, das auf Hugging Face gehostet wird. Wenn Sie dieses Modell verwenden möchten, fordern Sie das Hugging Face-Nutzerzugriffstoken mit der Berechtigung „Lesen“ an. Darauf wird später als YOUR_HF_TOKEN Bezug genommen.
Wenn Sie das Modell „gemma-3-1b-it“ verwenden möchten, müssen Sie den Nutzungsbedingungen zustimmen.
3. Einrichtung und Anforderungen
Richten Sie die folgenden Ressourcen ein:
- IAM-Dienstkonto und zugehörige IAM-Berechtigungen
- Secret Manager-Secret zum Speichern Ihres Hugging Face-Tokens
- Cloud Storage-Bucket zum Speichern des feinabgestimmten Modells
- Artifact Registry-Repository zum Speichern des Images, das Sie zum Feinabstimmen Ihres Modells erstellen.
- Umgebungsvariablen für dieses Codelab festlegen Wir haben bereits einige Variablen für Sie vorausgefüllt. Geben Sie Ihre Projekt-ID, Region und Ihr Hugging Face-Token an.
export PROJECT_ID=<YOUR_PROJECT_ID> export REGION=<YOUR_REGION> export HF_TOKEN=<YOUR_HF_TOKEN> export NEW_MODEL=gemma-emoji export AR_REPO=codelab-finetuning-jobs export IMAGE_NAME=finetune-to-gcs export JOB_NAME=finetuning-to-gcs-job export BUCKET_NAME=$PROJECT_ID-codelab-finetuning-jobs export SECRET_ID=HF_TOKEN export SERVICE_ACCOUNT="finetune-job-sa" export SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com - Erstellen Sie das Dienstkonto mit dem folgenden Befehl:
gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name="Service account for fine-tuning codelab" - Hugging Face-Zugriffstoken mit Secret Manager speichern:
gcloud secrets create $SECRET_ID \ --replication-policy="automatic" printf $HF_TOKEN | gcloud secrets versions add $SECRET_ID --data-file=- - Weisen Sie Ihrem Dienstkonto die Rolle „Secret Manager Secret Accessor“ zu:
gcloud secrets add-iam-policy-binding $SECRET_ID \ --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \ --role='roles/secretmanager.secretAccessor' - Erstellen Sie einen Bucket, in dem Ihr feinabgestimmtes Modell gehostet wird:
gcloud storage buckets create -l $REGION gs://$BUCKET_NAME - Gewähren Sie Ihrem Dienstkonto Zugriff auf den Bucket:
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_NAME \ --member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \ --role=roles/storage.objectAdmin - Erstellen Sie ein Artifact Registry-Repository zum Speichern des Container-Images:
gcloud artifacts repositories create $AR_REPO \ --repository-format=docker \ --location=$REGION \ --description="codelab for finetuning using CR jobs" \ --project=$PROJECT_ID
4. Cloud Run-Job-Image erstellen
Im nächsten Schritt erstellen Sie den Code, der Folgendes ausführt:
- Importiert das Gemma-Modell aus Hugging Face
- Führt die Feinabstimmung des Modells mit dem Dataset von Hugging Face durch. Für die Feinabstimmung wird eine einzelne L4-GPU verwendet.
- Lädt das feinabgestimmte Modell mit dem Namen
new_modelin Ihren Cloud Storage-Bucket hoch
- Erstellen Sie ein Verzeichnis für den Code Ihres Feinabstimmungsjobs.
mkdir codelab-finetuning-job cd codelab-finetuning-job - Erstellen Sie eine Datei mit dem Namen
finetune.py.# Copyright 2025 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import torch from datasets import load_dataset from peft import LoraConfig, PeftModel from transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, ) from trl import SFTTrainer # Cloud Storage bucket to upload the model bucket_name = os.getenv("BUCKET_NAME", "YOUR_BUCKET_NAME") # The model that you want to train from the Hugging Face hub model_name = os.getenv("MODEL_NAME", "google/gemma-3-1b-it") # The instruction dataset to use dataset_name = "KomeijiForce/Text2Emoji" # Fine-tuned model name new_model = os.getenv("NEW_MODEL", "gemma-emoji") ############################ Setup ############################################ # Load the entire model on the GPU 0 device_map = {"": torch.cuda.current_device()} # Limit dataset to a random selection dataset = load_dataset(dataset_name, split="train").shuffle(seed=42).select(range(1000)) # Setup input formats: trains the model to respond to "Translate to emoji:" with emoji output. tokenizer = AutoTokenizer.from_pretrained(model_name) def format_to_chat(example): return { "conversations": [ {"role": "user", "content": f"Translate to emoji: {example['text']}"}, {"role": "assistant", "content": example["emoji"]}, ] } formatted_dataset = dataset.map( format_to_chat, batched=False, # Process row by row remove_columns=dataset.column_names, # Optional: Keep only the new column ) def apply_chat_template(examples): texts = tokenizer.apply_chat_template(examples["conversations"], tokenize=False) return {"text": texts} final_dataset = formatted_dataset.map(apply_chat_template, batched=True) ############################# Config ######################################### # Load tokenizer and model with QLoRA configuration bnb_4bit_compute_dtype = "float16" # Compute dtype for 4-bit base models compute_dtype = getattr(torch, bnb_4bit_compute_dtype) bnb_config = BitsAndBytesConfig( load_in_4bit=True, # Activate 4-bit precision base model loading bnb_4bit_quant_type="nf4", # Quantization type (fp4 or nf4) bnb_4bit_compute_dtype=compute_dtype, bnb_4bit_use_double_quant=False, # Activate nested quantization for 4-bit base models (double quantization) ) # Load base model model = AutoModelForCausalLM.from_pretrained( model_name, quantization_config=bnb_config, device_map=device_map, torch_dtype=torch.float16, ) model.config.use_cache = False model.config.pretraining_tp = 1 ############################## Train ########################################## # Load LoRA configuration peft_config = LoraConfig( lora_alpha=16, # Alpha parameter for LoRA scaling lora_dropout=0.1, # Dropout probability for LoRA layers, r=8, # LoRA attention dimension bias="none", task_type="CAUSAL_LM", target_modules=["q_proj", "v_proj"], ) # Set training parameters training_arguments = TrainingArguments( output_dir="./results", num_train_epochs=1, per_device_train_batch_size=1, # Batch size per GPU for training gradient_accumulation_steps=2, # Number of update steps to accumulate the gradients for optim="paged_adamw_32bit", save_steps=0, logging_steps=5, learning_rate=2e-4, # Initial learning rate (AdamW optimizer) weight_decay=0.001, # Weight decay to apply to all layers except bias/LayerNorm weights fp16=True, bf16=False, # Enable fp16/bf16 training max_grad_norm=0.3, # Maximum gradient normal (gradient clipping) warmup_ratio=0.03, # Ratio of steps for a linear warmup (from 0 to learning rate) group_by_length=True, # Group sequences into batches with same length # Saves memory and speeds up training considerably lr_scheduler_type="cosine", ) trainer = SFTTrainer( model=model, train_dataset=final_dataset, peft_config=peft_config, dataset_text_field="text", max_seq_length=512, # Maximum sequence length to use tokenizer=tokenizer, args=training_arguments, packing=False, # Pack multiple short examples in the same input sequence to increase efficiency ) trainer.train() trainer.model.save_pretrained(new_model) ################################# Save ######################################## # Reload model in FP16 and merge it with LoRA weights base_model = AutoModelForCausalLM.from_pretrained( model_name, low_cpu_mem_usage=True, return_dict=True, torch_dtype=torch.float16, device_map=device_map, ) model = PeftModel.from_pretrained(base_model, new_model) model = model.merge_and_unload() # push results to Cloud Storage file_path_to_save_the_model = "/finetune/new_model" model.save_pretrained(file_path_to_save_the_model) tokenizer.save_pretrained(file_path_to_save_the_model) requirements.txt-Datei erstellen:accelerate==0.34.2 bitsandbytes==0.45.5 datasets==2.19.1 transformers==4.51.3 peft==0.11.1 trl==0.8.6 torch==2.3.0- Erstellen Sie ein
Dockerfile:FROM nvidia/cuda:12.6.2-runtime-ubuntu22.04 RUN apt-get update && \ apt-get -y --no-install-recommends install python3-dev gcc python3-pip git && \ rm -rf /var/lib/apt/lists/* COPY requirements.txt /requirements.txt RUN pip3 install -r requirements.txt --no-cache-dir COPY finetune.py /finetune.py ENV PYTHONUNBUFFERED 1 CMD python3 /finetune.py --device cuda - Erstellen Sie den Container in Ihrem Artifact Registry-Repository:
gcloud builds submit \ --tag $REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/$IMAGE_NAME \ --region $REGION
5. Job bereitstellen und ausführen
In diesem Schritt erstellen Sie den Job mit ausgehendem Direct VPC-Traffic für schnellere Uploads in Google Cloud Storage.
- Cloud Run-Job erstellen:
gcloud run jobs create $JOB_NAME \ --region $REGION \ --image $REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/$IMAGE_NAME \ --set-env-vars BUCKET_NAME=$BUCKET_NAME \ --set-secrets HF_TOKEN=$SECRET_ID:latest \ --cpu 8.0 \ --memory 32Gi \ --gpu 1 \ --add-volume name=finetuned_model,type=cloud-storage,bucket=$BUCKET_NAME \ --add-volume-mount volume=finetuned_model,mount-path=/finetune/new_model \ --service-account $SERVICE_ACCOUNT_ADDRESS - Job ausführen:
gcloud run jobs execute $JOB_NAME --region $REGION --async
Die Ausführung des Jobs dauert etwa 10 Minuten. Den Status können Sie über den Link in der Ausgabe des letzten Befehls prüfen.
6. Cloud Run-Dienst zum Bereitstellen Ihres feinabgestimmten Modells mit vLLM verwenden
In diesem Schritt stellen Sie einen Cloud Run-Dienst bereit. Bei dieser Konfiguration wird Direct VPC verwendet, um über ein privates Netzwerk auf den Cloud Storage-Bucket zuzugreifen und so schnellere Downloads zu ermöglichen.
- Cloud Run-Dienst bereitstellen:
gcloud run deploy serve-gemma-emoji \ --image us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20250601_0916_RC01 \ --region $REGION \ --port 8000 \ --set-env-vars MODEL_ID=new_model,HF_HUB_OFFLINE=1 \ --cpu 8.0 \ --memory 32Gi \ --gpu 1 \ --add-volume name=finetuned_model,type=cloud-storage,bucket=$BUCKET_NAME \ --add-volume-mount volume=finetuned_model,mount-path=/finetune/new_model \ --service-account $SERVICE_ACCOUNT_ADDRESS \ --max-instances 1 \ --command python3 \ --args="-m,vllm.entrypoints.api_server,--model=/finetune/new_model,--tensor-parallel-size=1" \ --no-gpu-zonal-redundancy \ --labels=dev-tutorial=codelab-tuning \ --no-invoker-iam-check
7. Abgestimmtes Modell testen
In diesem Schritt fordern Sie Ihr Modell auf, die Feinabstimmung mit „curl“ zu testen.
- Rufen Sie die Dienst-URL für Ihren Cloud Run-Dienst ab:
SERVICE_URL=$(gcloud run services describe serve-gemma-emoji \ --region $REGION --format 'value(status.url)') - Erstellen Sie den Prompt für Ihr Modell.
USER_PROMPT="Translate to emoji: I ate a banana for breakfast, later I'm thinking of having soup!" - Rufen Sie Ihren Dienst mit curl auf, um Ihr Modell zu prompten und die Ergebnisse mit jq zu filtern:
curl -s -X POST ${SERVICE_URL}/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: bearer $(gcloud auth print-identity-token)" \ -d @- <<EOF | jq ".choices[0].message.content" { "model": "${NEW_MODEL}", "messages": [{ "role": "user", "content": [ { "type": "text", "text": "${USER_PROMPT}"}] }] } EOF
Die Antwort sieht ungefähr so aus:
🍌🤔😋🥣
8. Glückwunsch!
Herzlichen Glückwunsch zum Abschluss des Codelabs!
Wir empfehlen, die Dokumentation zu Cloud Run Jobs – GPU zu lesen.
Behandelte Themen
- Fine-Tuning mit Cloud Run Jobs GPU durchführen
- Modell mit Cloud Run und vLLM bereitstellen
- Konfiguration für die direkte VPC für einen GPU-Job verwenden, um das Modell schneller hochzuladen und bereitzustellen
9. Bereinigen
Um unbeabsichtigte Gebühren zu vermeiden, z. B. wenn die Cloud Run-Dienste versehentlich öfter aufgerufen werden als Ihre monatliche Cloud Run-Aufrufkontingent im kostenlosen Kontingent, können Sie den in Schritt 6 erstellten Cloud Run-Dienst löschen.
Wenn Sie den Cloud Run-Dienst löschen möchten, rufen Sie die Cloud Run Console unter https://console.cloud.google.com/run auf und löschen Sie den serve-gemma-emoji-Dienst.
Wenn Sie das gesamte Projekt löschen möchten, rufen Sie Ressourcen verwalten auf, wählen Sie das Projekt aus, das Sie in Schritt 2 erstellt haben, und klicken Sie auf „Löschen“. Wenn Sie das Projekt löschen, müssen Sie das Projekt in Ihrem Cloud SDK ändern. Sie können die Liste aller verfügbaren Projekte mit gcloud projects list aufrufen.