ปรับแต่ง Gemini บน Vertex AI

1. บทนำ

ในห้องทดลองนี้ คุณจะได้เรียนรู้วิธีการทำงานทั้งหมดของการปรับแต่งแบบมีผู้ดูแลในโมเดล Google Gemini เพื่อปรับให้เหมาะกับงานที่เฉพาะเจาะจง นั่นคือการสรุปบทความ แม้ว่าโมเดลภาษาขนาดใหญ่จะมีประสิทธิภาพ แต่ลักษณะการใช้งานทั่วไปหมายความว่าโมเดลเหล่านี้จะมีประสิทธิภาพมากขึ้นสำหรับกรณีการใช้งานเฉพาะผ่านการปรับแต่ง การฝึกโมเดลในชุดข้อมูลตัวอย่างคุณภาพสูงจะช่วยปรับปรุงความสอดคล้อง คุณภาพ และประสิทธิภาพของโมเดลสำหรับงานเป้าหมายได้

คุณจะใช้ Gemini 2.5 Flash ซึ่งเป็นโมเดลที่มีน้ำหนักเบาและคุ้มค่า และทำการปรับแต่งโดยใช้ Vertex AI

ภาพรวมสถาปัตยกรรม

สิ่งที่เราจะสร้างมีดังนี้

  • Cloud Shell: สภาพแวดล้อมในการพัฒนาซอฟต์แวร์
  • Cloud Storage: จัดเก็บข้อมูลการฝึก/การตรวจสอบในรูปแบบ JSONL
  • การฝึก Vertex AI: จัดการงานการปรับแต่ง
  • ปลายทาง Vertex AI: โฮสต์โมเดลที่ปรับแต่งแล้ว

สิ่งที่คุณจะได้เรียนรู้

  • เตรียมชุดข้อมูลคุณภาพสูงสำหรับการปรับแต่งภายใต้การควบคุมดูแล
  • กำหนดค่าและเปิดใช้งานงานการปรับแต่งโดยใช้ Vertex AI SDK สำหรับ Python
  • ประเมินโมเดลโดยใช้เมตริกอัตโนมัติ (คะแนน ROUGE)
  • เปรียบเทียบโมเดลพื้นฐานกับโมเดลที่ปรับแต่งแล้วเพื่อวัดผลการปรับปรุง

2. การตั้งค่าโปรเจ็กต์

บัญชี Google

หากยังไม่มีบัญชี Google ส่วนบุคคล คุณต้องสร้างบัญชี Google

ใช้บัญชีส่วนตัวแทนบัญชีของที่ทำงานหรือโรงเรียน

ลงชื่อเข้าใช้ Google Cloud Console

ลงชื่อเข้าใช้ Google Cloud Console โดยใช้บัญชี Google ส่วนตัว

เปิดใช้การเรียกเก็บเงิน

แลกรับเครดิต Google Cloud มูลค่า $5 (ไม่บังคับ)

หากต้องการจัดเวิร์กช็อปนี้ คุณต้องมีบัญชีสำหรับการเรียกเก็บเงินที่มีเครดิตอยู่บ้าง หากวางแผนที่จะใช้การเรียกเก็บเงินของคุณเอง ให้ข้ามขั้นตอนนี้

  1. คลิกลิงก์นี้ แล้วลงชื่อเข้าใช้ด้วยบัญชี Google ส่วนบุคคล คุณจะเห็นข้อความคล้ายกับนี้คลิกเพื่อให้สิทธิ์ Cloud Shell
  2. คลิกปุ่มคลิกที่นี่เพื่อเข้าถึงเครดิต ระบบจะนำคุณไปยังหน้าเพื่อตั้งค่าโปรไฟล์การเรียกเก็บเงินคลิกเพื่อให้สิทธิ์ Cloud Shell
  3. คลิกยืนยัน

ตอนนี้คุณเชื่อมต่อกับบัญชีสำหรับการเรียกเก็บเงินของ Google Cloud Platform เวอร์ชันทดลองใช้งานแล้ว

ภาพหน้าจอของภาพรวมการเรียกเก็บเงิน

สร้างโปรเจ็กต์ (ไม่บังคับ)

