Melatih Qwen2 di cluster Slurm A4

Tutorial ini menunjukkan cara melatih model bahasa besar (LLM) di cluster Slurm multi-GPU, multi-node di Google Cloud. Model yang Anda gunakan dalam tutorial ini didasarkan pada model parameter 1,5 miliar Qwen2. Cluster Slurm menggunakan dua virtual machine (VM) a4-highgpu-8g, yang masing-masing memiliki 8 GPU NVIDIA B200.

Dua proses utama yang dijelaskan dalam tutorial ini adalah sebagai berikut:

  1. Deploy cluster Slurm berperforma tinggi dan siap produksi menggunakan Google Cloud Cluster Toolkit. Sebagai bagian dari deployment ini, Anda akan membuat image VM kustom dengan software yang diperlukan sudah diinstal sebelumnya. Anda juga menyiapkan instance Filestore bersama, dan mengonfigurasi jaringan RDMA berkecepatan tinggi.
  2. Setelah cluster di-deploy, Anda menjalankan tugas pra-pelatihan terdistribusi dengan menggunakan kumpulan skrip yang disertakan dalam tutorial ini. Tugas ini memanfaatkan library Hugging Face Accelerate.

Tutorial ini ditujukan untuk engineer, peneliti, administrator, dan operator platform machine learning (ML), serta spesialis data dan AI yang tertarik untuk men-deploy cluster Slurm berperforma tinggi di Google Cloud untuk melatih LLM.

Tujuan

  • Akses model Qwen2 menggunakan Hugging Face.
  • Siapkan lingkungan Anda.
  • Buat dan deploy cluster Slurm A4 tingkat produksi.
  • Latih model Qwen2 menggunakan library Accelerate .
  • Pantau tugas Anda.
  • Jalankan pembersihan.

Biaya

Dalam dokumen ini, Anda akan menggunakan komponen Google Cloudyang dapat ditagih berikut:

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga.

