การใช้ textembedding-gecko@003 สำหรับการฝังเวกเตอร์

1. บทนำ

อัปเดตล่าสุด: 08-04-2024

การฝังข้อความ

การฝังข้อความหมายถึงกระบวนการเปลี่ยนรูปแบบข้อมูลข้อความเป็นการนำเสนอที่เป็นตัวเลข การนําเสนอตัวเลขเหล่านี้ ซึ่งมักจะเป็นเวกเตอร์ จะจับความหมายเชิงอรรถศาสตร์และความสัมพันธ์ระหว่างคําในข้อความ ลองจินตนาการว่า

ข้อความเป็นภาษาที่ซับซ้อน เต็มไปด้วยความแตกต่างและความคลุมเครือ

การฝังข้อความจะแปลภาษานั้นให้เป็นรูปแบบทางคณิตศาสตร์ที่ง่ายขึ้น ซึ่งคอมพิวเตอร์จะเข้าใจและดัดแปลงได้

ประโยชน์ของการฝังข้อความ

  • ช่วยให้ประมวลผลได้อย่างมีประสิทธิภาพ: คอมพิวเตอร์จะประมวลผลตัวเลขได้เร็วกว่าข้อความดิบมาก ซึ่งเป็นสิ่งที่สําคัญสําหรับงานต่างๆ เช่น เครื่องมือค้นหา ระบบการแนะนํา และการแปลด้วยคอมพิวเตอร์
  • จับความหมายเชิงอรรถศาสตร์: ข้อมูลดังกล่าวไม่ได้จับแค่ความหมายตามตัวอักษรของคํา โดยจะจับบริบทและความสัมพันธ์ระหว่างคําต่างๆ ซึ่งช่วยให้วิเคราะห์ได้ละเอียดยิ่งขึ้น
  • ปรับปรุงประสิทธิภาพแมชชีนเลิร์นนิง: สามารถใช้การฝังข้อความเป็นฟีเจอร์ในโมเดลแมชชีนเลิร์นนิง ซึ่งจะทําให้งานต่างๆ เช่น การวิเคราะห์ความรู้สึก การจัดประเภทข้อความ และการสร้างโมเดลหัวข้อมีประสิทธิภาพดีขึ้น

Use Case ของการฝังข้อความ

การฝังข้อความจะปลดล็อกแอปพลิเคชันต่างๆ ในการประมวลผลภาษาธรรมชาติ (NLP) ด้วยการเปลี่ยนข้อความให้อยู่ในรูปแบบตัวเลข กรณีการใช้งานหลักๆ มีดังนี้

1. เครื่องมือค้นหาและการดึงข้อมูล:

การฝังข้อความช่วยให้เครื่องมือค้นหาเข้าใจความหมายเชิงอรรถศาสตร์ที่อยู่เบื้องหลังคำค้นหาและจับคู่กับเอกสารที่เกี่ยวข้องได้ แม้ว่าจะไม่มีคีย์เวิร์ดที่ตรงกันทุกประการก็ตาม

การเปรียบเทียบการฝังของคำค้นหากับการฝังของเอกสารช่วยให้เครื่องมือค้นหาระบุเอกสารที่ครอบคลุมหัวข้อหรือแนวคิดที่คล้ายกันได้

2. ระบบการแนะนำวิดีโอ:

ระบบแนะนำใช้การฝังข้อความเพื่อวิเคราะห์พฤติกรรมและค่ากําหนดของผู้ใช้ที่แสดงผ่านรีวิว การให้คะแนน หรือประวัติการท่องเว็บ

จากนั้นระบบจะแนะนำรายการที่คล้ายกันโดยเปรียบเทียบการฝังผลิตภัณฑ์ บทความ หรือเนื้อหาอื่นๆ ที่ผู้ใช้โต้ตอบด้วย

3. การตรวจหาการลอกเลียนผลงาน:

การเปรียบเทียบการฝังของข้อความ 2 รายการช่วยระบุการลอกเลียนแบบที่อาจเกิดขึ้นได้โดยค้นหาความคล้ายคลึงที่สำคัญในโครงสร้างเชิงความหมาย

