|
|
เรียกใช้ใน Google Colab
|
|
|
ดูซอร์สโค้ดใน GitHub
|
คู่มือนี้จะแนะนำวิธีปรับแต่ง Gemma อย่างละเอียดในชุดข้อมูลข้อความเป็น SQL ที่กำหนดเองโดยใช้ Hugging Face Transformers และ TRL คุณจะได้เรียนรู้สิ่งต่อไปนี้
- Quantized Low-Rank Adaptation (QLoRA) คืออะไร
- ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์
- สร้างและเตรียมชุดข้อมูลการปรับแต่งอย่างละเอียด
- ปรับแต่ง Gemma อย่างละเอียดโดยใช้ TRL และ SFTTrainer
- ทดสอบการอนุมานของโมเดลและสร้างการค้นหา SQL
Quantized Low-Rank Adaptation (QLoRA) คืออะไร
คู่มือนี้แสดงให้เห็นถึงการใช้ Quantized Low-Rank Adaptation (QLoRA) ซึ่งกลายเป็นวิธีที่ได้รับความนิยมในการปรับแต่ง LLM อย่างละเอียดอย่างมีประสิทธิภาพ เนื่องจากช่วยลดข้อกำหนดด้านทรัพยากรการคำนวณในขณะที่ยังคงประสิทธิภาพสูงไว้ได้ ใน QLoRA โมเดลที่ฝึกไว้ล่วงหน้าจะถูกควอนไทซ์เป็น 4 บิตและน้ำหนักจะถูกตรึงไว้ จากนั้นจะมีการแนบเลเยอร์อะแดปเตอร์ที่ฝึกได้ (LoRA) และมีการฝึกเฉพาะเลเยอร์อะแดปเตอร์เท่านั้น หลังจากนั้น คุณสามารถผสานน้ำหนักอะแดปเตอร์กับโมเดลฐานหรือเก็บไว้เป็นอะแดปเตอร์แยกต่างหากก็ได้
ตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์
ขั้นตอนแรกคือการติดตั้งไลบรารี Hugging Face ซึ่งรวมถึง TRL และชุดข้อมูลเพื่อปรับแต่งโมเดลแบบเปิดอย่างละเอียด ซึ่งรวมถึงเทคนิค RLHF และการจัดแนวต่างๆ
# Install Pytorch & other libraries
%pip install torch tensorboard
# Install Transformers
%pip install transformers
# Install Hugging Face libraries
%pip install datasets accelerate evaluate bitsandbytes trl peft protobuf sentencepiece
# COMMENT IN: if you are running on a GPU that supports BF16 data type and flash attn, such as NVIDIA L4 or NVIDIA A100
#%pip install flash-attn
หมายเหตุ: หากคุณใช้ GPU ที่มีสถาปัตยกรรม Ampere (เช่น NVIDIA L4) หรือใหม่กว่า คุณสามารถใช้ Flash Attention ได้ Flash Attention เป็นวิธีที่ช่วยเร่งการคำนวณขึ้นอย่างมากและลดการใช้งานหน่วยความจำจากกำลังสองเป็นเชิงเส้นตามความยาวลำดับ ซึ่งจะช่วยเร่งการฝึกได้สูงสุด 3 เท่า ดูข้อมูลเพิ่มเติมได้ที่ FlashAttention.
คุณต้องมีโทเค็น Hugging Face ที่ถูกต้องจึงจะเผยแพร่โมเดลได้ หากคุณเรียกใช้ภายใน Google Colab คุณสามารถใช้โทเค็น Hugging Face ได้อย่างปลอดภัยโดยใช้ความลับของ Colab หรือคุณจะตั้งค่าโทเค็นโดยตรงในเมธอด login ก็ได้ ตรวจสอบว่าโทเค็นมีสิทธิ์เขียนด้วย เนื่องจากคุณจะพุชโมเดลไปยังฮับระหว่างการฝึก
# Login into Hugging Face Hub
from huggingface_hub import login
login()
สร้างและเตรียมชุดข้อมูลการปรับแต่งอย่างละเอียด
เมื่อปรับแต่ง LLM อย่างละเอียด สิ่งสำคัญคือคุณต้องทราบกรณีการใช้งานและงานที่ต้องการแก้ไข ซึ่งจะช่วยให้คุณสร้างชุดข้อมูลเพื่อปรับแต่งโมเดลอย่างละเอียดได้ หากยังไม่ได้กำหนดกรณีการใช้งาน คุณอาจต้องกลับไปเริ่มต้นใหม่
ตัวอย่างเช่น คู่มือนี้จะเน้นกรณีการใช้งานต่อไปนี้
- ปรับแต่งโมเดลภาษาธรรมชาติเป็น SQL อย่างละเอียดเพื่อการผสานรวมที่ราบรื่นเข้ากับเครื่องมือวิเคราะห์ข้อมูล วัตถุประสงค์คือการลดเวลาและความเชี่ยวชาญที่จำเป็นสำหรับการสร้างการค้นหา SQL ลงอย่างมาก ซึ่งจะช่วยให้แม้แต่ผู้ใช้ที่ไม่ใช่ผู้เชี่ยวชาญด้านเทคนิคก็สามารถดึงข้อมูลเชิงลึกที่มีความหมายจากข้อมูลได้
ข้อความเป็น SQL อาจเป็นกรณีการใช้งานที่ดีสำหรับการปรับแต่ง LLM อย่างละเอียด เนื่องจากเป็นงานที่ซับซ้อนซึ่งต้องใช้ความรู้ (ภายใน) จำนวนมากเกี่ยวกับข้อมูลและภาษา SQL
เมื่อพิจารณาแล้วว่าการปรับแต่งอย่างละเอียดเป็นโซลูชันที่เหมาะสม คุณจะต้องมีชุดข้อมูลเพื่อปรับแต่งอย่างละเอียด ชุดข้อมูลควรเป็นการสาธิตงานที่คุณต้องการแก้ไขที่หลากหลาย คุณสร้างชุดข้อมูลดังกล่าวได้หลายวิธี ซึ่งรวมถึง
- การใช้ชุดข้อมูลโอเพนซอร์สที่มีอยู่ เช่น Spider
- การใช้ชุดข้อมูลสังเคราะห์ที่สร้างโดย LLM เช่น Alpaca
- การใช้ชุดข้อมูลที่สร้างโดยมนุษย์ เช่น Dolly
- การใช้วิธีการต่างๆ ร่วมกัน เช่น Orca
แต่ละวิธีมีข้อดีและข้อเสียของตัวเอง และขึ้นอยู่กับงบประมาณ เวลา และข้อกำหนดด้านคุณภาพ ตัวอย่างเช่น การใช้ชุดข้อมูลที่มีอยู่เป็นวิธีที่ง่ายที่สุด แต่อาจไม่เหมาะกับกรณีการใช้งานเฉพาะของคุณ ในขณะที่การใช้ผู้เชี่ยวชาญเฉพาะด้านอาจให้ผลลัพธ์ที่แม่นยำที่สุด แต่ก็อาจใช้เวลานานและมีค่าใช้จ่ายสูง นอกจากนี้ คุณยังสามารถใช้วิธีการต่างๆ ร่วมกันเพื่อสร้างชุดข้อมูลคำแนะนำได้ ดังที่แสดงใน Orca: Progressive Learning from Complex Explanation Traces of GPT-4
คู่มือนี้ใช้ชุดข้อมูลที่มีอยู่แล้ว (philschmid/gretel-synthetic-text-to-sql) ซึ่งเป็นชุดข้อมูลข้อความเป็น SQL สังเคราะห์คุณภาพสูง ซึ่งรวมถึงคำแนะนำภาษาธรรมชาติ คำจำกัดความของสคีมา การให้เหตุผล และการค้นหา SQL ที่เกี่ยวข้อง
Hugging Face TRL รองรับการสร้างเทมเพลตชุดข้อมูลการสนทนาในรูปแบบต่างๆ โดยอัตโนมัติ ซึ่งหมายความว่าคุณเพียงแค่ต้องแปลงชุดข้อมูลเป็นออบเจ็กต์ JSON ที่เหมาะสม และ trl จะจัดการการสร้างเทมเพลตและจัดรูปแบบให้ถูกต้อง
{"messages": [{"role": "system", "content": "You are..."}, {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}
{"messages": [{"role": "system", "content": "You are..."}, {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}
{"messages": [{"role": "system", "content": "You are..."}, {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}
philschmid/gretel-synthetic-text-to-sql มีตัวอย่างมากกว่า 100,000 รายการ เราจึงลดขนาดตัวอย่างลงเหลือเพียง 10,000 รายการเพื่อให้คู่มือมีขนาดเล็กลง
ตอนนี้คุณสามารถใช้ไลบรารี Hugging Face Datasets เพื่อโหลดชุดข้อมูลและสร้างเทมเพลตพรอมต์เพื่อรวมคำแนะนำภาษาธรรมชาติ คำจำกัดความของสคีมา และเพิ่มข้อความระบบสำหรับผู้ช่วยได้แล้ว
from datasets import load_dataset
# System message for the assistant
system_message = """You are a text to SQL query translator. Users will ask you questions in English and you will generate a SQL query based on the provided SCHEMA."""
# User prompt that combines the user query and the schema
user_prompt = """Given the <USER_QUERY> and the <SCHEMA>, generate the corresponding SQL command to retrieve the desired data, considering the query's syntax, semantics, and schema constraints.
<SCHEMA>
{context}
</SCHEMA>
<USER_QUERY>
{question}
</USER_QUERY>
"""
def create_conversation(sample):
return {
"messages": [
{"role": "system", "content": system_message},
{"role": "user", "content": user_prompt.format(question=sample["sql_prompt"], context=sample["sql_context"])},
{"role": "assistant", "content": sample["sql"]}
]
}
# Load dataset from the hub
dataset = load_dataset("philschmid/gretel-synthetic-text-to-sql", split="train")
dataset = dataset.shuffle().select(range(12500))
# Convert dataset to OAI messages
dataset = dataset.map(create_conversation, remove_columns=dataset.features,batched=False)
# split dataset into 80% training samples and 20% test samples
dataset = dataset.train_test_split(test_size=0.2)
# Print formatted user prompt
for item in dataset["train"][0]["messages"]:
print(item)
README.md: 0%| | 0.00/737 [00:00<?, ?B/s]
synthetic_text_to_sql_train.snappy.parqu(…): 0%| | 0.00/32.4M [00:00<?, ?B/s]
synthetic_text_to_sql_test.snappy.parque(…): 0%| | 0.00/1.90M [00:00<?, ?B/s]
Generating train split: 0%| | 0/100000 [00:00<?, ? examples/s]
Generating test split: 0%| | 0/5851 [00:00<?, ? examples/s]
Map: 0%| | 0/12500 [00:00<?, ? examples/s]
{'content': 'You are a text to SQL query translator. Users will ask you questions in English and you will generate a SQL query based on the provided SCHEMA.', 'role': 'system'}
{'content': "Given the <USER_QUERY> and the <SCHEMA>, generate the corresponding SQL command to retrieve the desired data, considering the query's syntax, semantics, and schema constraints.\n\n<SCHEMA>\nCREATE TABLE Menu (id INT PRIMARY KEY, name VARCHAR(255), category VARCHAR(255), price DECIMAL(5,2));\n</SCHEMA>\n\n<USER_QUERY>\nCalculate the average price of all menu items in the Vegan category\n</USER_QUERY>\n", 'role': 'user'}
{'content': "SELECT AVG(price) FROM Menu WHERE category = 'Vegan';", 'role': 'assistant'}
ปรับแต่ง Gemma อย่างละเอียดโดยใช้ TRL และ SFTTrainer
ตอนนี้คุณพร้อมที่จะปรับแต่งโมเดลอย่างละเอียดแล้ว Hugging Face TRL SFTTrainer ช่วยให้การปรับแต่ง LLM แบบเปิดอย่างละเอียดภายใต้การดูแลเป็นเรื่องง่าย SFTTrainer เป็นคลาสย่อยของ Trainer จากไลบรารี transformers และรองรับฟีเจอร์ทั้งหมดเหมือนกัน ซึ่งรวมถึงการบันทึก การประเมิน และการตรวจสอบ แต่เพิ่มฟีเจอร์ที่ช่วยให้การใช้งานสะดวกยิ่งขึ้น ซึ่งรวมถึง
- การจัดรูปแบบชุดข้อมูล ซึ่งรวมถึงรูปแบบการสนทนาและคำแนะนำ
- การฝึกเฉพาะการเติมข้อความให้สมบูรณ์ โดยไม่สนใจพรอมต์
- การแพ็กชุดข้อมูลเพื่อการฝึกที่มีประสิทธิภาพมากขึ้น
- การรองรับการปรับแต่งอย่างละเอียดที่มีประสิทธิภาพด้านพารามิเตอร์ (PEFT) ซึ่งรวมถึง QLoRA
- การเตรียมโมเดลและโทเค็นไนเซอร์สำหรับการปรับแต่งอย่างละเอียดแบบสนทนา (เช่น การเพิ่มโทเค็นพิเศษ)
โค้ดต่อไปนี้จะโหลดโมเดลและโทเค็นไนเซอร์ Gemma จาก Hugging Face และเริ่มต้นการกำหนดค่าการควอนไทซ์
import torch
from transformers import AutoTokenizer, AutoModelForImageTextToText, BitsAndBytesConfig
# Hugging Face model id
model_id = "google/gemma-4-E2B" # @param ["google/gemma-4-E2B","google/gemma-4-E4B"] {"allow-input":true}
# Check if GPU benefits from bfloat16
if torch.cuda.get_device_capability()[0] >= 8:
torch_dtype = torch.bfloat16
else:
torch_dtype = torch.float16
# Define model init arguments
model_kwargs = dict(
dtype=torch_dtype,
device_map="auto", # Let torch decide how to load the model
)
# BitsAndBytesConfig: Enables 4-bit quantization to reduce model size/memory usage
model_kwargs["quantization_config"] = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type='nf4',
bnb_4bit_compute_dtype=model_kwargs['dtype'],
bnb_4bit_quant_storage=model_kwargs['dtype'],
)
# Load model and tokenizer
model = AutoModelForImageTextToText.from_pretrained(model_id, **model_kwargs)
tokenizer = AutoTokenizer.from_pretrained("google/gemma-4-E2B-it") # Load the Instruction Tokenizer to use the official Gemma template
config.json: 0.00B [00:00, ?B/s] model.safetensors: 0%| | 0.00/10.2G [00:00<?, ?B/s] Loading weights: 0%| | 0/2011 [00:00<?, ?it/s] generation_config.json: 0%| | 0.00/181 [00:00<?, ?B/s] config.json: 0.00B [00:00, ?B/s] tokenizer_config.json: 0.00B [00:00, ?B/s] tokenizer.json: 0%| | 0.00/32.2M [00:00<?, ?B/s] chat_template.jinja: 0.00B [00:00, ?B/s]
SFTTrainer รองรับการผสานรวมกับ peft ในตัว ซึ่งช่วยให้การปรับแต่ง LLM อย่างมีประสิทธิภาพโดยใช้ QLoRA เป็นเรื่องง่าย คุณเพียงแค่ต้องสร้าง LoraConfig แล้วส่งให้เทรนเนอร์
from peft import LoraConfig
peft_config = LoraConfig(
lora_alpha=16,
lora_dropout=0.05,
r=16,
bias="none",
target_modules="all-linear",
task_type="CAUSAL_LM",
modules_to_save=["lm_head", "embed_tokens"], # make sure to save the lm_head and embed_tokens as you train the special tokens
ensure_weight_tying=True,
)
ก่อนที่จะเริ่มการฝึก คุณต้องกำหนดไฮเปอร์พารามิเตอร์ที่ต้องการใช้ในอินสแตนซ์ SFTConfig
import torch
from trl import SFTConfig
args = SFTConfig(
output_dir="gemma-text-to-sql", # directory to save and repository id
max_length=512, # max length for model and packing of the dataset
num_train_epochs=3, # number of training epochs
per_device_train_batch_size=1, # batch size per device during training
optim="adamw_torch_fused", # use fused adamw optimizer
logging_steps=10, # log every 10 steps
save_strategy="epoch", # save checkpoint every epoch
eval_strategy="epoch", # evaluate checkpoint every epoch
learning_rate=5e-5, # learning rate
fp16=True if model.dtype == torch.float16 else False, # use float16 precision
bf16=True if model.dtype == torch.bfloat16 else False, # use bfloat16 precision
max_grad_norm=0.3, # max gradient norm based on QLoRA paper
lr_scheduler_type="constant", # use constant learning rate scheduler
push_to_hub=True, # push model to hub
report_to="tensorboard", # report metrics to tensorboard
dataset_kwargs={
"add_special_tokens": False, # Template with special tokens
"append_concat_token": True, # Add EOS token as separator token between examples
}
)
ตอนนี้คุณมีทุกองค์ประกอบที่ใช้สร้างสรรค์ที่จำเป็นในการสร้าง SFTTrainer เพื่อเริ่มการฝึกโมเดลแล้ว
from trl import SFTTrainer
# Create Trainer object
trainer = SFTTrainer(
model=model,
args=args,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
peft_config=peft_config,
processing_class=tokenizer,
)
Tokenizing train dataset: 0%| | 0/10000 [00:00<?, ? examples/s] Tokenizing eval dataset: 0%| | 0/2500 [00:00<?, ? examples/s]
เริ่มการฝึกโดยเรียกใช้เมธอด train()
# Start training, the model will be automatically saved to the Hub and the output directory
trainer.train()
# Save the final model again to the Hugging Face Hub
trainer.save_model()
The tokenizer has new PAD/BOS/EOS tokens that differ from the model config and generation config. The model config and generation config were aligned accordingly, being updated with the tokenizer's values. Updated tokens: {'eos_token_id': 1, 'bos_token_id': 2, 'pad_token_id': 0}.
ตรวจสอบว่าได้เคลียร์หน่วยความจำแล้วก่อนที่จะทดสอบโมเดล
# free the memory again
del model
del trainer
torch.cuda.empty_cache()
เมื่อใช้ QLoRA คุณจะฝึกเฉพาะอะแดปเตอร์เท่านั้น ไม่ใช่โมเดลทั้งหมด ซึ่งหมายความว่าเมื่อบันทึกโมเดลระหว่างการฝึก คุณจะบันทึกเฉพาะน้ำหนักอะแดปเตอร์เท่านั้น ไม่ใช่โมเดลทั้งหมด หากต้องการบันทึกโมเดลทั้งหมด ซึ่งจะช่วยให้ใช้งานกับสแต็กการแสดงผล เช่น vLLM หรือ TGI ได้ง่ายขึ้น คุณสามารถผสานน้ำหนักอะแดปเตอร์เข้ากับน้ำหนักโมเดลได้โดยใช้เมธอด merge_and_unload แล้วบันทึกโมเดลด้วยเมธอด save_pretrained ซึ่งจะบันทึกโมเดลเริ่มต้นที่ใช้สำหรับการอนุมานได้
from peft import PeftModel
# Load Model base model
model = AutoModelForImageTextToText.from_pretrained(model_id, low_cpu_mem_usage=True)
# Merge LoRA and base model and save
peft_model = PeftModel.from_pretrained(model, args.output_dir)
merged_model = peft_model.merge_and_unload()
merged_model.save_pretrained("merged_model", safe_serialization=True, max_shard_size="2GB")
processor = AutoTokenizer.from_pretrained(args.output_dir)
processor.save_pretrained("merged_model")
Loading weights: 0%| | 0/2011 [00:00<?, ?it/s]
Writing model shards: 0%| | 0/5 [00:00<?, ?it/s]
('merged_model/tokenizer_config.json',
'merged_model/chat_template.jinja',
'merged_model/tokenizer.json')
ทดสอบการอนุมานของโมเดลและสร้างการค้นหา SQL
หลังจากฝึกเสร็จแล้ว คุณจะต้องประเมินและทดสอบโมเดล คุณสามารถโหลดตัวอย่างต่างๆ จากชุดข้อมูลทดสอบและประเมินโมเดลในตัวอย่างเหล่านั้นได้
import torch
from transformers import pipeline
model_id = "merged_model"
# Load Model with PEFT adapter
model = AutoModelForImageTextToText.from_pretrained(
model_id,
device_map="auto",
dtype="auto",
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
Loading weights: 0%| | 0/2012 [00:00<?, ?it/s] The tied weights mapping and config for this model specifies to tie model.language_model.embed_tokens.weight to lm_head.weight, but both are present in the checkpoints with different values, so we will NOT tie them. You should update the config with `tie_word_embeddings=False` to silence this warning.
มาโหลดตัวอย่างแบบสุ่มจากชุดข้อมูลทดสอบและสร้างคำสั่ง SQL กัน
from random import randint
import re
from transformers import pipeline, GenerationConfig
config = GenerationConfig.from_pretrained(model_id)
config.max_new_tokens = 256
# Load the model and tokenizer into the pipeline
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer)
# Load a random sample from the test dataset
rand_idx = randint(0, len(dataset["test"]))
test_sample = dataset["test"][rand_idx]
# Convert as test example into a prompt with the Gemma template
prompt = pipe.tokenizer.apply_chat_template(test_sample["messages"][:2], tokenize=False, add_generation_prompt=True)
print(prompt)
# Generate our SQL query.
outputs = pipe(prompt, generation_config=config)
# Extract the user query and original answer
print(f"Context:\n", re.search(r'<SCHEMA>\n(.*?)\n</SCHEMA>', test_sample['messages'][1]['content'], re.DOTALL).group(1).strip())
print(f"Query:\n", re.search(r'<USER_QUERY>\n(.*?)\n</USER_QUERY>', test_sample['messages'][1]['content'], re.DOTALL).group(1).strip())
print(f"Original Answer:\n{test_sample['messages'][2]['content']}")
print(f"Generated Answer:\n{outputs[0]['generated_text'][len(prompt):].strip()}")
<bos><|turn>system You are a text to SQL query translator. Users will ask you questions in English and you will generate a SQL query based on the provided SCHEMA.<turn|> <|turn>user Given the <USER_QUERY> and the <SCHEMA>, generate the corresponding SQL command to retrieve the desired data, considering the query's syntax, semantics, and schema constraints. <SCHEMA> CREATE TABLE broadband_plans (plan_id INT, plan_name VARCHAR(255), download_speed INT, upload_speed INT, price DECIMAL(5,2)); </SCHEMA> <USER_QUERY> Delete a broadband plan from the 'broadband_plans' table </USER_QUERY><turn|> <|turn>model Context: CREATE TABLE broadband_plans (plan_id INT, plan_name VARCHAR(255), download_speed INT, upload_speed INT, price DECIMAL(5,2)); Query: Delete a broadband plan from the 'broadband_plans' table Original Answer: DELETE FROM broadband_plans WHERE plan_id = 3001; Generated Answer: DELETE FROM broadband_plans WHERE plan_name = 'Basic';
สรุปและขั้นตอนถัดไป
บทแนะนำนี้ครอบคลุมวิธีปรับแต่งโมเดล Gemma อย่างละเอียดโดยใช้ TRL และ QLoRA โปรดดูเอกสารต่อไปนี้ในขั้นตอนถัดไป
- ดูวิธีสร้างข้อความด้วยโมเดล Gemma
- ดูวิธีปรับแต่ง Gemma อย่างละเอียดสำหรับงานด้านวิชันซิสเต็มโดยใช้ Hugging Face Transformers
- ดูวิธีปรับแต่งและอนุมานแบบกระจายในโมเดล Gemma อย่างละเอียด
- ดูวิธีใช้โมเดลแบบเปิด Gemma กับ Vertex AI
- ดูวิธีปรับแต่ง Gemma อย่างละเอียดโดยใช้ KerasNLP และทำให้ใช้งานได้กับ Vertex AI
เรียกใช้ใน Google Colab
ดูซอร์สโค้ดใน GitHub