Pengguna Google Cloud baru mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Sebelum memulai

  1. Login ke akun Google Cloud Anda. Jika Anda baru menggunakan Google Cloud, buat akun untuk mengevaluasi performa produk kami dalam skenario dunia nyata. Pelanggan baru juga mendapatkan kredit gratis senilai $300 untuk menjalankan, menguji, dan men-deploy workload.
  2. Instal Google Cloud CLI.

  3. Jika Anda menggunakan penyedia identitas (IdP) eksternal, Anda harus login ke gcloud CLI dengan identitas gabungan Anda terlebih dahulu.

  4. Untuk melakukan inisialisasi gcloud CLI, jalankan perintah berikut:

    gcloud init
  5. Buat atau pilih Google Cloud project.

    Peran yang diperlukan untuk memilih atau membuat project

    • Pilih project: Memilih project tidak memerlukan peran IAM tertentu—Anda dapat memilih project mana pun yang telah diberi peran.
    • Membuat project: Untuk membuat project, Anda memerlukan peran Pembuat Project (roles/resourcemanager.projectCreator), yang berisi izin resourcemanager.projects.create. Pelajari cara memberikan peran.
    • Buat Google Cloud project:

      gcloud projects create PROJECT_ID

      Ganti PROJECT_ID dengan nama untuk Google Cloud project yang Anda buat.

    • Pilih project Google Cloud yang Anda buat:

      gcloud config set project PROJECT_ID

      Ganti PROJECT_ID dengan nama project Google Cloud Anda.

  6. Verifikasi bahwa penagihan diaktifkan untuk project Google Cloud Anda.

  7. Aktifkan API yang diperlukan:

    Peran yang diperlukan untuk mengaktifkan API

    Untuk mengaktifkan API, Anda memerlukan peran IAM Service Usage Admin (roles/serviceusage.serviceUsageAdmin), yang berisi izin serviceusage.services.enable. Pelajari cara memberikan peran.

    gcloud services enable gcloud services enable compute.googleapis.com file.googleapis.com logging.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com
  8. Instal Google Cloud CLI.

  9. Jika Anda menggunakan penyedia identitas (IdP) eksternal, Anda harus login ke gcloud CLI dengan identitas gabungan Anda terlebih dahulu.

  10. Untuk melakukan inisialisasi gcloud CLI, jalankan perintah berikut:

    gcloud init
  11. Buat atau pilih Google Cloud project.

    Peran yang diperlukan untuk memilih atau membuat project

    • Pilih project: Memilih project tidak memerlukan peran IAM tertentu—Anda dapat memilih project mana pun yang telah diberi peran.
    • Membuat project: Untuk membuat project, Anda memerlukan peran Pembuat Project (roles/resourcemanager.projectCreator), yang berisi izin resourcemanager.projects.create. Pelajari cara memberikan peran.
    • Buat Google Cloud project:

      gcloud projects create PROJECT_ID

      Ganti PROJECT_ID dengan nama untuk Google Cloud project yang Anda buat.

    • Pilih project Google Cloud yang Anda buat:

      gcloud config set project PROJECT_ID

      Ganti PROJECT_ID dengan nama project Google Cloud Anda.

  12. Verifikasi bahwa penagihan diaktifkan untuk project Google Cloud Anda.

  13. Aktifkan API yang diperlukan:

    Peran yang diperlukan untuk mengaktifkan API

    Untuk mengaktifkan API, Anda memerlukan peran IAM Service Usage Admin (roles/serviceusage.serviceUsageAdmin), yang berisi izin serviceusage.services.enable. Pelajari cara memberikan peran.

    gcloud services enable gcloud services enable compute.googleapis.com file.googleapis.com logging.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com
  14. Memberikan peran ke akun pengguna Anda. Jalankan perintah berikut satu kali untuk setiap peran IAM berikut: roles/compute.admin, roles/iam.serviceAccountUser, roles/file.editor, roles/storage.admin, roles/serviceusage.serviceUsageAdmin

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

    Ganti kode berikut:

    • PROJECT_ID: Project ID Anda.
    • USER_IDENTIFIER: ID untuk akun pengguna Anda. Misalnya, myemail@example.com.
    • ROLE: Peran IAM yang Anda berikan ke akun pengguna Anda.
  15. Aktifkan akun layanan default untuk project Google Cloud Anda:
    gcloud iam service-accounts enable PROJECT_NUMBER-compute@developer.gserviceaccount.com \
        --project=PROJECT_ID

    Ganti PROJECT_NUMBER dengan nomor project Anda. Untuk meninjau nomor project Anda, lihat Mendapatkan project yang sudah ada.

  16. Berikan peran Editor (roles/editor) ke akun layanan default:
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
        --role=roles/editor
  17. Buat kredensial autentikasi lokal untuk akun pengguna Anda:
    gcloud auth application-default login
  18. Aktifkan Login OS untuk project Anda:
    gcloud compute project-info add-metadata --metadata=enable-oslogin=TRUE
  19. Login atau buat akun Hugging Face.

Mengakses Qwen2 menggunakan Hugging Face

Untuk menggunakan Hugging Face guna mengakses Qwen2, lakukan hal berikut:

  1. Tandatangani perjanjian izin untuk menggunakan Qwen 2 1,5B.

  2. Buat token akses read.

Menyiapkan lingkungan Anda

Untuk menyiapkan lingkungan Anda, ikuti langkah-langkah berikut:

  1. Buat clone repositori GitHub Cluster Toolkit:

    git clone https://github.com/GoogleCloudPlatform/cluster-toolkit.git
    
  2. Membuat bucket Cloud Storage:

    gcloud storage buckets create gs://BUCKET_NAME \
        --project=PROJECT_ID
    

    Ganti kode berikut:

    • BUCKET_NAME: nama untuk bucket Cloud Storage Anda yang mengikuti persyaratan penamaan bucket.

    • PROJECT_ID: ID projectGoogle Cloud tempat Anda ingin membuat bucket Cloud Storage.