ตัวอย่างเหล่านี้เป็นเพียงตัวอย่างบางส่วน และโอกาสจะเพิ่มขึ้นเรื่อยๆ เมื่อเทคนิคการฝังข้อความพัฒนาขึ้น เมื่อคอมพิวเตอร์เข้าใจภาษาได้ดีขึ้นผ่านข้อมูลเชิงลึก เราคาดว่าจะมีแอปพลิเคชันใหม่ๆ อีกมากมายในอนาคต

textembedding-gecko@003

Textembedding-gecko@003 เป็นโมเดลการฝังข้อความที่ฝึกไว้ล่วงหน้าเวอร์ชันที่เฉพาะเจาะจงซึ่ง Google Cloud Platform (GCP) นำเสนอผ่าน Vertex AI และชุดเครื่องมือและบริการ AI

สิ่งที่คุณจะสร้าง

ในโค้ดแล็บนี้ คุณจะได้สร้างสคริปต์ Python สคริปต์นี้จะทําสิ่งต่อไปนี้

  • ใช้ Vertex API เพื่อเรียก textembedding-gecko@003 และเปลี่ยนข้อความให้อยู่ในรูปแบบข้อความที่ฝัง (เวกเตอร์)
  • สร้างฐานข้อมูลที่จําลองขึ้นจากข้อความและเวกเตอร์ของข้อความ
  • ทำการค้นหาในฐานข้อมูลเวกเตอร์จำลองของเราโดยการเปรียบเทียบเวกเตอร์และรับคำตอบที่เป็นไปได้มากที่สุด

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

  • วิธีใช้การฝังข้อความใน GCP
  • วิธีเรียกใช้ textembedding-gecko@003
  • วิธีเรียกใช้ใน Workbench
  • วิธีใช้ Vertex AI - Workbench เพื่อเรียกใช้สคริปต์

สิ่งที่ต้องมี

  • Chrome เวอร์ชันล่าสุด
  • ความรู้เกี่ยวกับ Python
  • โปรเจ็กต์ Google Cloud
  • สิทธิ์เข้าถึง Vertex AI - Workbench

2. การเริ่มตั้งค่า

สร้างอินสแตนซ์ Vertex AI Workbench

  1. ในคอนโซล Google Cloud ให้เลือกหรือสร้างโปรเจ็กต์ Google Cloud ในหน้าตัวเลือกโปรเจ็กต์
  1. ไปที่เครื่องมือเลือกโปรเจ็กต์
  2. ตรวจสอบว่าเปิดใช้การเรียกเก็บเงินสำหรับโปรเจ็กต์ Google Cloud แล้ว
  3. เปิดใช้ Notebooks API

คุณสามารถสร้างอินสแตนซ์ Vertex AI Workbench โดยใช้คอนโซล Google Cloud, gcloud CLI หรือ Terraform เราจะสร้างโดยใช้คอนโซล Google Cloud เพื่อวัตถุประสงค์ของบทแนะนำนี้ ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีอื่นๆ ได้ที่นี่

  1. ในคอนโซล Google Cloud ให้ไปที่หน้าอินสแตนซ์ซึ่งเข้าถึงได้ในเมนู Vertex AI ในส่วน Notebooks แล้วคลิก Workbench 56c087d619c464dd.png
  2. ไปที่อินสแตนซ์
  3. คลิกสร้างใหม่ 381ff9b895e77641.png
  4. ในกล่องโต้ตอบสร้างอินสแตนซ์ ให้ระบุข้อมูลต่อไปนี้สำหรับอินสแตนซ์ใหม่ในส่วน "รายละเอียด"

ชื่อ: ระบุชื่ออินสแตนซ์ใหม่ ชื่อต้องขึ้นต้นด้วยตัวอักษร ตามด้วยตัวอักษรพิมพ์เล็ก ตัวเลข หรือขีดกลาง (-) ไม่เกิน 62 ตัว และต้องไม่ลงท้ายด้วยขีดกลาง

ภูมิภาคและโซน: เลือกภูมิภาคและโซนสำหรับอินสแตนซ์ใหม่ เลือกภูมิภาคที่อยู่ใกล้กับคุณที่สุดตามภูมิศาสตร์เพื่อให้เครือข่ายทำงานได้ดีที่สุด

ไม่ต้องติดตั้ง GPU

ในส่วน "การทํางานร่วมกัน" ให้ระบุข้อมูลต่อไปนี้