หากไม่มีโปรเจ็กต์ปัจจุบันที่ต้องการใช้สำหรับแล็บนี้ ให้สร้างโปรเจ็กต์ใหม่ที่นี่

3. เปิดเครื่องมือแก้ไข Cloud Shell

  1. คลิกลิงก์นี้เพื่อไปยัง Cloud Shell Editor โดยตรง
  2. หากระบบแจ้งให้ให้สิทธิ์ในวันนี้ ให้คลิกให้สิทธิ์เพื่อดำเนินการต่อคลิกเพื่อให้สิทธิ์ Cloud Shell
  3. หากเทอร์มินัลไม่ปรากฏที่ด้านล่างของหน้าจอ ให้เปิดโดยทำดังนี้
    • คลิกดู
    • คลิก Terminalเปิดเทอร์มินัลใหม่ใน Cloud Shell Editor
  4. ในเทอร์มินัล ให้ตั้งค่าโปรเจ็กต์ด้วยคำสั่งนี้
    gcloud config set project [PROJECT_ID]
    
    • ตัวอย่าง
      gcloud config set project lab-project-id-example
      
    • หากจำรหัสโปรเจ็กต์ไม่ได้ คุณสามารถแสดงรหัสโปรเจ็กต์ทั้งหมดได้โดยใช้คำสั่งต่อไปนี้
      gcloud projects list
      
      ตั้งค่ารหัสโปรเจ็กต์ในเทอร์มินัล Cloud Shell Editor
  5. คุณควรเห็นข้อความต่อไปนี้
    Updated property [core/project].
    

4. เปิดใช้ API

หากต้องการใช้ Vertex AI และบริการอื่นๆ คุณต้องเปิดใช้ API ที่จำเป็นในโปรเจ็กต์ Google Cloud

  1. เปิดใช้ API ในเทอร์มินัลโดยทำดังนี้
    • Vertex AI API (aiplatform.googleapis.com): ช่วยให้ใช้ Vertex AI ในการปรับแต่งและแสดงโมเดลได้
    • Cloud Storage API (storage.googleapis.com): เปิดใช้การจัดเก็บชุดข้อมูลและอาร์ติแฟกต์ของโมเดล
    gcloud services enable aiplatform.googleapis.com \
        storage.googleapis.com
    

5. ตั้งค่าสภาพแวดล้อมของโปรเจ็กต์

สร้างไดเรกทอรีการทำงาน

  1. ในเทอร์มินัล ให้สร้างไดเรกทอรีสำหรับโปรเจ็กต์แล้วไปที่ไดเรกทอรีนั้น
    mkdir gemini-finetuning
    cd gemini-finetuning
    

ตั้งค่าตัวแปรสภาพแวดล้อม

  1. ในเทอร์มินัล ให้กำหนดตัวแปรสภาพแวดล้อมสำหรับโปรเจ็กต์ เราจะสร้างไฟล์ env.sh เพื่อจัดเก็บตัวแปรเหล่านี้เพื่อให้โหลดซ้ำได้ง่ายหากเซสชันของคุณถูกตัดการเชื่อมต่อ
    cat <<EOF > env.sh
    export PROJECT_ID=\$(gcloud config get-value project)
    export REGION="us-central1"
    export BUCKET_NAME="\${PROJECT_ID}-gemini-tuning"
    EOF
    
    source env.sh
    

สร้างที่เก็บข้อมูล Cloud Storage

  1. ในเทอร์มินัล ให้สร้างที่เก็บข้อมูลเพื่อจัดเก็บชุดข้อมูลและอาร์ติแฟกต์ของโมเดล
    gcloud storage buckets create gs://$BUCKET_NAME --project=$PROJECT_ID --location=$REGION
    

ตั้งค่าสภาพแวดล้อมเสมือน

  1. เราจะใช้ uv เพื่อจัดการสภาพแวดล้อม Python ในเทอร์มินัล ให้เรียกใช้คำสั่งต่อไปนี้
    uv venv .venv
    source .venv/bin/activate
    
  2. ติดตั้งแพ็กเกจ Python ที่จำเป็นในเทอร์มินัล
    uv pip install google-cloud-aiplatform rouge-score matplotlib pandas tqdm
    

6. เตรียมข้อมูลการฝึก