Membuat cluster Slurm A4

Untuk membuat cluster Slurm A4, ikuti langkah-langkah berikut:

  1. Buka direktori cluster-toolkit:

    cd cluster-toolkit
    
  2. Jika Anda baru pertama kali menggunakan Cluster Toolkit, bangun biner gcluster:

    make
    
  3. Buka direktori examples/machine-learning/a4-highgpu-8g:

    cd examples/machine-learning/a4-highgpu-8g/
    
  4. Buka file a4high-slurm-deployment.yaml, lalu edit sebagai berikut:

    terraform_backend_defaults:
      type: gcs
      configuration:
        bucket: BUCKET_NAME
    
    vars:
      deployment_name: a4-high
      project_id: PROJECT_ID
      region: REGION
      zone: ZONE
      a4h_cluster_size: 2
      a4h_reservation_name: RESERVATION_URL
    

    Ganti kode berikut:

    • BUCKET_NAME: nama bucket Cloud Storage yang Anda buat di bagian sebelumnya.

    • PROJECT_ID: ID Google Cloud project tempat Cloud Storage Anda berada dan tempat Anda ingin membuat cluster Slurm.

    • REGION: region tempat pemesanan Anda berada.

    • ZONE: zona tempat pemesanan Anda berada.

    • RESERVATION_URL: URL reservasi yang ingin Anda gunakan untuk membuat cluster Slurm. Berdasarkan project tempat pemesanan berada, tentukan salah satu nilai berikut:

      • Reservasi ada di project Anda: RESERVATION_NAME

      • Pemesanan ada di project lain, dan project Anda dapat menggunakan pemesanan: projects/RESERVATION_PROJECT_ID/reservations/RESERVATION_NAME

  5. Deploy cluster:

    ./gcluster deploy -d examples/machine-learning/a4-highgpu-8g/a4high-slurm-deployment.yaml examples/machine-learning/a4-highgpu-8g/a4high-slurm-blueprint.yaml --auto-approve
    

    Perintah ./gcluster deploy adalah proses dua fase, yang adalah sebagai berikut:

    • Fase pertama membuat image kustom dengan semua software yang sudah diinstal sebelumnya, yang dapat memerlukan waktu hingga 35 menit untuk diselesaikan.

    • Fase kedua men-deploy cluster menggunakan image kustom tersebut. Proses ini akan selesai lebih cepat daripada fase pertama.

    Jika fase pertama berhasil, tetapi fase kedua gagal, Anda dapat mencoba men-deploy cluster Slurm lagi dengan melewati fase pertama:

    ./gcluster deploy -d examples/machine-learning/a4-highgpu-8g/a4high-slurm-deployment.yaml examples/machine-learning/a4-highgpu-8g/a4high-slurm-blueprint.yaml --auto-approve --skip "image" -w
    

Siapkan workload Anda

Untuk menyiapkan beban kerja Anda, ikuti langkah-langkah berikut:

  1. Buat skrip beban kerja.

  2. Upload skrip ke cluster Slurm.

  3. Hubungkan ke cluster Slurm.

  4. Instal framework dan alat.

Membuat skrip beban kerja