เครือข่าย: ปรับตัวเลือกเครือข่ายเพื่อใช้เครือข่ายในโปรเจ็กต์ปัจจุบันหรือเครือข่าย VPC ที่แชร์จากโปรเจ็กต์โฮสต์ หากมีการกําหนดค่าไว้ หากคุณใช้ VPC ที่แชร์ในโปรเจ็กต์โฮสต์ คุณต้องมอบบทบาทผู้ใช้เครือข่าย Compute (roles/compute.networkUser) ให้กับตัวแทนบริการ Notebooks จากโปรเจ็กต์บริการด้วย

ในช่องเครือข่าย: เลือกเครือข่ายที่ต้องการ คุณเลือกเครือข่าย VPC ได้ ตราบใดที่เครือข่ายเปิดใช้การเข้าถึง Google แบบส่วนตัวหรือเข้าถึงอินเทอร์เน็ตได้

ในช่องเครือข่ายย่อย: เลือกเครือข่ายย่อยที่ต้องการ คุณเลือกค่าเริ่มต้นได้

ในพร็อพเพอร์ตี้อินสแตนซ์ คุณสามารถปล่อยค่าเริ่มต้นไว้ได้ ซึ่งก็คือ e2-standard-4

d47bdc2d7f516c46.png

  1. คลิกสร้าง

Vertex AI Workbench จะสร้างอินสแตนซ์และเริ่มอินสแตนซ์โดยอัตโนมัติ เมื่ออินสแตนซ์พร้อมใช้งาน Vertex AI Workbench จะเปิดใช้งานลิงก์ Open JupyterLab คลิกที่ไอคอน

สร้าง Notebook ของ Python 3

  1. ใน Jupyterlab จาก Launcher ในส่วน Notebook ให้คลิกไอคอนที่มีโลโก้ Python ซึ่งระบุว่า Python3 e16bb118cd28256f.png
  2. ระบบจะสร้างสมุดบันทึก Jupyter ที่มีชื่อ "ไม่มีชื่อ" และนามสกุล ipynb da9bd34cf307156c.png
  3. คุณสามารถเปลี่ยนชื่อได้โดยใช้ส่วนโปรแกรมเรียกดูไฟล์ทางด้านซ้าย หรือจะปล่อยไว้ตามเดิมก็ได้

ตอนนี้เราจะเริ่มใส่โค้ดลงในโน้ตบุ๊กได้

3. การนําเข้าไลบรารีที่จําเป็น

เมื่อสร้างอินสแตนซ์และเปิด JupyterLab แล้ว เราจะต้องติดตั้งไลบรารีที่จำเป็นทั้งหมดสำหรับโค้ดแล็บ

โดยเราจะต้องขอข้อมูลต่อไปนี้

  1. numpy
  2. แพนด้า
  3. TextEmbeddingInput, TextEmbeddingModel จาก vertexai.language_models

คัดลอกและวางโค้ดด้านล่างในเซลล์

from vertexai.language_models import TextEmbeddingInput, TextEmbeddingModel

import numpy as np
import pandas as pd

URL จะมีหน้าตาดังนี้:

6852d323eedcac93.png

4. สร้างฐานข้อมูลเวกเตอร์จำลอง

เราจะสร้างฐานข้อมูลที่ประกอบด้วยข้อความและเวกเตอร์ที่เกี่ยวข้องซึ่งแปลโดยใช้โมเดลการฝังข้อความ gecko@003 เพื่อทดสอบโค้ด

วัตถุประสงค์คือเพื่อให้ผู้ใช้ค้นหาข้อความ แปลเป็นเวกเตอร์ ค้นหาในฐานข้อมูล แล้วแสดงผลลัพธ์ที่ใกล้เคียงที่สุด

ฐานข้อมูลเวกเตอร์จะมีระเบียน 3 รายการ โดยเราจะสร้างดังนี้

คัดลอกและวางโค้ดด้านล่างในเซลล์ใหม่