ข้อมูลคุณภาพคือรากฐานของการปรับแต่งที่ประสบความสำเร็จ คุณจะใช้ชุดข้อมูล WikiLingua แปลงเป็นรูปแบบ JSONL เฉพาะที่ Gemini ต้องการ และอัปโหลดไปยังที่เก็บข้อมูล

  1. สร้างไฟล์ชื่อ prepare_data.py ในเทอร์มินัล
    cloudshell edit prepare_data.py
    
  2. วางโค้ดต่อไปนี้ลงใน prepare_data.py
    import json
    import os
    import pandas as pd
    from google.cloud import storage
    import subprocess
    
    # Configuration
    BUCKET_NAME = os.environ["BUCKET_NAME"]
    PROJECT_ID = os.environ["PROJECT_ID"]
    
    def download_data():
        print("Downloading WikiLingua dataset...")
        # Using gsutil to copy from public bucket
        subprocess.run(["gsutil", "cp", "gs://github-repo/generative-ai/gemini/tuning/summarization/wikilingua/*", "."], check=True)
    
    def convert_to_gemini_format(input_file, output_file, max_samples=1000):
        print(f"Converting {input_file} to Gemini format (first {max_samples} samples)...")
        converted_data = []
        with open(input_file, 'r') as f:
            for i, line in enumerate(f):
                if i >= max_samples:
                    break
                obj = json.loads(line)
                messages = obj.get("messages", [])
    
                # Convert messages to Gemini 2.5 format
                # Input: {"messages": [{"role": "user", "content": "..."}, {"role": "model", "content": "..."}]}
                # Output: {"contents": [{"role": "user", "parts": [{"text": "..."}]}, {"role": "model", "parts": [{"text": "..."}]}]}
    
                contents = []
                for msg in messages:
                    role = msg["role"]
                    content = msg["content"]
                    contents.append({
                        "role": role,
                        "parts": [{"text": content}]
                    })
    
                converted_data.append({"contents": contents})
    
        with open(output_file, 'w') as f:
            for item in converted_data:
                f.write(json.dumps(item) + "\n")
    
        print(f"Saved {len(converted_data)} examples to {output_file}")
    
    def upload_to_gcs(local_file, destination_blob_name):
        print(f"Uploading {local_file} to gs://{BUCKET_NAME}/{destination_blob_name}...")
        storage_client = storage.Client(project=PROJECT_ID)
        bucket = storage_client.bucket(BUCKET_NAME)
        blob = bucket.blob(destination_blob_name)
        blob.upload_from_filename(local_file)
        print("Upload complete.")
    
    def main():
        download_data()
    
        # Process Training Data
        convert_to_gemini_format("sft_train_samples.jsonl", "train_gemini.jsonl")
        upload_to_gcs("train_gemini.jsonl", "datasets/train/train_gemini.jsonl")
    
        # Process Validation Data
        convert_to_gemini_format("sft_val_samples.jsonl", "val_gemini.jsonl")
        upload_to_gcs("val_gemini.jsonl", "datasets/val/val_gemini.jsonl")
    
        print("Data preparation complete!")
    
    if __name__ == "__main__":
        main()
    
  3. เรียกใช้สคริปต์การเตรียมข้อมูลในเทอร์มินัล
    python prepare_data.py
    

7. กำหนดประสิทธิภาพพื้นฐาน

