1. Introduzione
Panoramica
In questo codelab, utilizzerai i job Cloud Run per ottimizzare un modello Gemma 3, quindi pubblicherai il risultato su Cloud Run utilizzando vLLM.
In questo lab proverai a:
Addestra un modello a rispondere a una frase specifica con un risultato specifico utilizzando il set di dati KomeijiForce/Text2Emoji, creato nell'ambito di EmojiLM: Modeling the New Emoji Language.
Dopo l'addestramento, il modello risponde a una frase con il prefisso "Traduci in emoji: " con una serie di emoji corrispondenti alla frase.
Obiettivi didattici
- Come eseguire il fine tuning utilizzando Cloud Run Jobs GPU
- Come pubblicare un modello utilizzando Cloud Run con vLLM
- Come utilizzare la configurazione VPC diretto per un job GPU per caricare e pubblicare più rapidamente il modello
2. Prima di iniziare
Abilita API
Prima di poter iniziare a utilizzare questo codelab, abilita le seguenti API eseguendo:
gcloud services enable run.googleapis.com \
compute.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
secretmanager.googleapis.com \
artifactregistry.googleapis.com
Quota GPU
Consulta la documentazione relativa alla quota di GPU per verificare come richiedere la quota.
Se visualizzi errori del tipo "Non hai una quota per l'utilizzo delle GPU", verifica la tua quota su g.co/cloudrun/gpu-quota.
Nota: se utilizzi un nuovo progetto, potrebbero essere necessari alcuni minuti tra l'abilitazione dell'API e la visualizzazione delle quote nella pagina delle quote.
Hugging Face
Questo codelab utilizza un modello ospitato su Hugging Face. Per ottenere questo modello, richiedi il token di accesso utente di Hugging Face con l'autorizzazione "Lettura". A cui farai riferimento in un secondo momento come YOUR_HF_TOKEN.
Per utilizzare il modello gemma-3-1b-it, devi accettare i termini di utilizzo.
3. Configurazione e requisiti
Configura le seguenti risorse:
- Service account IAM e autorizzazioni IAM associate.
- Secret di Secret Manager per archiviare il token Hugging Face.
- Bucket Cloud Storage per archiviare il modello ottimizzato e
- Repository Artifact Registry per archiviare l'immagine che creerai per ottimizzare il modello.
- Imposta le variabili di ambiente per questo codelab. Abbiamo precompilato una serie di variabili per te. Specifica l'ID progetto, la regione e il token Hugging Face.
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 - Crea il service account eseguendo questo comando:
gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name="Service account for fine-tuning codelab" - Utilizza Secret Manager per archiviare il token di accesso a Hugging Face:
gcloud secrets create $SECRET_ID \ --replication-policy="automatic" printf $HF_TOKEN | gcloud secrets versions add $SECRET_ID --data-file=- - Concedi al tuo service account il ruolo Secret Manager Secret Accessor:
gcloud secrets add-iam-policy-binding $SECRET_ID \ --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \ --role='roles/secretmanager.secretAccessor' - Crea un bucket che ospiterà il modello ottimizzato:
gcloud storage buckets create -l $REGION gs://$BUCKET_NAME - Concedi al service account l'accesso al bucket:
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_NAME \ --member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \ --role=roles/storage.objectAdmin - Crea un repository Artifact Registry per archiviare l'immagine container:
gcloud artifacts repositories create $AR_REPO \ --repository-format=docker \ --location=$REGION \ --description="codelab for finetuning using CR jobs" \ --project=$PROJECT_ID
4. Crea l'immagine del job Cloud Run
Nel passaggio successivo, creerai il codice che esegue le seguenti operazioni:
- Importa il modello Gemma da Hugging Face
- Esegue l'ottimizzazione del modello con il set di dati di Hugging Face. Il job utilizza una singola GPU L4 per il perfezionamento.
- Carica il modello sottoposto a perfezionamento denominato
new_modelnel bucket Cloud Storage
- Crea una directory per il codice del job di perfezionamento.
mkdir codelab-finetuning-job cd codelab-finetuning-job - Crea un file denominato
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) - Crea un file
requirements.txt: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 - Crea un
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 - Crea il container nel repository Artifact Registry:
gcloud builds submit \ --tag $REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/$IMAGE_NAME \ --region $REGION
5. Esegui il deployment ed esegui il job
In questo passaggio, creerai il job con l'uscita VPC diretta per caricamenti più rapidi su Google Cloud Storage.
- Crea il job Cloud Run:
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 - Esegui il job:
gcloud run jobs execute $JOB_NAME --region $REGION --async
Il completamento del job richiede circa 10 minuti. Puoi controllare lo stato utilizzando il link fornito nell'output dell'ultimo comando.
6. Utilizzare un servizio Cloud Run per pubblicare il modello ottimizzato con vLLM
In questo passaggio, eseguirai il deployment di un servizio Cloud Run. Questa configurazione utilizza il VPC diretto per accedere al bucket Cloud Storage tramite la rete privata per download più rapidi.
- Esegui il deployment del servizio Cloud Run:
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. Testa il modello ottimizzato
In questo passaggio, chiederai al modello di testare l'ottimizzazione utilizzando curl.
- Recupera l'URL del servizio Cloud Run:
SERVICE_URL=$(gcloud run services describe serve-gemma-emoji \ --region $REGION --format 'value(status.url)') - Crea il prompt per il tuo modello.
USER_PROMPT="Translate to emoji: I ate a banana for breakfast, later I'm thinking of having soup!" - Chiama il tuo servizio utilizzando curl per richiedere al modello di filtrare i risultati con jq:
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
Dovresti visualizzare una risposta simile alla seguente:
🍌🤔😋🥣
8. Complimenti!
Congratulazioni per aver completato il codelab.
Ti consigliamo di consultare la documentazione relativa alle GPU di Cloud Run Jobs.
Argomenti trattati
- Come eseguire il fine tuning utilizzando Cloud Run Jobs GPU
- Come pubblicare un modello utilizzando Cloud Run con vLLM
- Come utilizzare la configurazione VPC diretto per un job GPU per caricare e pubblicare più rapidamente il modello
9. Esegui la pulizia
Per evitare addebiti involontari, ad esempio se i servizi Cloud Run vengono richiamati inavvertitamente più volte rispetto all'allocazione mensile di chiamate di Cloud Run nel livello senza costi, puoi eliminare il servizio Cloud Run creato nel passaggio 6.
Per eliminare il servizio Cloud Run, vai alla console Cloud Run all'indirizzo https://console.cloud.google.com/run ed elimina il servizio serve-gemma-emoji.
Per eliminare l'intero progetto, vai a Gestisci risorse, seleziona il progetto che hai creato nel passaggio 2 e scegli Elimina. Se elimini il progetto, dovrai cambiarlo in Cloud SDK. Puoi visualizzare l'elenco di tutti i progetti disponibili eseguendo gcloud projects list.