DOCUMENT1 = {
    "title": "Operating the Climate Control System",
    "content": "Your Googlecar has a climate control system that allows you to adjust the temperature and airflow in the car. To operate the climate control system, use the buttons and knobs located on the center console.  Temperature: The temperature knob controls the temperature inside the car. Turn the knob clockwise to increase the temperature or counterclockwise to decrease the temperature. Airflow: The airflow knob controls the amount of airflow inside the car. Turn the knob clockwise to increase the airflow or counterclockwise to decrease the airflow. Fan speed: The fan speed knob controls the speed of the fan. Turn the knob clockwise to increase the fan speed or counterclockwise to decrease the fan speed. Mode: The mode button allows you to select the desired mode. The available modes are: Auto: The car will automatically adjust the temperature and airflow to maintain a comfortable level. Cool: The car will blow cool air into the car. Heat: The car will blow warm air into the car. Defrost: The car will blow warm air onto the windshield to defrost it."}

DOCUMENT2 = {
    "title": "Touchscreen",
    "content": "Your Googlecar has a large touchscreen display that provides access to a variety of features, including navigation, entertainment, and climate control. To use the touchscreen display, simply touch the desired icon.  For example, you can touch the \"Navigation\" icon to get directions to your destination or touch the \"Music\" icon to play your favorite songs."}

DOCUMENT3 = {
    "title": "Shifting Gears",
    "content": "Your Googlecar has an automatic transmission. To shift gears, simply move the shift lever to the desired position.  Park: This position is used when you are parked. The wheels are locked and the car cannot move. Reverse: This position is used to back up. Neutral: This position is used when you are stopped at a light or in traffic. The car is not in gear and will not move unless you press the gas pedal. Drive: This position is used to drive forward. Low: This position is used for driving in snow or other slippery conditions."}

documents = [DOCUMENT1, DOCUMENT2, DOCUMENT3]

df_initial_db = pd.DataFrame(documents)
df_initial_db.columns = ['Title', 'Text']
df_initial_db

ซึ่งจะมีลักษณะดังนี้

26baa3b876c0605d.png

มาวิเคราะห์โค้ดกัน

ในตัวแปร DOCUMENT1, DOCUMENT2 และ DOCUMENT3 เราจัดเก็บพจนานุกรมที่จะจําลองเอกสารที่มีชื่อและเนื้อหา "เอกสาร" เหล่านี้อ้างอิงถึงคู่มือจำลองของรถยนต์ที่ผลิตโดย Google

ในบรรทัดถัดไป เราจะสร้างรายการจากเอกสาร 3 รายการ (พจนานุกรม) ดังกล่าว

documents = [DOCUMENT1, DOCUMENT2, DOCUMENT3]

สุดท้าย เราจะใช้ Pandas เพื่อสร้าง DataFrame จากรายการดังกล่าว ซึ่งจะเรียกว่า df_initial_db

df_initial_db = pd.DataFrame(documents)
df_initial_db.columns = ['Title', 'Text']
df_initial_db

5. สร้างการฝังข้อความ

ตอนนี้เราจะดูการฝังข้อความโดยใช้โมเดล gecko@003 สําหรับแต่ละระเบียนในฐานข้อมูลเอกสารจำลอง

คัดลอกและวางโค้ดด้านล่างลงในเซลล์ใหม่

def embed_fn(df_input):
    list_embedded_values = []
    for index, row in df_input.iterrows():        
        model = TextEmbeddingModel.from_pretrained("textembedding-gecko@003")
        embeddings = model.get_embeddings([(row['Text'])])        
        list_embedded_values.append(embeddings[0].values)
    df_input['Embedded text'] = list_embedded_values
    return df_input        
                                           
df_embedded_values_db = embed_fn(df_initial_db)
df_embedded_values_db      

ซึ่งจะมีลักษณะดังนี้

4c4af091c7a82861.png

มาวิเคราะห์โค้ดกัน

เรากําหนดฟังก์ชันชื่อ embed_fn ซึ่งจะรับข้อมูลเป็น DataFrame ของ Pandas ที่มีข้อความสําหรับทำการฝัง จากนั้นฟังก์ชันจะแสดงผลข้อความที่เข้ารหัสเป็นเวกเตอร์

def embed_fn(df_input):
    list_embedded_values = []
    for index, row in df_input.iterrows():        
        model = TextEmbeddingModel.from_pretrained("textembedding-gecko@003")
        embeddings = model.get_embeddings([(row['Text'])])        
        list_embedded_values.append(embeddings[0].values)
    df_input['Embedded text'] = list_embedded_values
    return df_input             