คุณต้องมีเกณฑ์เปรียบเทียบก่อนจึงจะปรับแต่งได้ คุณจะวัดประสิทธิภาพของโมเดลพื้นฐาน gemini-2.5-flash ในงานสรุปโดยใช้คะแนน ROUGE

  1. สร้างไฟล์ชื่อ evaluate.py ในเทอร์มินัล
    cloudshell edit evaluate.py
    
  2. วางโค้ดต่อไปนี้ลงใน evaluate.py
    import argparse
    import json
    import os
    import pandas as pd
    from google.cloud import aiplatform
    import vertexai
    from vertexai.generative_models import GenerativeModel, GenerationConfig, HarmCategory, HarmBlockThreshold
    from rouge_score import rouge_scorer
    from tqdm import tqdm
    import matplotlib.pyplot as plt
    import time
    
    # Configuration
    PROJECT_ID = os.environ["PROJECT_ID"]
    REGION = os.environ["REGION"]
    
    aiplatform.init(project=PROJECT_ID, location=REGION)
    
    def evaluate(model_name, test_file, max_samples=50, output_json="results.json"):
        print(f"Evaluating model: {model_name}")
    
        # Load Test Data
        test_df = pd.read_csv(test_file)
        test_df = test_df.head(max_samples)
    
        model = GenerativeModel(model_name)
    
        safety_settings = {
            HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
            HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH,
            HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
            HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_ONLY_HIGH,
        }
    
        generation_config = GenerationConfig(
            temperature=0.1,
            max_output_tokens=1024,
        )
    
        scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True)
        results = []
    
        for index, row in tqdm(test_df.iterrows(), total=len(test_df)):
            input_text = row['input_text']
            reference_summary = row['output_text']
    
            try:
                response = model.generate_content(
                    input_text,
                    generation_config=generation_config,
                    safety_settings=safety_settings
                )
                generated_summary = response.text
    
                scores = scorer.score(reference_summary, generated_summary)
    
                results.append({
                    "generated": generated_summary,
                    "reference": reference_summary,
                    "rouge1": scores['rouge1'].fmeasure,
                    "rouge2": scores['rouge2'].fmeasure,
                    "rougeL": scores['rougeL'].fmeasure
                })
            except Exception as e:
                print(f"Error processing example {index}: {e}")
                # Sleep briefly to avoid quota issues if hitting limits
                time.sleep(1)
    
        # Save results
        with open(output_json, 'w') as f:
            json.dump(results, f, indent=2)
    
        return pd.DataFrame(results)
    
    def plot_results(df, title, filename):
        os.makedirs("plots", exist_ok=True)
    
        metrics = ['rouge1', 'rouge2', 'rougeL']
        fig, axes = plt.subplots(1, 3, figsize=(15, 5))
    
        for i, metric in enumerate(metrics):
            axes[i].hist(df[metric], bins=10, alpha=0.7, color='skyblue', edgecolor='black')
            axes[i].set_title(f'{metric} Distribution')
            axes[i].set_xlabel('Score')
            axes[i].set_ylabel('Count')
    
        plt.suptitle(title)
        plt.tight_layout()
        plt.savefig(f"plots/{filename}")
        print(f"Plot saved to plots/{filename}")
    
    def compare_results(baseline_file, tuned_file):
        with open(baseline_file, 'r') as f:
            baseline_data = pd.DataFrame(json.load(f))
        with open(tuned_file, 'r') as f:
            tuned_data = pd.DataFrame(json.load(f))
    
        print("\n--- Comparison ---")
        metrics = ['rouge1', 'rouge2', 'rougeL']
        for metric in metrics:
            base_mean = baseline_data[metric].mean()
            tuned_mean = tuned_data[metric].mean()
            diff = tuned_mean - base_mean
            print(f"{metric}: Base={base_mean:.4f}, Tuned={tuned_mean:.4f}, Diff={diff:+.4f}")
    
        # Comparative Plot
        os.makedirs("plots", exist_ok=True)
        comparison_df = pd.DataFrame({
            'Metric': metrics,
            'Baseline': [baseline_data[m].mean() for m in metrics],
            'Tuned': [tuned_data[m].mean() for m in metrics]
        })
    
        comparison_df.plot(x='Metric', y=['Baseline', 'Tuned'], kind='bar', figsize=(10, 6))
        plt.title('Baseline vs Tuned Model Performance')
        plt.ylabel('Average Score')
        plt.xticks(rotation=0)
        plt.tight_layout()
        plt.savefig("plots/comparison.png")
        print("Comparison plot saved to plots/comparison.png")
    
    def main():
        parser = argparse.ArgumentParser()
        parser.add_argument("--model", type=str, default="gemini-2.5-flash", help="Model resource name")
        parser.add_argument("--baseline", type=str, help="Path to baseline results json for comparison")
        parser.add_argument("--output", type=str, default="results.json", help="Output file for results")
        args = parser.parse_args()
    
        # Ensure test data exists (it was downloaded in prepare_data step)
        if not os.path.exists("sft_test_samples.csv"):
            # Fallback download if needed
            subprocess.run(["gsutil", "cp", "gs://github-repo/generative-ai/gemini/tuning/summarization/wikilingua/sft_test_samples.csv", "."], check=True)
    
        df = evaluate(args.model, "sft_test_samples.csv", output_json=args.output)
    
        print("\n--- Results Summary ---")
        print(df.describe())
    
        plot_filename = "baseline_dist.png" if not args.baseline else "tuned_dist.png"
        plot_results(df, f"ROUGE Scores - {args.model}", plot_filename)
    
        if args.baseline:
            compare_results(args.baseline, args.output)
    
    if __name__ == "__main__":
        main()
    
  3. เรียกใช้การประเมินพื้นฐานในเทอร์มินัล
    python evaluate.py --model "gemini-2.5-flash" --output "baseline.json"
    
    ซึ่งจะสร้างไฟล์ baseline.json และพล็อตใน plots/baseline_dist.png

