การประเมินและนำโมเดลที่ปรับแต่งละเอียดไปใช้งาน
ทำการประเมินเชิงปริมาณโดยเปรียบเทียบโมเดลพื้นฐานกับโมเดลที่ปรับแต่งละเอียดบนกรณีทดสอบที่กันไว้ แปลงเป็น GGUF เพื่ออนุมานในเครื่อง และให้บริการผ่าน llama.cpp หรือ vLLM
การประเมินและนำโมเดลที่ปรับแต่งละเอียดไปใช้งาน เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Engineering Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องประเมินก่อนนำไปใช้งาน
โมเดลที่ปรับแต่งละเอียดแล้วซึ่งทำงานได้ดีบนข้อมูลการฝึก อาจทำงานแย่กว่าโมเดลพื้นฐานเมื่อใช้กับกรณีใช้งานจริงของคุณ วิธีเดียวที่จะทราบได้คือการประเมินอย่างเข้มงวด การปรับแต่งละเอียดอาจทำให้เกิด การลืมอย่างรุนแรง (สูญเสียความสามารถที่โมเดลพื้นฐานเคยมี) การปรับให้เฉพาะทางมากเกินไป (ทำงานได้ดีในงานของคุณแต่แย่ลงในงานใกล้เคียง) หรือการถดถอยอย่างละเอียดในพฤติกรรมด้านความปลอดภัย อย่านำโมเดลที่ปรับแต่งละเอียดแล้วไปใช้งานโดยไม่ประเมินเทียบกับโมเดลพื้นฐานด้วยชุดทดสอบที่เป็นตัวแทนของการใช้งานจริง
การสร้างชุดทดสอบที่กันไว้ออกจากการฝึก
ชุดทดสอบของคุณต้องแยกออกจากข้อมูลการฝึกและการตรวจสอบความถูกต้องโดยสมบูรณ์ โดยเป็นตัวอย่างที่โมเดลไม่เคยเห็นในขั้นตอนใดของการฝึก ชุดทดสอบควรแทน การกระจายตัวของอินพุตในการใช้งานจริงทั้งหมด ซึ่งรวมถึงกรณีทั่วไป กรณีขอบ และอินพุตที่ออกแบบมาเพื่อโจมตี สำหรับงานทำตามคำสั่ง ให้รวมตัวอย่างที่ต้องทำตามคำสั่งทุกส่วน ไม่ใช่เฉพาะส่วนที่พบบ่อยที่สุด โดยทั่วไป ชุดทดสอบ 100-500 ตัวอย่างก็เพียงพอสำหรับการประเมินที่น่าเชื่อถือ
import json
from typing import TypedDict
class TestCase(TypedDict):
input: str # the user message
expected_output: str # the ideal response
category: str # e.g., 'format', 'accuracy', 'edge_case'
evaluation_method: str # 'exact_match', 'json_schema', 'llm_judge'
# Load test set (never used during training)
def load_test_set(path: str) -> list[TestCase]:
cases = []
with open(path) as f:
for line in f:
data = json.loads(line.strip())
cases.append({
'input': data['messages'][-2]['content'], # user message
'expected_output': data['messages'][-1]['content'], # assistant response
'category': data.get('metadata', {}).get('category', 'general'),
'evaluation_method': data.get('metadata', {}).get('eval_method', 'llm_judge')
})
return cases
test_set = load_test_set('test.jsonl')
print(f'Test set loaded: {len(test_set)} examples')ตัวชี้วัดเชิงปริมาณสำหรับการประเมินเฉพาะงาน
เลือกตัวชี้วัดการประเมินให้ตรงกับงานของคุณ สำหรับ การดึงข้อมูล JSON ให้วัดอัตราการเป็นไปตามโครงสร้างและความถูกต้องในระดับฟิลด์ สำหรับ การจำแนกประเภท ให้วัดความถูกต้อง ความแม่นยำ และการเรียกคืนแยกตามประเภท สำหรับ การสร้างข้อความ ให้ใช้การให้คะแนนโดย LLM ในฐานะผู้ตัดสินเพื่อประเมินคุณภาพ สำหรับ การทำตามรูปแบบ ให้วัดอัตราการเป็นไปตามรูปแบบอย่างตรงตามข้อกำหนด เรียกใช้ตัวชี้วัดแต่ละรายการกับทั้งโมเดลพื้นฐานและโมเดลที่ปรับแต่งละเอียดแล้ว เพื่อวัดส่วนต่างของการปรับปรุง
import json
def evaluate_json_extraction(model_output: str, expected: str, schema: dict) -> dict:
metrics = {'valid_json': False, 'schema_compliant': False, 'field_accuracy': 0.0}
try:
parsed = json.loads(model_output.strip())
metrics['valid_json'] = True
# Check schema compliance
required_fields = schema.get('required', [])
all_present = all(field in parsed for field in required_fields)
correct_types = all(
isinstance(parsed.get(field), schema['properties'][field]['expected_type'])
for field in required_fields if field in parsed
)
metrics['schema_compliant'] = all_present and correct_types
# Field-level accuracy against expected output
expected_parsed = json.loads(expected)
correct_fields = sum(1 for k in expected_parsed if parsed.get(k) == expected_parsed[k])
metrics['field_accuracy'] = correct_fields / len(expected_parsed) if expected_parsed else 0.0
except json.JSONDecodeError:
pass # valid_json stays False
return metricsการประเมินโดย LLM ในฐานะผู้ตัดสิน
สำหรับงานสร้างข้อความปลายเปิด ให้ใช้ LLM ในฐานะผู้ตัดสินเพื่อให้คะแนนเอาต์พุตของโมเดลที่ปรับแต่งละเอียดแล้ว โดยเทียบกับเอาต์พุตที่คาดหวัง สั่ง GPT-4o ให้ทำหน้าที่เป็นผู้ประเมิน ระบุอินพุต เอาต์พุตที่คาดหวัง และเอาต์พุตของโมเดล แล้วขอให้ให้คะแนนความถูกต้อง ความครบถ้วน และการเป็นไปตามรูปแบบในระดับ 1-5 หาค่าเฉลี่ยคะแนนตลอดชุดทดสอบเพื่อได้คะแนนคุณภาพโดยรวม จากนั้นเปรียบเทียบคะแนนของโมเดลที่ปรับแต่งละเอียดแล้วกับคะแนนของโมเดลพื้นฐานในชุดทดสอบเดียวกัน
from openai import OpenAI
client = OpenAI()
def llm_judge_score(instruction: str, expected: str, actual: str) -> dict:
judge_prompt = f'''Evaluate the quality of an AI assistant response.
Instruction given to assistant:
{instruction}
Expected ideal response:
{expected}
Actual response from model being evaluated:
{actual}
Rate the actual response on these criteria (1=poor, 5=excellent):
1. Correctness: Is the information accurate?
2. Format compliance: Does it follow the expected output format?
3. Completeness: Does it address all parts of the instruction?
Return JSON: {{"correctness": N, "format": N, "completeness": N, "overall": N, "reason": "brief explanation"}}'''
response = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': judge_prompt}],
response_format={'type': 'json_object'}
)
return json.loads(response.choices[0].message.content)การเรียกใช้การประเมินเปรียบเทียบ
ทำการประเมินแบบแข่งขันโดยเปรียบเทียบโมเดลพื้นฐาน โมเดลที่ปรับแต่งละเอียดแล้ว (และอาจรวมแนวทางพื้นฐานที่ใช้พรอมต์อย่างมีประสิทธิภาพ) กับกรณีทดสอบทั้งหมด สร้างเอาต์พุตจากแต่ละโมเดลสำหรับทุกกรณีทดสอบ แล้วให้คะแนนเอาต์พุตทั้งหมดด้วยตัวชี้วัดการประเมิน จัดทำตารางเปรียบเทียบที่แสดงคะแนนตัวชี้วัด ส่วนเบี่ยงเบนมาตรฐาน และตัวอย่างที่โมเดลที่ปรับแต่งละเอียดแล้วทำได้ดีกว่าหรือแย่กว่าแนวทางพื้นฐาน
def run_full_evaluation(test_set: list, models: dict, system_prompt: str) -> dict:
results = {name: {'scores': [], 'errors': 0} for name in models}
for i, test_case in enumerate(test_set):
print(f'Evaluating test case {i+1}/{len(test_set)}')
for model_name, model_fn in models.items():
try:
output = model_fn(test_case['input'], system_prompt)
score = llm_judge_score(
test_case['input'],
test_case['expected_output'],
output
)
results[model_name]['scores'].append(score['overall'])
except Exception as e:
results[model_name]['errors'] += 1
results[model_name]['scores'].append(0)
# Summarize
summary = {}
for name, data in results.items():
scores = data['scores']
summary[name] = {
'mean_score': sum(scores) / len(scores),
'errors': data['errors']
}
print(f'{name}: mean={summary[name]["mean_score"]:.2f}, errors={data["errors"]}')
return summaryการทดสอบการถดถอยเพื่อจับการลืมอย่างรุนแรง
การปรับแต่งละเอียดอาจทำให้ความสามารถทั่วไปของโมเดลลดลง ซึ่งเป็นปรากฏการณ์ที่เรียกว่า การลืมอย่างรุนแรง ให้เรียกใช้ชุดการทดสอบการถดถอยกับทั้งโมเดลพื้นฐานและโมเดลที่ปรับแต่งละเอียดแล้ว โดยครอบคลุมงานที่คุณให้ความสำคัญนอกเหนือจากงานเป้าหมาย เช่น การตอบคำถามทั่วไป การให้เหตุผล การสร้างโค้ด และการทำตามคำสั่ง หากโมเดลที่ปรับแต่งละเอียดแล้วได้คะแนนในงานเหล่านี้ต่ำลงอย่างมีนัยสำคัญ แรงก์ LoRA ของคุณอาจสูงเกินไป หรือคุณอาจฝึกนานเกินไป
REGRESSION_TEST_CASES = [
# General QA
{'input': 'What is the capital of France?', 'expected_substring': 'Paris'},
{'input': 'What is 17 * 23?', 'expected_substring': '391'},
# Instruction following
{'input': 'List 3 planets. Format as: 1. Planet Name', 'expected_pattern': r'^1\. '},
# Reasoning
{'input': 'If all A are B and all B are C, are all A also C?', 'expected_substring': 'yes'},
]
def run_regression_tests(model_fn, test_cases: list) -> float:
passed = 0
for test in test_cases:
output = model_fn(test['input'], '')
if 'expected_substring' in test:
if test['expected_substring'].lower() in output.lower():
passed += 1
elif 'expected_pattern' in test:
import re
if re.search(test['expected_pattern'], output):
passed += 1
rate = passed / len(test_cases)
print(f'Regression test pass rate: {rate:.1%} ({passed}/{len(test_cases)})')
return rateการแปลงเป็น GGUF สำหรับการอนุมานภายในเครื่อง
สำหรับการนำไปใช้งานภายในเครื่องโดยไม่ต้องมีโครงสร้างพื้นฐาน GPU ราคาแพง ให้แปลงโมเดลที่รวมแล้วเป็น รูปแบบ GGUF และเรียกใช้การอนุมานด้วย llama.cpp GGUF รองรับระดับการทำควอนไทซ์หลากหลายระดับ ได้แก่ Q4_K_M (4 บิต สมดุลระหว่างคุณภาพกับความเร็วที่ดี), Q8_0 (8 บิต คุณภาพใกล้เคียงความละเอียดเต็ม) และ Q2_K (2 บิต เร็วมากแต่คุณภาพต่ำกว่า) โมเดล 7B ที่ทำควอนไทซ์แบบ Q4 ต้องใช้ RAM เพียงประมาณ 4GB และสามารถทำงานบน CPU ได้ที่ความเร็ว 1-5 โทเคนต่อวินาที
# Step 1: Convert merged HuggingFace model to GGUF
# git clone https://github.com/ggerganov/llama.cpp
# python llama.cpp/convert_hf_to_gguf.py ./merged-model --outtype f16 --outfile model-f16.gguf
# Step 2: Quantize to 4-bit
# ./llama.cpp/llama-quantize model-f16.gguf model-q4.gguf Q4_K_M
# Step 3: Run inference with llama.cpp Python bindings
# pip install llama-cpp-python
from llama_cpp import Llama
llm = Llama(
model_path='./model-q4.gguf',
n_ctx=4096, # context window
n_threads=8, # CPU threads
n_gpu_layers=0 # set > 0 to offload layers to GPU
)
output = llm.create_chat_completion(
messages=[{'role': 'user', 'content': 'What is the capital of France?'}],
temperature=0.1
)
print(output['choices'][0]['message']['content'])การให้บริการด้วย vLLM สำหรับการใช้งานจริง
สำหรับการให้บริการโมเดลที่ปรับแต่งละเอียดแล้วในระบบใช้งานจริงในระดับขนาดใหญ่ vLLM เป็นมาตรฐานที่ใช้กันในปัจจุบัน vLLM ใช้ PagedAttention เพื่อจัดชุดคำขอหลายรายการเข้าด้วยกันอย่างมีประสิทธิภาพ ทำให้ปริมาณงานของ GPU เพิ่มขึ้นอย่างมาก โดยรองรับจุดปลายทาง API ที่เข้ากันได้กับ OpenAI จึงสามารถใช้แทน API ของ OpenAI ได้ทันที GPU A100 เพียงหนึ่งตัวที่เรียกใช้ vLLM กับโมเดล 7B ที่ปรับแต่งละเอียดแล้ว สามารถรองรับคำขอหลายร้อยรายการต่อนาที
# Start vLLM server (run from command line)
# pip install vllm
# python -m vllm.entrypoints.openai.api_server \
# --model ./merged-model \
# --host 0.0.0.0 \
# --port 8000 \
# --max-model-len 4096 \
# --tensor-parallel-size 1
# Use with OpenAI client (drop-in replacement)
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:8000/v1',
api_key='not-needed' # vLLM doesn't require auth by default
)
response = client.chat.completions.create(
model='merged-model', # model name matches the path you passed to vLLM
messages=[{'role': 'user', 'content': 'Extract JSON from: "Alice, 30, NYC"'}]
)
print(response.choices[0].message.content)การทดสอบ A/B กับโมเดลที่ปรับแต่งละเอียดแล้ว
ก่อนเปลี่ยนไปใช้โมเดลที่ปรับแต่งละเอียดแล้วในระบบใช้งานจริงทั้งหมด ให้ทำ การทดสอบ A/B โดยส่งทราฟฟิกจากการใช้งานจริงบางส่วน (เริ่มที่ 5-10%) ไปยังโมเดลที่ปรับแต่งละเอียดแล้ว ขณะที่ทราฟฟิกส่วนใหญ่ยังใช้โมเดลพื้นฐานหรือแนวทางพรอมต์เดิม ติดตามคะแนนคุณภาพ เวลาแฝง และตัวชี้วัดความพึงพอใจของผู้ใช้ของทั้งสองกลุ่ม เพิ่มสัดส่วนทราฟฟิกของโมเดลที่ปรับแต่งละเอียดแล้วก็ต่อเมื่อการทดสอบ A/B ยืนยันว่ามีการปรับปรุง หลังมีคำขอจำนวนมากพอที่จะให้ผลอย่างมีนัยสำคัญทางสถิติ
import random
class ModelRouter:
def __init__(self, fine_tuned_traffic_fraction=0.1):
self.ft_fraction = fine_tuned_traffic_fraction
self.metrics = {'base': {'count': 0, 'quality_sum': 0}, 'fine_tuned': {'count': 0, 'quality_sum': 0}}
def route(self, user_id: str, request: str) -> dict:
# Deterministic routing by user_id (same user always goes to same model)
use_fine_tuned = (hash(user_id) % 100) < (self.ft_fraction * 100)
model_group = 'fine_tuned' if use_fine_tuned else 'base'
response = call_model(request, use_fine_tuned=use_fine_tuned)
return {'response': response, 'model_group': model_group}
def record_quality(self, model_group: str, quality_score: float):
self.metrics[model_group]['count'] += 1
self.metrics[model_group]['quality_sum'] += quality_score
def ab_test_summary(self) -> dict:
summary = {}
for group, data in self.metrics.items():
avg = data['quality_sum'] / data['count'] if data['count'] > 0 else 0
summary[group] = {'avg_quality': avg, 'n': data['count']}
return summaryการดูแลรักษาโมเดลที่ปรับแต่งละเอียดแล้วในระยะยาว
โมเดลที่ปรับแต่งละเอียดแล้วต้องได้รับการดูแลรักษาอย่างต่อเนื่อง เมื่อโมเดลพื้นฐานอัปเดต (เช่น GPT-4o เวอร์ชันใหม่ หรือ Mistral รุ่นใหม่) ค่าน้ำหนักของตัวปรับอาจเข้ากันไม่ได้ และคุณอาจต้องฝึกใหม่ เมื่อข้อกำหนดของงานเปลี่ยนแปลง คุณต้องอัปเดตข้อมูลการฝึกและฝึกใหม่ เมื่อค้นพบรูปแบบความล้มเหลวใหม่ในการใช้งานจริง ให้เพิ่มตัวอย่างลงในชุดข้อมูลฝึก วางแผน การฝึกใหม่เป็นระยะให้เป็นส่วนหนึ่งของเวิร์กโฟลว์การดำเนินงาน ML ในระบบใช้งานจริง
เมทริกซ์การตัดสินใจนำไปใช้งาน
การเลือกกลยุทธ์การนำโมเดลที่ปรับแต่งแล้วไปใช้งานขึ้นอยู่กับขนาดการใช้งานและข้อจำกัดด้านโครงสร้างพื้นฐานของคุณ สำหรับปริมาณการใช้งานต่ำ (น้อยกว่า 1,000 คำขอต่อวัน) API สำหรับการปรับแต่งโมเดลของ OpenAI เป็นตัวเลือกที่ง่ายที่สุด สำหรับปริมาณการใช้งานปานกลาง (1,000–100,000 คำขอต่อวัน) ให้พิจารณาใช้ vLLM บนอินสแตนซ์ GPU เดียว สำหรับแอปพลิเคชันที่มีปริมาณการใช้งานสูงหรือมีข้อกำหนดด้านเวลาแฝงอย่างเข้มงวด ให้ใช้ vLLM กับ GPU หลายตัว พิจารณาการประมวลผลแบบขนานของเทนเซอร์ และเพิ่มชั้นแคชไว้ด้านหน้า สำหรับข้อมูลที่มีความอ่อนไหวด้านความเป็นส่วนตัว ให้โฮสต์ด้วยตนเองบนโครงสร้างพื้นฐานของคุณโดยใช้ GGUF/llama.cpp หรือ vLLM
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจของคุณเกี่ยวกับการประเมินและการนำโมเดลที่ปรับแต่งแล้วไปใช้งานจากบทเรียนนี้
สรุปบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า การประเมินก่อนนำไปใช้งานอย่างเคร่งครัด โดยเปรียบเทียบโมเดลที่ปรับแต่งแล้วกับโมเดลพื้นฐานบนกรณีทดสอบที่กันไว้นั้นเป็นสิ่งที่ขาดไม่ได้ การทดสอบการถดถอยช่วยตรวจจับการลืมความสามารถทั่วไปอย่างรุนแรงซึ่งเกิดจากการปรับให้เฉพาะทางมากเกินไป และตัวเลือกในการนำไปใช้งานครอบคลุมตั้งแต่ API การปรับแต่งโมเดลที่ OpenAI ดูแลให้ เพื่อความเรียบง่าย ไปจนถึง vLLM สำหรับให้บริการในสภาพแวดล้อมจริงที่ต้องรองรับปริมาณงานสูง และ GGUF/llama.cpp สำหรับการอนุมานภายในเครื่องด้วย CPU ขอแสดงความยินดีที่เรียนจบเส้นทางวิศวกรรม AI!
คำถามที่พบบ่อย
บทเรียน “การประเมินและนำโมเดลที่ปรับแต่งละเอียดไปใช้งาน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การประเมินและนำโมเดลที่ปรับแต่งละเอียดไปใช้งาน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การประเมินและนำโมเดลที่ปรับแต่งละเอียดไปใช้งาน”
ทำการประเมินเชิงปริมาณโดยเปรียบเทียบโมเดลพื้นฐานกับโมเดลที่ปรับแต่งละเอียดบนกรณีทดสอบที่กันไว้ แปลงเป็น GGUF เพื่ออนุมานในเครื่อง และให้บริการผ่าน llama.cpp หรือ vLLM คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การประเมินและนำโมเดลที่ปรับแต่งละเอียดไปใช้งาน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม
ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เมื่อการปรับแต่งละเอียดดีกว่าการเขียนพรอมต์
- การเตรียมชุดข้อมูลฝึกคุณภาพสูง
- การปรับแต่งละเอียด LoRA ด้วย Hugging Face PEFT
- การประเมินและนำโมเดลที่ปรับแต่งละเอียดไปใช้งาน