ในลิสต์ชื่อ list_embedded_values เป็นที่ที่เราจัดเก็บและเพิ่มข้อความที่เข้ารหัสของทุกแถวต่อท้าย

เมื่อใช้เมธอด iterrows จาก pandas เราจะวนซ้ำทุกแถวใน DataFrame เพื่อรับค่าจากคอลัมน์ข้อความ (ซึ่งมีข้อมูลจากฐานข้อมูลที่จําลองขึ้นด้วยตนเอง)

หากต้องการส่งข้อความปกติและแสดงผลเวกเตอร์โดยใช้โมเดล gecko@003 เราจะเริ่มต้นตัวแปรโมเดลซึ่งเป็นที่ที่เราตั้งค่าโมเดลที่จะใช้โดยการเรียกใช้ฟังก์ชัน TextEmbeddingModel.from_pretrained

model = TextEmbeddingModel.from_pretrained("textembedding-gecko@003")
embeddings = model.get_embeddings([(row['Text'])])                     

จากนั้นในตัวแปรเชิงลึก เราจะบันทึกเวกเตอร์ของข้อความที่เราส่งผ่านฟังก์ชัน model.get_embeddings

ที่ส่วนท้ายของฟังก์ชัน เราจะสร้างคอลัมน์ใหม่ใน DataFrame ชื่อ "ข้อความที่ฝัง" ซึ่งจะมีรายการเวกเตอร์ที่สร้างตามโมเดล gecko@003

df_input['Embedded text'] = list_embedded_values
return df_input             

สุดท้าย ในตัวแปร df_embedded_values_db เราจะบันทึก DataFrame ที่มีข้อมูลเดิมจากฐานข้อมูลที่จําลองไว้ รวมถึงคอลัมน์ใหม่ที่มีรายการเวกเตอร์สําหรับแต่ละแถว

df_embedded_values_db = embed_fn(df_initial_db)
df_embedded_values_db      

6. ถามคําถามไปยังฐานข้อมูลเวกเตอร์

ตอนนี้ฐานข้อมูลของเรามีข้อความและเวกเตอร์ของข้อความแล้ว เราจึงสามารถถามคำถามและค้นหาคำตอบจากฐานข้อมูลได้

โดยให้คัดลอกและวางโค้ดด้านล่างลงในเซลล์ใหม่

question='How do you shift gears in the Google car?'
model = TextEmbeddingModel.from_pretrained("textembedding-gecko@003")
embeddings = model.get_embeddings([(question)])        
text_to_search=embeddings[0].values
len(text_to_search)

ผลลัพธ์ที่ได้จะมีลักษณะดังนี้

6b7cf9b08e3b4573.png

มาวิเคราะห์โค้ดกัน

เช่นเดียวกับฟังก์ชันจากขั้นตอนก่อนหน้า เราจะเริ่มต้นตัวแปรคำถามด้วยสิ่งที่เราตั้งใจจะถามฐานข้อมูลก่อน

question='How do you shift gears in the Google car?'

จากนั้นในตัวแปรโมเดล เราจะตั้งค่าโมเดลที่ต้องการใช้ผ่านฟังก์ชัน TextEmbeddingModel.from_pretrained ซึ่งในกรณีนี้คือโมเดล gecko@003

model = TextEmbeddingModel.from_pretrained("textembedding-gecko@003")

ในตัวแปร embeddings เราจะเรียกใช้ฟังก์ชัน model.get_embeddings และส่งข้อความให้แปลงเป็นเวกเตอร์ ซึ่งในกรณีนี้เราจะส่งคำถามที่จะถาม

embeddings = model.get_embeddings([(question)])        

สุดท้ายตัวแปร text_to_search จะเก็บรายการเวกเตอร์ที่แปลมาจากคําถาม

เราพิมพ์ความยาวของเวกเตอร์ไว้เพื่อเป็นข้อมูลอ้างอิงเท่านั้น

text_to_search=embeddings[0].values
len(text_to_search)

7. การเปรียบเทียบเวกเตอร์