8. กำหนดค่าและเปิดตัวการปรับแต่ง

ตอนนี้คุณจะเปิดตัวงานการปรับแต่งที่มีการจัดการใน Vertex AI

  1. สร้างไฟล์ชื่อ tune.py ในเทอร์มินัล
    cloudshell edit tune.py
    
  2. วางโค้ดต่อไปนี้ลงใน tune.py
    import os
    import time
    from google.cloud import aiplatform
    import vertexai
    from vertexai.preview.tuning import sft
    
    # Configuration
    PROJECT_ID = os.environ["PROJECT_ID"]
    REGION = os.environ["REGION"]
    BUCKET_NAME = os.environ["BUCKET_NAME"]
    
    aiplatform.init(project=PROJECT_ID, location=REGION)
    
    def train():
        print("Launching fine-tuning job...")
    
        sft_tuning_job = sft.train(
            source_model="gemini-2.5-flash", # Using specific version for stability
            train_dataset=f"gs://{BUCKET_NAME}/datasets/train/train_gemini.jsonl",
            validation_dataset=f"gs://{BUCKET_NAME}/datasets/val/val_gemini.jsonl",
            epochs=1, # Keep it short for the lab
            adapter_size=4,
            learning_rate_multiplier=1.0,
            tuned_model_display_name="gemini-2.5-flash-wikilingua",
        )
    
        print(f"Job started: {sft_tuning_job.resource_name}")
        print("Waiting for job to complete... (this may take ~45 minutes)")
    
        # Wait for the job to complete
        while not sft_tuning_job.has_ended:
            time.sleep(60)
            sft_tuning_job.refresh()
            print(f"Status: {sft_tuning_job.state.name}")
    
        print("Job completed!")
        print(f"Tuned Model Endpoint: {sft_tuning_job.tuned_model_endpoint_name}")
        return sft_tuning_job.tuned_model_endpoint_name
    
    if __name__ == "__main__":
        train()
    
  3. เรียกใช้สคริปต์การปรับแต่งในเทอร์มินัล
    python tune.py
    
    หมายเหตุ: กระบวนการนี้อาจใช้เวลาประมาณ 45 นาที คุณสามารถตรวจสอบงานได้ใน Vertex AI Console

9. ทำความเข้าใจรหัสการฝึก

ขณะที่งานกำลังทำงาน มาดูtune.pyสคริปต์อย่างละเอียดเพื่อทำความเข้าใจวิธีการทำงานของการปรับแต่งกัน

การปรับแต่งที่มีการควบคุมดูแลที่มีการจัดการ

สคริปต์ใช้วิธี vertexai.tuning.sft.train เพื่อส่งงานการปรับแต่งที่จัดการ ซึ่งช่วยลดความซับซ้อนของการจัดสรรโครงสร้างพื้นฐาน การกระจายการฝึก และการจัดการจุดตรวจสอบ

sft_tuning_job = sft.train(
    source_model="gemini-2.5-flash",
    train_dataset=f"gs://{BUCKET_NAME}/datasets/train/train_gemini.jsonl",
    # ...
)

การกำหนดค่า LoRA