Untuk membuat skrip yang akan digunakan workload pelatihan Anda, ikuti langkah-langkah berikut:

  1. Untuk menyiapkan lingkungan virtual Python, buat file install_environment.sh dengan konten berikut:

    #!/bin/bash
    # This script should be run ONCE on the login node to set up the
    # shared Python virtual environment.
    
    set -e
    echo "--- Creating Python virtual environment in /home ---"
    python3 -m venv ~/.venv
    echo "--- Activating virtual environment ---"
    source ~/.venv/bin/activate
    
    echo "--- Installing build dependencies ---"
    pip install --upgrade pip wheel packaging
    
    echo "--- Installing PyTorch for CUDA 12.8 ---"
    pip install torch --index-url https://download.pytorch.org/whl/cu128
    
    echo "--- Installing application requirements ---"
    pip install -r requirements.txt
    
    echo "--- Environment setup complete. You can now submit jobs with sbatch. ---"
    
  2. Untuk menentukan konfigurasi tugas penyesuaian, buat file accelerate_config.yaml dengan konten berikut:

    # Default configuration for a 2-node, 8-GPU-per-node (16 total GPUs) FSDP training job.
    
    compute_environment: "LOCAL_MACHINE"
    distributed_type: "FSDP"
    downcast_bf16: "no"
    machine_rank: 0
    main_training_function: "main"
    mixed_precision: "bf16"
    num_machines: 2
    num_processes: 16
    rdzv_backend: "static"
    same_network: true
    tpu_env: []
    use_cpu: false
    
  3. Untuk menentukan tugas yang akan dijalankan pada cluster Slurm, buat file submit.slurm dengan konten berikut:

    #!/bin/bash
    #SBATCH --job-name=qwen2-pretrain-smollm-fineweb
    #SBATCH --nodes=2
    #SBATCH --ntasks-per-node=8 # 8 tasks per node
    #SBATCH --gpus-per-task=1   # 1 GPU per task
    #SBATCH --partition=a4high
    #SBATCH --output=logs/slurm-%j.out
    #SBATCH --error=logs/slurm-%j.err
    
    set -e
    echo "--- Slurm Job Started ---"
    
    # --- STAGE 1: Setup environment and pre-process data on each node's local SSD ---
    # This command runs once per node.
    srun --ntasks=$SLURM_NNODES --ntasks-per-node=1 bash -c '
      set -e
      echo "Setting up local environment on $(hostname)..."
      LOCAL_VENV="/mnt/localssd/venv_job_${SLURM_JOB_ID}"
      LOCAL_CACHE="/mnt/localssd/hf_cache_job_${SLURM_JOB_ID}"
      PROCESSED_DATA_DIR="/mnt/localssd/processed_data_${SLURM_JOB_ID}"
      rsync -a --info=progress2 ~/./.venv/ ${LOCAL_VENV}/
      mkdir -p ${LOCAL_CACHE} ${PROCESSED_DATA_DIR}
    
      echo "Pre-processing data on $(hostname)..."
      source ${LOCAL_VENV}/bin/activate
      export HF_HOME=${LOCAL_CACHE}
      export HF_DATASETS_CACHE=${LOCAL_CACHE}
    
      # This runs the new preprocessing script. It ensures only ONE process per node
      # downloads and processes the data, avoiding rate limiting and redundant work.
      python preprocess_data.py \
        --dataset_name "HuggingFaceFW/fineweb-edu" \
        --dataset_config "CC-MAIN-2024-10" \
        --tokenizer_id "Qwen/Qwen2-1.5B" \
        --max_seq_length 1024 \
        --output_path ${PROCESSED_DATA_DIR}
    
      echo "Setup on $(hostname) complete."
    '
    
    # --- STAGE 2: Run the Training Job using the Local Environment ---
    echo "--- Starting Training ---"
    
    LOCAL_VENV="/mnt/localssd/venv_job_${SLURM_JOB_ID}"
    PROCESSED_DATA_DIR="/mnt/localssd/processed_data_${SLURM_JOB_ID}"
    LOCAL_OUTPUT_DIR="/mnt/localssd/outputs_${SLURM_JOB_ID}"
    mkdir -p ${LOCAL_OUTPUT_DIR}
    
    # This is the main training command. It launches one Python process per GPU.
    srun --ntasks=$((SLURM_NNODES * 8)) --gpus-per-task=1 bash -c "
      source ${LOCAL_VENV}/bin/activate
    
      # The training script now loads the pre-processed data from the local SSD.
      python train.py \
        --model_config_id "Qwen/Qwen2-1.5B" \
        --preprocessed_data_path ${PROCESSED_DATA_DIR} \
        --output_dir ${LOCAL_OUTPUT_DIR} \
        --per_device_train_batch_size 4 \
        --gradient_accumulation_steps 4 \
        --max_steps 10000 \
        --learning_rate 5e-5 \
        --save_strategy steps \
        --save_steps 500
    "
    
    # --- STAGE 3: Copy Final Model from Local SSD to Home Directory ---
    echo "--- Copying final model from local SSD to /home ---"
    # This command runs only on the first node of the job allocation
    # and copies the final model back to the persistent shared directory.
    srun --nodes=1 --ntasks=1 --ntasks-per-node=1 bash -c "
      rsync -a --info=progress2 ${LOCAL_OUTPUT_DIR}/ ~/qwen2-from-scratch-on-smollm-fineweb/
    "
    
    echo "--- Slurm Job Finished ---"
    
  4. Untuk menentukan dependensi bagi tugas penyesuaian Anda, buat file requirements.txt dengan konten berikut:

    # Hugging Face Libraries (Pinned to recent, stable versions for reproducibility)
    transformers==4.53.3
    datasets==4.0.0
    accelerate==1.9.0
    evaluate==0.4.5
    bitsandbytes==0.46.1
    trl==0.19.1
    peft==0.16.0
    
    # Other dependencies
    tensorboard==2.20.0
    protobuf==6.31.1
    sentencepiece==0.2.0
    
  5. Untuk mendownload, melakukan tokenisasi, dan memproses awal set data ke dalam format yang siap untuk pelatihan, buat file preprocess_data.py dengan konten berikut:

    import argparse
    from datasets import load_dataset
    from transformers import AutoTokenizer
    import os
    from itertools import chain
    
    def get_args():
       parser = argparse.ArgumentParser(description="Download and preprocess a dataset.")
       parser.add_argument("--dataset_name", type=str, required=True)
       parser.add_argument("--dataset_config", type=str, required=True)
       parser.add_argument("--tokenizer_id", type=str, required=True)
       parser.add_argument("--max_seq_length", type=int, required=True)
       parser.add_argument("--output_path", type=str, required=True, help="Path to save the processed dataset.")
       return parser.parse_args()
    
    def main():
       args = get_args()
    
       if os.path.exists(args.output_path) and os.listdir(args.output_path):
           print(f"Processed dataset already exists at {args.output_path}. Skipping.")
           return
    
       # 1. Load tokenizer
       tokenizer = AutoTokenizer.from_pretrained(args.tokenizer_id)
    
       # 2. Load raw dataset
       print(f"Loading raw dataset {args.dataset_name}...")
       raw_dataset = load_dataset(args.dataset_name, name=args.dataset_config, split="train")
    
       # 3. Tokenize
       def tokenize_function(examples):
           return tokenizer(examples["text"])
    
       num_proc = os.cpu_count()
       print(f"Tokenizing dataset using {num_proc} processes...")
       print("Tokenizing dataset...")
       tokenized_dataset = raw_dataset.map(
           tokenize_function,
           batched=True,
           remove_columns=raw_dataset.column_names,
           desc="Running tokenizer on dataset",
           num_proc=num_proc,
       )
    
       # 4. Group texts
       def group_texts(examples):
           concatenated_examples = {k: list(chain.from_iterable(examples[k])) for k in examples.keys()}
           total_length = len(concatenated_examples[list(examples.keys())[0]])
           if total_length >= args.max_seq_length:
               total_length = (total_length // args.max_seq_length) * args.max_seq_length
           result = {
               k: [t[i : i + args.max_seq_length] for i in range(0, total_length, args.max_seq_length)]
               for k, t in concatenated_examples.items()
           }
           result["labels"] = result["input_ids"].copy()
           return result
    
       print("Grouping texts...")
       lm_dataset = tokenized_dataset.map(
           group_texts,
           batched=True,
           desc=f"Grouping texts in chunks of {args.max_seq_length}",
           num_proc=num_proc,
       )
    
       # 5. Save to disk
       print(f"Saving processed dataset to {args.output_path}...")
       lm_dataset.save_to_disk(args.output_path)
       print("Preprocessing complete.")
    
    if __name__ == "__main__":
       main()
    
  6. Untuk menentukan petunjuk bagi tugas Anda, buat file train.py dengan konten berikut:

    import torch
    import argparse
    from datasets import load_dataset, load_from_disk
    import os
    from transformers import (
        AutoConfig,
        AutoTokenizer,
        AutoModelForCausalLM,
        Trainer,
        TrainingArguments,
        DataCollatorForLanguageModeling,
    )
    from huggingface_hub import login
    
    def get_args():
        parser = argparse.ArgumentParser()
        parser.add_argument("--model_config_id", type=str, default="Qwen/Qwen2-1.5B", help="Hugging Face model config to use for architecture.")
        # Data arguments - used if preprocessed data is not available
        parser.add_argument("--dataset_name", type=str, default="HuggingFaceFW/fineweb-edu", help="Hugging Face dataset for pre-training.")
        parser.add_argument("--dataset_config", type=str, default="CC-MAIN-2024-10", help="Config for the smollm-corpus dataset, e.g., 'fineweb-edu-dedup'.")
        parser.add_argument("--preprocessed_data_path", type=str, default=None, help="Path to a preprocessed dataset on disk. If provided, skips download and processing.")
        # General arguments
        parser.add_argument("--hf_token", type=str, default=None, help="Hugging Face token for private models/tokenizers")
        parser.add_argument("--output_dir", type=str, default="qwen2-from-scratch-on-olmo", help="Directory to save model checkpoints")
    
        # TrainingArguments
        parser.add_argument("--max_seq_length", type=int, default=1024, help="Maximum sequence length")
        parser.add_argument("--num_train_epochs", type=int, default=1, help="Number of training epochs")
        parser.add_argument("--max_steps", type=int, default=-1, help="If set to a positive number, it overrides num_train_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=5e-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=500, help="Save checkpoint every X steps")
    
        return parser.parse_args()
    
    def main():
        args = get_args()
    
        # --- 1. Setup and Login ---
        if args.hf_token:
            login(args.hf_token)
    
        # --- 2. Load Tokenizer ---
        # We load the tokenizer from the specified config ID to ensure compatibility
        # with the model architecture (e.g., special tokens).
        tokenizer = AutoTokenizer.from_pretrained(args.model_config_id)
    
        # --- 4. Initialize Model from Scratch ---
        print(f"Initializing a new model from {args.model_config_id} configuration...")
        config = AutoConfig.from_pretrained(args.model_config_id)
        model = AutoModelForCausalLM.from_config(config)
    
        print(f"Model has {model.num_parameters():,} parameters.")
    
        # --- 3. Load or Create and prepare the training dataset ---
        if args.preprocessed_data_path and os.path.exists(args.preprocessed_data_path):
            print(f"Loading preprocessed dataset from {args.preprocessed_data_path}...")
            lm_dataset = load_from_disk(args.preprocessed_data_path)
        else:
            print("No preprocessed dataset found, starting from raw data...")
            raw_dataset = load_dataset(args.dataset_name, name=args.dataset_config, split="train")
    
            # Tokenization function
            def tokenize_function(examples):
                return tokenizer(examples["text"])
    
            tokenized_dataset = raw_dataset.map(
                tokenize_function,
                batched=True,
                remove_columns=raw_dataset.column_names,
                desc="Running tokenizer on dataset",
            )
    
            # Main data processing function that will concatenate all texts from our dataset
            # and generate chunks of max_seq_length.
            def group_texts(examples):
                # Concatenate all texts.
                concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
                total_length = len(concatenated_examples[list(examples.keys())[0]])
                # We drop the small remainder.
                if total_length >= args.max_seq_length:
                    total_length = (total_length // args.max_seq_length) * args.max_seq_length
                # Split by chunks of max_len.
                result = {
                    k: [t[i : i + args.max_seq_length] for i in range(0, total_length, args.max_seq_length)]
                    for k, t in concatenated_examples.items()
                }
                result["labels"] = result["input_ids"].copy()
                return result
    
            lm_dataset = tokenized_dataset.map(
                group_texts,
                batched=True,
                desc=f"Grouping texts in chunks of {args.max_seq_length}",
            )
    
        # --- 5. Configure Training Arguments ---
        # Check for bfloat16 support
        use_bf16 = torch.cuda.is_available() and torch.cuda.is_bf16_supported()
    
        training_args = TrainingArguments(
            output_dir=args.output_dir,
            num_train_epochs=args.num_train_epochs,
            max_steps=args.max_steps,
            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,
            save_total_limit=2, # Optional: Limit the number of checkpoints
            bf16=use_bf16,
            fp16=not use_bf16,
            optim="adamw_torch",
            lr_scheduler_type="cosine",
            warmup_ratio=0.03,
            report_to="tensorboard",
            gradient_checkpointing=True,
            # Required for gradient checkpointing with some parallelization strategies
            gradient_checkpointing_kwargs={"use_reentrant": False},
        )
    
        # --- 6. Create Trainer and Start Training ---
        # Data collator will take care of creating batches for causal language modeling
        data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
    
        trainer = Trainer(
            model=model,
            args=training_args,
            train_dataset=lm_dataset,
            # eval_dataset=... # Optional: if you have a validation set
            tokenizer=tokenizer,
            data_collator=data_collator,
        )
    
        print("Starting training from scratch...")
        trainer.train()
        print("Training finished.")
    
        # --- 7. Save the final model ---
        print(f"Saving final model to {args.output_dir}")
        trainer.save_model()
    
    if __name__ == "__main__":
        main()
    

Mengupload skrip ke cluster Slurm

Untuk mengupload skrip yang Anda buat di bagian sebelumnya ke cluster Slurm, ikuti langkah-langkah berikut:

  1. Untuk mengidentifikasi node login Anda, cantumkan semua VM A4 di project Anda:

    gcloud compute instances list --filter="machineType:a4-highgpu-8g"
    

    Nama node login mirip dengan a4-high-login-001.

  2. Upload skrip Anda ke direktori utama node login:

    gcloud compute scp \
      --project=PROJECT_ID \
      --zone=ZONE \
      --tunnel-through-iap \
      ./train.py \
      ./requirements.txt \
      ./submit.slurm \
      ./install_environment.sh \
      ./accelerate_config.yaml \
      "LOGIN_NODE_NAME":~/
    

    Ganti LOGIN_NODE_NAME dengan nama node login.

Menghubungkan ke cluster Slurm

Hubungkan ke cluster Slurm dengan menghubungkan ke node login melalui SSH:

gcloud compute ssh LOGIN_NODE_NAME \
    --project=PROJECT_ID \
    --tunnel-through-iap \
    --zone=ZONE

Menginstal framework dan alat

Setelah terhubung ke node login, instal framework dan alat dengan melakukan hal berikut:

  1. Buat variabel lingkungan untuk token akses Hugging Face Anda:

    export HUGGING_FACE_TOKEN="HUGGING_FACE_TOKEN"
    
  2. Siapkan lingkungan virtual Python dengan semua dependensi yang diperlukan:

    chmod +x install_environment.sh
    ./install_environment.sh
    

Mulai pra-pelatihan workload Anda

Untuk memulai pelatihan workload, lakukan hal berikut:

  1. Kirimkan tugas ke penjadwal Slurm:

    sbatch submit.slurm
    
  2. Di node login di cluster Slurm, Anda dapat memantau progres tugas dengan memeriksa file output yang dibuat di direktori home:

    tail -f logs/slurm-qwen2-pretrain-smollm-fineweb.err
    

    Jika tugas Anda berhasil dimulai, file .err akan menampilkan status progres yang diperbarui seiring progres tugas Anda.

Memantau workload Anda

Anda dapat memantau penggunaan GPU di cluster Slurm untuk memverifikasi bahwa tugas penyesuaian Anda berjalan secara efisien. Untuk melakukannya, buka link berikut di browser Anda:

https://console.cloud.google.com/monitoring/metrics-explorer?project=PROJECT_ID&pageState=%7B%22xyChart%22%3A%7B%22dataSets%22%3A%5B%7B%22timeSeriesFilter%22%3A%7B%22filter%22%3A%22metric.type%3D%5C%22agent.googleapis.com%2Fgpu%2Futilization%5C%22%20resource.type%3D%5C%22gce_instance%5C%22%22%2C%22perSeriesAligner%22%3A%22ALIGN_MEAN%22%7D%2C%22plotType%22%3A%22LINE%22%7D%5D%7D%7D

Saat memantau workload, Anda dapat melihat hal berikut:

  • Penggunaan GPU: untuk tugas penyesuaian yang berjalan lancar, Anda dapat melihat penggunaan semua 16 GPU (delapan GPU untuk setiap VM dalam cluster) meningkat dan stabil ke tingkat tertentu selama pelatihan.

  • Durasi tugas: tugas akan memerlukan waktu sekitar satu jam untuk diselesaikan.

Mendownload model Anda

Setelah berhasil menjalankan tugas, model terlatih Anda akan disimpan di direktori ~/qwen2-from-scratch-on-smollm-fineweb/ pada node login. Karena direktori bersama persisten ini di-mount di semua node dalam cluster Anda, checkpoint model Anda tetap tersedia meskipun setelah tugas selesai atau node komputasi dibatalkan alokasinya.

Anda dapat mendownload model tersimpan dari node login ke komputer lokal dengan menggunakan perintah gcloud compute scp, seperti yang ditunjukkan dalam contoh berikut:

# From your local machine
LOGIN_NODE_NAME="your-login-node-name" # e.g., a4high-login-001
PROJECT_ID="your-gcp-project-id"
ZONE="your-cluster-zone" # e.g., us-west4-a

gcloud compute scp --project="$PROJECT_ID" --zone="$ZONE" --tunnel-through-iap \
  "${LOGIN_NODE_NAME}":~/qwen2-from-scratch-on-smollm-fineweb/ ./qwen2-trained-model/ --recurse

Setelah mendownload model, Anda dapat melakukan hal berikut:

  • Memuat model untuk inferensi: Gunakan framework Hugging Face Transformers untuk memuat direktori qwen2-trained-model/ dan melakukan inferensi dengan model Qwen2 yang baru dilatih.
  • Penyesuaian tambahan: Gunakan checkpoint tersimpan sebagai titik awal untuk penyesuaian tambahan pada set data yang lebih spesifik.
  • Kirim model ke Hugging Face Hub: Bagikan model terlatih Anda dengan mengirimkannya ke Hugging Face Hub.

Pembersihan

Agar tidak perlu membayar biaya pada akun Google Cloud Anda untuk resource yang digunakan dalam tutorial ini, hapus project yang berisi resource tersebut, atau simpan project dan hapus setiap resource.

Menghapus project Anda

Menghapus Google Cloud project:

gcloud projects delete PROJECT_ID

Menghapus cluster Slurm

Untuk menghapus cluster Slurm, ikuti langkah-langkah berikut:

  1. Buka direktori cluster-toolkit.

  2. Hancurkan file Terraform dan semua resource yang dibuat:

    ./gcluster destroy a4-high --auto-approve
    

Langkah berikutnya