1. Pengantar
Ringkasan
Dalam codelab ini, Anda akan menggunakan tugas Cloud Run untuk menyesuaikan model Gemma, lalu menayangkan hasilnya di Cloud Run menggunakan vLLM.
Untuk tujuan codelab ini, Anda akan menggunakan set data text-to-sql, yang dimaksudkan untuk membuat LLM membalas dengan kueri SQL saat ditanya dalam bahasa alami.
Yang akan Anda pelajari
- Cara melakukan penyesuaian halus menggunakan GPU Tugas Cloud Run
- Cara menayangkan model menggunakan Cloud Run dengan vLLM
- Cara menggunakan konfigurasi VPC Langsung untuk Tugas GPU agar upload dan penayangan model lebih cepat
2. Sebelum memulai
Mengaktifkan API
Sebelum Anda dapat mulai menggunakan codelab ini, aktifkan API berikut dengan menjalankan:
gcloud services enable run.googleapis.com \
compute.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
secretmanager.googleapis.com \
artifactregistry.googleapis.com
Kuota GPU
Meminta penambahan kuota untuk region yang didukung. Kuotanya adalah nvidia_l4_gpu_allocation_no_zonal_redundancy
, di bagian Cloud Run Admin API.
Catatan: Jika Anda menggunakan project baru, mungkin perlu waktu beberapa menit antara mengaktifkan API dan menampilkan kuota di halaman ini.
Wajah Memeluk
Codelab ini menggunakan model yang dihosting di Hugging Face. Untuk mendapatkan model ini, minta token akses pengguna Hugging Face dengan izin "Baca". Anda akan mereferensikannya nanti sebagai YOUR_HF_TOKEN
.
Anda juga harus menyetujui persyaratan penggunaan untuk menggunakan model: https://huggingface.co/google/gemma-2b
3. Penyiapan dan Persyaratan
Siapkan resource berikut:
- Akun layanan IAM dan izin IAM terkait,
- Secret Secret Manager untuk menyimpan token Hugging Face Anda,
- Bucket Cloud Storage untuk menyimpan model yang telah dioptimalkan, dan
- Repositori Artifact Registry untuk menyimpan image yang akan Anda build guna menyesuaikan model.
- Tetapkan variabel lingkungan untuk codelab ini. Kami telah mengisi otomatis sejumlah variabel untuk Anda. Tentukan project ID, region, dan token Hugging Face Anda.
export PROJECT_ID=<YOUR_PROJECT_ID> export REGION=<YOUR_REGION> export HF_TOKEN=<YOUR_HF_TOKEN> 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
- Buat akun layanan dengan menjalankan perintah ini:
gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name="Service account for fine-tuning codelab"
- Gunakan Secret Manager untuk menyimpan token akses Hugging Face:
gcloud secrets create $SECRET_ID \ --replication-policy="automatic" printf $HF_TOKEN | gcloud secrets versions add $SECRET_ID --data-file=-
- Berikan peran Secret Manager Secret Accessor ke akun layanan Anda:
gcloud secrets add-iam-policy-binding $SECRET_ID \ --member serviceAccount:$SERVICE_ACCOUNT_ADDRESS \ --role='roles/secretmanager.secretAccessor'
- Buat bucket yang akan menghosting model yang telah di-fine-tune:
gcloud storage buckets create -l $REGION gs://$BUCKET_NAME
- Berikan akses akun layanan Anda ke bucket:
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_NAME \ --member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \ --role=roles/storage.objectAdmin
- Buat repositori Artifact Registry untuk menyimpan image container:
gcloud artifacts repositories create $AR_REPO \ --repository-format=docker \ --location=$REGION \ --description="codelab for finetuning using CR jobs" \ --project=$PROJECT_ID
4. Membuat gambar tugas Cloud Run
Pada langkah berikutnya, Anda akan membuat kode yang melakukan hal berikut:
- Mengimpor model Gemma dari Hugging Face
- Melakukan penyesuaian pada model dengan set data dari Hugging Face. Tugas menggunakan satu GPU L4 untuk penyesuaian halus.
- Mengupload model yang telah dioptimalkan yang disebut
new_model
ke bucket Cloud Storage Anda
- Buat direktori untuk kode tugas penyesuaian Anda.
mkdir codelab-finetuning-job cd codelab-finetuning-job
- Buat file bernama
finetune.py
# Copyright 2024 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 transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, ) from peft import LoraConfig, PeftModel 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-2b") # The instruction dataset to use dataset_name = "b-mc2/sql-create-context" # Fine-tuned model name new_model = os.getenv("NEW_MODEL", "gemma-2b-sql") ################################################################################ # QLoRA parameters ################################################################################ # LoRA attention dimension lora_r = int(os.getenv("LORA_R", "4")) # Alpha parameter for LoRA scaling lora_alpha = int(os.getenv("LORA_ALPHA", "8")) # Dropout probability for LoRA layers lora_dropout = 0.1 ################################################################################ # bitsandbytes parameters ################################################################################ # Activate 4-bit precision base model loading use_4bit = True # Compute dtype for 4-bit base models bnb_4bit_compute_dtype = "float16" # Quantization type (fp4 or nf4) bnb_4bit_quant_type = "nf4" # Activate nested quantization for 4-bit base models (double quantization) use_nested_quant = False ################################################################################ # TrainingArguments parameters ################################################################################ # Output directory where the model predictions and checkpoints will be stored output_dir = "./results" # Number of training epochs num_train_epochs = 1 # Enable fp16/bf16 training (set bf16 to True with an A100) fp16 = True bf16 = False # Batch size per GPU for training per_device_train_batch_size = int(os.getenv("TRAIN_BATCH_SIZE", "1")) # Batch size per GPU for evaluation per_device_eval_batch_size = int(os.getenv("EVAL_BATCH_SIZE", "2")) # Number of update steps to accumulate the gradients for gradient_accumulation_steps = int(os.getenv("GRADIENT_ACCUMULATION_STEPS", "1")) # Enable gradient checkpointing gradient_checkpointing = True # Maximum gradient normal (gradient clipping) max_grad_norm = 0.3 # Initial learning rate (AdamW optimizer) learning_rate = 2e-4 # Weight decay to apply to all layers except bias/LayerNorm weights weight_decay = 0.001 # Optimizer to use optim = "paged_adamw_32bit" # Learning rate schedule lr_scheduler_type = "cosine" # Number of training steps (overrides num_train_epochs) max_steps = -1 # Ratio of steps for a linear warmup (from 0 to learning rate) warmup_ratio = 0.03 # Group sequences into batches with same length # Saves memory and speeds up training considerably group_by_length = True # Save checkpoint every X updates steps save_steps = 0 # Log every X updates steps logging_steps = int(os.getenv("LOGGING_STEPS", "50")) ################################################################################ # SFT parameters ################################################################################ # Maximum sequence length to use max_seq_length = int(os.getenv("MAX_SEQ_LENGTH", "512")) # Pack multiple short examples in the same input sequence to increase efficiency packing = False # Load the entire model on the GPU 0 device_map = {'':torch.cuda.current_device()} # Set limit to a positive number limit = int(os.getenv("DATASET_LIMIT", "5000")) dataset = load_dataset(dataset_name, split="train") if limit != -1: dataset = dataset.shuffle(seed=42).select(range(limit)) def transform(data): question = data['question'] context = data['context'] answer = data['answer'] template = "Question: {question}\nContext: {context}\nAnswer: {answer}" return {'text': template.format(question=question, context=context, answer=answer)} transformed = dataset.map(transform) # Load tokenizer and model with QLoRA configuration compute_dtype = getattr(torch, bnb_4bit_compute_dtype) bnb_config = BitsAndBytesConfig( load_in_4bit=use_4bit, bnb_4bit_quant_type=bnb_4bit_quant_type, bnb_4bit_compute_dtype=compute_dtype, bnb_4bit_use_double_quant=use_nested_quant, ) # Check GPU compatibility with bfloat16 if compute_dtype == torch.float16 and use_4bit: major, _ = torch.cuda.get_device_capability() if major >= 8: print("=" * 80) print("Your GPU supports bfloat16") print("=" * 80) # 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 # Load LLaMA tokenizer tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) tokenizer.pad_token = tokenizer.eos_token tokenizer.padding_side = "right" # Load LoRA configuration peft_config = LoraConfig( lora_alpha=lora_alpha, lora_dropout=lora_dropout, r=lora_r, bias="none", task_type="CAUSAL_LM", target_modules=["q_proj", "v_proj"] ) # Set training parameters training_arguments = TrainingArguments( output_dir=output_dir, num_train_epochs=num_train_epochs, per_device_train_batch_size=per_device_train_batch_size, gradient_accumulation_steps=gradient_accumulation_steps, optim=optim, save_steps=save_steps, logging_steps=logging_steps, learning_rate=learning_rate, weight_decay=weight_decay, fp16=fp16, bf16=bf16, max_grad_norm=max_grad_norm, max_steps=max_steps, warmup_ratio=warmup_ratio, group_by_length=group_by_length, lr_scheduler_type=lr_scheduler_type, ) trainer = SFTTrainer( model=model, train_dataset=transformed, peft_config=peft_config, dataset_text_field="text", max_seq_length=max_seq_length, tokenizer=tokenizer, args=training_arguments, packing=packing, ) trainer.train() trainer.model.save_pretrained(new_model) # 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 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)
- Buat 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
- Buat
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
- Build container di repositori Artifact Registry Anda:
gcloud builds submit \ --tag $REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/$IMAGE_NAME \ --region $REGION
5. Men-deploy dan menjalankan tugas
Pada langkah ini, Anda akan membuat konfigurasi YAML untuk tugas dengan traffic keluar VPC langsung untuk upload yang lebih cepat ke Google Cloud Storage.
Perhatikan bahwa file ini berisi variabel yang akan Anda perbarui pada langkah berikutnya.
- Buat file bernama
finetune-job.yaml.tmpl
:apiVersion: run.googleapis.com/v1 kind: Job metadata: name: $JOB_NAME labels: cloud.googleapis.com/location: $REGION annotations: run.googleapis.com/launch-stage: ALPHA spec: template: metadata: annotations: run.googleapis.com/execution-environment: gen2 run.googleapis.com/network-interfaces: '[{"network":"default","subnetwork":"default"}]' spec: parallelism: 1 taskCount: 1 template: spec: serviceAccountName: $SERVICE_ACCOUNT_ADDRESS containers: - name: $IMAGE_NAME image: $REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/$IMAGE_NAME env: - name: MODEL_NAME value: "google/gemma-2b" - name: NEW_MODEL value: "gemma-2b-sql-finetuned" - name: BUCKET_NAME value: "$BUCKET_NAME" - name: LORA_R value: "8" - name: LORA_ALPHA value: "16" - name: GRADIENT_ACCUMULATION_STEPS value: "2" - name: DATASET_LIMIT value: "1000" - name: LOGGING_STEPS value: "5" - name: HF_TOKEN valueFrom: secretKeyRef: key: 'latest' name: HF_TOKEN resources: limits: cpu: 8000m nvidia.com/gpu: '1' memory: 32Gi volumeMounts: - mountPath: /finetune/new_model name: finetuned_model volumes: - name: finetuned_model csi: driver: gcsfuse.run.googleapis.com readOnly: false volumeAttributes: bucketName: $BUCKET_NAME maxRetries: 3 timeoutSeconds: '3600' nodeSelector: run.googleapis.com/accelerator: nvidia-l4
- Ganti variabel dalam YAML dengan variabel lingkungan Anda dengan menjalankan perintah berikut:
envsubst < finetune-job.yaml.tmpl > finetune-job.yaml
- Buat Tugas Cloud Run:
gcloud alpha run jobs replace finetune-job.yaml
- Jalankan tugas:
gcloud alpha run jobs execute $JOB_NAME --region $REGION --async
Tugas ini akan memerlukan waktu sekitar 10 menit untuk diselesaikan. Anda dapat memeriksa statusnya menggunakan link yang diberikan dalam output perintah terakhir.
6. Menggunakan layanan Cloud Run untuk menayangkan model yang telah dioptimalkan dengan vLLM
Pada langkah ini, Anda akan men-deploy layanan Cloud Run. Konfigurasi ini menggunakan VPC langsung untuk mengakses bucket Cloud Storage melalui jaringan pribadi agar download lebih cepat.
Perhatikan bahwa file ini berisi variabel yang akan Anda perbarui pada langkah berikutnya.
- Buat file
service.yaml.tmpl
:apiVersion: serving.knative.dev/v1 kind: Service metadata: name: serve-gemma-sql labels: cloud.googleapis.com/location: $REGION annotations: run.googleapis.com/launch-stage: BETA run.googleapis.com/ingress: all run.googleapis.com/ingress-status: all spec: template: metadata: labels: annotations: autoscaling.knative.dev/maxScale: '1' run.googleapis.com/cpu-throttling: 'false' run.googleapis.com/gpu-zonal-redundancy-disabled: 'true' run.googleapis.com/network-interfaces: '[{"network":"default","subnetwork":"default"}]' spec: containers: - name: serve-finetuned image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20250505_0916_RC00 ports: - name: http1 containerPort: 8000 resources: limits: cpu: 8000m nvidia.com/gpu: '1' memory: 32Gi volumeMounts: - name: fuse mountPath: /finetune/new_model command: ["python3", "-m", "vllm.entrypoints.api_server"] args: - --model=/finetune/new_model - --tensor-parallel-size=1 env: - name: MODEL_ID value: 'new_model' - name: HF_HUB_OFFLINE value: '1' volumes: - name: fuse csi: driver: gcsfuse.run.googleapis.com volumeAttributes: bucketName: $BUCKET_NAME nodeSelector: run.googleapis.com/accelerator: nvidia-l4
- Perbarui file
service.yaml
dengan nama bucket Anda.envsubst < service.yaml.tmpl > service.yaml
- Men-deploy Layanan Cloud Run Anda:
gcloud alpha run services replace service.yaml
7. Menguji model yang telah di-fine-tune
Pada langkah ini, Anda akan meminta model untuk menguji penyesuaian.
- Dapatkan URL layanan untuk layanan Cloud Run Anda:
SERVICE_URL=$(gcloud run services describe serve-gemma-sql --platform managed --region $REGION --format 'value(status.url)')
- Buat perintah untuk model Anda.
USER_PROMPT="Question: What are the first name and last name of all candidates? Context: CREATE TABLE candidates (candidate_id VARCHAR); CREATE TABLE people (first_name VARCHAR, last_name VARCHAR, person_id VARCHAR)"
- Panggil layanan Anda menggunakan CURL untuk meminta model Anda:
curl -X POST $SERVICE_URL/generate \ -H "Content-Type: application/json" \ -H "Authorization: bearer $(gcloud auth print-identity-token)" \ -d @- <<EOF { "prompt": "${USER_PROMPT}" } EOF
Anda akan melihat respons seperti berikut:
{"predictions":["Prompt:\nQuestion: What are the first name and last name of all candidates? Context: CREATE TABLE candidates (candidate_id VARCHAR); CREATE TABLE people (first_name VARCHAR, last_name VARCHAR, person_id VARCHAR)\nOutput:\n CREATE TABLE people_to_candidates (candidate_id VARCHAR, person_id VARCHAR) CREATE TABLE people_to_people (person_id VARCHAR, person_id VARCHAR) CREATE TABLE people_to_people_to_candidates (person_id VARCHAR, candidate_id"]}
8. Selamat!
Selamat, Anda telah menyelesaikan codelab.
Sebaiknya tinjau dokumentasi Cloud Run.
Yang telah kita bahas
- Cara melakukan penyesuaian halus menggunakan GPU Tugas Cloud Run
- Cara menayangkan model menggunakan Cloud Run dengan vLLM
- Cara menggunakan konfigurasi VPC Langsung untuk Tugas GPU agar upload dan penayangan model lebih cepat
9. Pembersihan
Untuk menghindari tagihan yang tidak disengaja, misalnya, jika layanan Cloud Run tidak sengaja dipanggil lebih dari alokasi pemanggilan Cloud Run bulanan Anda di paket gratis, Anda dapat menghapus layanan Cloud Run yang dibuat di Langkah 6.
Untuk menghapus layanan Cloud Run, buka Cloud Console Cloud Run di https://console.cloud.google.com/run dan hapus layanan serve-gemma-sql
.
Untuk menghapus seluruh project, buka Manage Resources, pilih project yang Anda buat di Langkah 2, lalu pilih Delete. Jika menghapus project, Anda harus mengubah project di Cloud SDK. Anda dapat melihat daftar semua project yang tersedia dengan menjalankan gcloud projects list
.