Vertex AI ช่วยลดความซับซ้อนในการกำหนด LoraConfig ด้วยตนเองเหมือนในเฟรมเวิร์กโอเพนซอร์สให้เหลือเพียงพารามิเตอร์หลักๆ 2-3 รายการ ดังนี้

  • adapter_size: พารามิเตอร์นี้ (ตั้งค่าเป็น 4 ในสคริปต์ของเรา) จะควบคุมอันดับของอะแดปเตอร์ LoRA ขนาดที่ใหญ่ขึ้นช่วยให้โมเดลเรียนรู้การดัดแปลงที่ซับซ้อนมากขึ้นได้ แต่จะเพิ่มจำนวนพารามิเตอร์ที่ฝึกได้
  • epochs: เราตั้งค่านี้เป็น 1 สำหรับ Lab นี้เพื่อให้เวลาในการฝึกสั้นลง (~20 นาที) ในสถานการณ์การใช้งานจริง คุณอาจเพิ่มค่านี้เพื่อให้โมเดลเรียนรู้จากข้อมูลได้ลึกซึ้งยิ่งขึ้น แต่ควรระวังการเกิด Overfitting

การเลือกโมเดล

เราจะระบุ source_model="gemini-2.5-flash" อย่างชัดเจน Vertex AI รองรับ Gemini หลายเวอร์ชัน และการปักหมุดเวอร์ชันที่เฉพาะเจาะจงจะช่วยให้มั่นใจว่าไปป์ไลน์จะยังคงเสถียรและทำซ้ำได้

10. เปรียบเทียบรูปแบบ

เมื่องานการปรับแต่งเสร็จสมบูรณ์แล้ว คุณจะเปรียบเทียบประสิทธิภาพของโมเดลใหม่กับค่าพื้นฐานได้

  1. รับปลายทางของโมเดลที่ปรับแต่งแล้ว โดยจะพิมพ์ไว้ที่ท้ายสคริปต์tune.py โดยจะมีลักษณะดังนี้ projects/.../locations/.../endpoints/...
  2. เรียกใช้สคริปต์การประเมินอีกครั้ง โดยคราวนี้ส่งโมเดลที่ปรับแล้วและผลลัพธ์พื้นฐานเพื่อเปรียบเทียบ
    # Replace [YOUR_TUNED_MODEL_ENDPOINT] with the actual endpoint name
    export TUNED_MODEL="projects/[YOUR_PROJECT_ID]/locations/[YOUR_REGION]/endpoints/[YOUR_ENDPOINT_ID]"
    
    python evaluate.py --model "$TUNED_MODEL" --baseline "baseline.json" --output "tuned.json"
    
  3. ดูผลลัพธ์ สคริปต์จะแสดงผลการเปรียบเทียบคะแนน ROUGE และสร้างplots/comparison.pngแผนภูมิที่แสดงการปรับปรุง คุณสามารถดูพล็อตได้โดยเปิดโฟลเดอร์ plots ใน Cloud Shell Editor

11. ล้างข้อมูล

โปรดลบทรัพยากรที่คุณสร้างขึ้นเพื่อไม่ให้มีการเรียกเก็บเงิน

  1. ในเทอร์มินัล ให้ลบที่เก็บข้อมูล Cloud Storage และโมเดลที่ปรับแต่งแล้ว
    gcloud storage rm -r gs://$BUCKET_NAME
    # Note: You can delete the model endpoint from the Vertex AI Console
    

12. ยินดีด้วย

คุณปรับแต่ง Gemini 2.5 Flash บน Vertex AI เรียบร้อยแล้ว

สรุป

ในห้องทดลองนี้ คุณจะได้ทำสิ่งต่อไปนี้

  • จัดเตรียมชุดข้อมูลในรูปแบบ JSONL สำหรับการปรับแต่ง Gemini
  • กำหนดค่าพื้นฐานโดยใช้โมเดล Gemini 2.5 Flash ฐาน
  • เปิดตัวงานการปรับแต่งภายใต้การควบคุมดูแลใน Vertex AI
  • ประเมินและเปรียบเทียบโมเดลที่ปรับแต่งอย่างละเอียดกับเกณฑ์พื้นฐาน

ขั้นตอนถัดไป

แล็บนี้เป็นส่วนหนึ่งของเส้นทางการเรียนรู้AI พร้อมใช้งานจริงด้วย Google Cloud

ดูหลักสูตรทั้งหมดเพื่อเชื่อมช่องว่างจากต้นแบบไปสู่การผลิต

แชร์ความคืบหน้าของคุณด้วยแฮชแท็ก #ProductionReadyAI