ตอนนี้เรามีรายการเวกเตอร์ในฐานข้อมูลที่จําลองและคำถามที่เปลี่ยนรูปแบบเป็นเวกเตอร์แล้ว กล่าวคือ ตอนนี้เราสามารถเปรียบเทียบเวกเตอร์ของคำถามกับเวกเตอร์ทั้งหมดในฐานข้อมูลเพื่อหาเวกเตอร์ที่ใกล้เคียงกับคำตอบของคำถามมากที่สุด

โดยเราจะวัดระยะทางระหว่างเวกเตอร์ของคำถามกับเวกเตอร์แต่ละรายการของฐานข้อมูล การวัดระยะทางระหว่างเวกเตอร์มีหลายเทคนิค แต่สำหรับโค้ดแล็บนี้ เราจะใช้ระยะทางแบบยูคลิดหรือ L2

73ea8635c4570bea.png

ใน Python เราใช้ประโยชน์จากฟังก์ชัน numpy เพื่อทำสิ่งนี้ได้

คัดลอกและวางโค้ดด้านล่างลงในเซลล์ใหม่

list_embedded_text_from_db = df_embedded_values_db['Embedded text']
shortest_distance=1
for position, embedded_value in enumerate(list_embedded_text_from_db):
    distance=np.linalg.norm((np.array(embedded_value) - np.array(text_to_search)), ord = 2)
    print(distance)
    if distance<shortest_distance:
        shortest_distance=distance
        shortest_position=position
        
print(f'The shortest distance is {shortest_distance} and the position of that value is {shortest_position}')

ผลลัพธ์ที่ได้ควรมีลักษณะดังนี้

b70563b50ea86668.png

มาวิเคราะห์โค้ดกัน

เราเริ่มต้นด้วยการเปลี่ยนคอลัมน์ที่มีข้อความที่ฝังหรือเวกเตอร์ของฐานข้อมูลเป็นรายการและจัดเก็บไว้ใน list_embedded_text_from_db

นอกจากนี้ เรายังเริ่มต้นค่าตัวแปร shortest_distance เป็น 1 เพื่ออัปเดตค่านี้ต่อไปจนกว่าจะพบระยะทางที่สั้นที่สุดจริง

list_embedded_text_from_db = df_embedded_values_db['Embedded text']
shortest_distance=1

จากนั้นใช้ลูป for เพื่อวนซ้ำและรับระยะห่างระหว่างเวกเตอร์จากคำถามกับเวกเตอร์แต่ละรายการในฐานข้อมูล

เราคำนวณระยะทางโดยใช้ฟังก์ชัน numpy linalg.norm

หากระยะทางที่คำนวณได้น้อยกว่าระยะทางในตัวแปร shortest_distance ระบบจะตั้งค่าระยะทางที่คำนวณไว้เป็นตัวแปรนี้

จากนั้นเราจะบันทึกระยะทางที่สั้นที่สุด รวมถึงตำแหน่งในรายการที่พบ ในตัวแปร shortest_distance และ shortest_position

for position, embedded_value in enumerate(list_embedded_text_from_db):
    distance=np.linalg.norm((np.array(embedded_value) - np.array(text_to_search)), ord = 2)
    print(distance)
    if distance<shortest_distance:
        shortest_distance=distance
        shortest_position=position

8. ผลลัพธ์

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

คัดลอกและวางโค้ดด้านล่างในเซลล์ใหม่

print("Your question was:\n "+question+ " \nAnd our answer is:\n "+
      df_embedded_values_db.at[shortest_position, 'Title']+": "+
      df_embedded_values_db.at[shortest_position, 'Text'])

หลังจากเรียกใช้แล้ว คุณจะเห็นข้อมูลประมาณนี้

7a0e429171a19afe.png

9. ขอแสดงความยินดี

ยินดีด้วย คุณสร้างแอปพลิเคชันแรกโดยใช้โมเดล textembedding-gecko@003 ใน Use Case จริงเรียบร้อยแล้ว

คุณได้เรียนรู้พื้นฐานเกี่ยวกับการฝังข้อความและวิธีใช้โมเดล gecko003 ใน GCP Workbench

ตอนนี้คุณทราบขั้นตอนสําคัญที่จําเป็นต่อการใช้ความรู้กับกรณีการใช้งานเพิ่มเติมแล้ว

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

ลองดู Codelab เหล่านี้...

เอกสารอ้างอิง