ในโลกของ AI production สมัยนี้ การที่โมเดลตอบว่า "มั่นใจ 99%" แต่ความจริงถูกแค่ 60% นี่คือปัญหาที่ทำให้ระบบหลายตัวพังทลาย ในบทความนี้ผมจะสอนวิธี calibrate โมเดล AI ให้ probability ที่ออกมานั้นตรงกับความเป็นจริง พร้อมโค้ดที่ใช้งานได้จริงกับ HolySheep AI

ทำไม Calibration ถึงสำคัญ: กรณีศึกษาจากโปรเจกต์จริง

ผมเคยพัฒนาระบบ RAG สำหรับองค์กรขนาดใหญ่แห่งหนึ่ง ระบบตอบคำถามลูกค้าเกี่ยวกับสินค้าคงคลัง ปัญหาคือตอนแรกโมเดลบอกว่ามั่นใจ 95% แต่พอตรวจสอบ才发现ว่า accuracy จริงๆ แค่ 70% เท่านั้น นี่คือจุดที่ผมเริ่มศึกษาเรื่อง model calibration อย่างจริงจัง

พื้นฐาน: Calibration Curve และ Expected Calibration Error (ECE)

Calibration ที่ดีหมายความว่า เมื่อโมเดลบอกว่ามั่นใจ X% แล้วความถูกต้องควรจะใกล้ X% จริงๆ

import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix

def calculate_ece(confidences, accuracies, n_bins=10):
    """
    คำนวณ Expected Calibration Error (ECE)
    - confidences: ความมั่นใจที่โมเดลทำนาย (0-1)
    - accuracies: ความถูกต้องจริง (0 หรือ 1)
    """
    bin_boundaries = np.linspace(0, 1, n_bins + 1)
    ece = 0.0
    
    for i in range(n_bins):
        bin_lower = bin_boundaries[i]
        bin_upper = bin_boundaries[i + 1]
        
        # หา samples ในแต่ละ bin
        in_bin = (confidences > bin_lower) & (confidences <= bin_upper)
        
        if np.sum(in_bin) > 0:
            avg_confidence = np.mean(confidences[in_bin])
            avg_accuracy = np.mean(accuracies[in_bin])
            bin_weight = np.sum(in_bin) / len(confidences)
            
            ece += bin_weight * np.abs(avg_confidence - avg_accuracy)
    
    return ece

def plot_calibration_curve(confidences, accuracies, model_name="Model"):
    """วาด Calibration Curve"""
    bin_boundaries = np.linspace(0, 1, 11)
    confidences_bin = []
    accuracies_bin = []
    
    for i in range(len(bin_boundaries) - 1):
        in_bin = (confidences > bin_boundaries[i]) & \
                 (confidences <= bin_boundaries[i + 1])
        
        if np.sum(in_bin) > 0:
            confidences_bin.append(np.mean(confidences[in_bin]))
            accuracies_bin.append(np.mean(accuracies[in_bin]))
    
    # Perfect calibration line
    plt.figure(figsize=(10, 8))
    plt.plot([0, 1], [0, 1], 'k--', label='Perfect Calibration')
    plt.plot(confidences_bin, accuracies_bin, 'o-', 
             linewidth=2, markersize=8, label=model_name)
    
    plt.xlabel('Confidence', fontsize=12)
    plt.ylabel('Accuracy', fontsize=12)
    plt.title(f'Calibration Curve - {model_name}', fontsize=14)
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.xlim([0, 1])
    plt.ylim([0, 1])
    plt.savefig('calibration_curve.png', dpi=150)
    plt.show()

ตัวอย่างการใช้งาน

np.random.seed(42) n_samples = 1000

โมเดลที่ uncalibrated (overconfident)

true_probs = np.random.uniform(0, 1, n_samples) confidences_uncal = np.minimum(1.0, true_probs + np.random.normal(0.15, 0.1, n_samples)) confidences_uncal = np.clip(confidences_uncal, 0, 1) accuracies = (np.random.uniform(0, 1, n_samples) < true_probs).astype(int)

คำนวณ ECE

ece_before = calculate_ece(confidences_uncal, accuracies) print(f"ECE ก่อน Calibration: {ece_before:.4f}")

แสดงผล

plot_calibration_curve(confidences_uncal, accuracies, "Uncalibrated Model")

Temperature Scaling: วิธี Calibration ที่ง่ายแต่ทรงพลัง

Temperature scaling เป็นวิธีที่นิยมมากที่สุดในการ calibrate โมเดล โดยปรับ temperature parameter T ใน softmax function

import torch
import torch.nn.functional as F
from scipy.optimize import minimize_scalar

class TemperatureScaler:
    """
    Temperature Scaling for Model Calibration
    ปรับ temperature T ให้ probability ตรงกับความเป็นจริง
    """
    def __init__(self):
        self.temperature = 1.0
    
    def calibrate(self, logits, labels, verbose=True):
        """
        Calibrate โมเดลด้วย validation set
        - logits: output ก่อน softmax จากโมเดล
        - labels: ground truth labels
        """
        # Objective: minimize NLL
        def nll_loss(T):
            scaled_logits = logits / T
            probs = F.softmax(scaled_logits, dim=1)
            loss = F.cross_entropy(scaled_logits, labels)
            return loss.item()
        
        # Optimize temperature
        result = minimize_scalar(nll_loss, bounds=(0.1, 10.0), method='bounded')
        self.temperature = result.x
        
        if verbose:
            print(f"Optimal Temperature: {self.temperature:.4f}")
            print(f"NLL Loss: {result.fun:.4f}")
        
        return self.temperature
    
    def forward(self, logits):
        """ใช้ calibrated temperature ในการ predict"""
        scaled_logits = logits / self.temperature
        return F.softmax(scaled_logits, dim=1)

def get_calibration_metrics(probs, labels):
    """คำนวณ metrics สำหรับวัด calibration quality"""
    predictions = np.argmax(probs, axis=1)
    accuracies = (predictions == labels).astype(float)
    confidences = np.max(probs, axis=1)
    
    ece = calculate_ece(confidences, accuracies)
    nll = -np.mean(np.log(probs[np.arange(len(labels)), labels] + 1e-10))
    
    # Brier Score
    one_hot = np.zeros_like(probs)
    one_hot[np.arange(len(labels)), labels] = 1
    brier = np.mean(np.sum((probs - one_hot) ** 2, axis=1))
    
    return {
        'ECE': ece,
        'NLL': nll,
        'Brier Score': brier,
        'Accuracy': np.mean(accuracies)
    }

ตัวอย่างการใช้งานกับ HolySheep API

import requests import json def get_model_calibration_data(): """ ดึง calibration data จาก HolySheep API ราคา: DeepSeek V3.2 เพียง $0.42/MTok ประหยัดมาก """ base_url = "https://api.holysheep.ai/v1" headers = { "Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY", "Content-Type": "application/json" } # ดึง logits จากโมเดล payload = { "model": "deepseek-v3.2", "messages": [ {"role": "user", "content": "Explain what calibration means in ML"} ], "temperature": 0.7, "max_tokens": 500 } response = requests.post( f"{base_url}/chat/completions", headers=headers, json=payload ) if response.status_code == 200: result = response.json() return result['choices'][0]['message']['content'] return None print("Calibration Metrics:") print(f"- ECE: ยิ่งต่ำยิ่งดี (< 0.01 ดีมาก)") print(f"- NLL: Negative Log Likelihood") print(f"- Brier Score: วัดความแม่นยำของ probability")

Ensemble และ Bayesian Methods สำหรับ Uncertainty Estimation

สำหรับงานที่ต้องการความแม่นยำสูงในการประเมิน uncertainty การใช้ ensemble หรือ Bayesian approach จะให้ผลลัพธ์ที่ดีกว่า

import torch
import torch.nn as nn
from typing import List, Tuple

class MC_Dropout_Estimator:
    """
    Monte Carlo Dropout - วิธีประมาณค่า uncertainty โดยใช้ dropout ในการ inference
    """
    def __init__(self, model, n_dropout_samples=30):
        self.model = model
        self.n_dropout_samples = n_dropout_samples
        self.model.train()  # เปิด dropout mode
    
    def predict_with_uncertainty(self, inputs):
        """ทำนายพร้อมคำนวณ uncertainty"""
        with torch.no_grad():
            dropout_outputs = []
            
            for _ in range(self.n_dropout_samples):
                output = self.model(inputs)
                dropout_outputs.append(F.softmax(output, dim=1))
            
            # Stack outputs
            stacked = torch.stack(dropout_outputs)
            
            # Mean prediction
            mean_probs = torch.mean(stacked, dim=0)
            
            # Uncertainty = variance across predictions
            uncertainty = torch.var(stacked, dim=0)
            
            return mean_probs, uncertainty
    
    def get_prediction_with_confidence(self, inputs, threshold=0.7):
        """
        Return prediction พร้อม confidence level
        - ถ้า uncertainty สูง → ต้องมีคนตรวจสอบ
        """
        mean_probs, uncertainty = self.predict_with_uncertainty(inputs)
        
        predictions = torch.argmax(mean_probs, dim=1)
        confidence = torch.max(mean_probs, dim=1)[0]
        max_uncertainty = torch.max(uncertainty, dim=1)[0]
        
        # กำหนดว่าต้อง human review หรือไม่
        needs_review = max_uncertainty > (1 - threshold)
        
        return {
            'predictions': predictions,
            'confidence': confidence,
            'uncertainty': max_uncertainty,
            'needs_human_review': needs_review
        }

class Deep_Ensemble_Calibrator:
    """
    Deep Ensemble - รวมผลจากหลายโมเดลเพื่อ uncertainty ที่ดีกว่า
    """
    def __init__(self, models: List[nn.Module]):
        self.models = models
        self.scalers = [TemperatureScaler() for _ in models]
    
    def calibrate_ensemble(self, logits_list, labels):
        """Calibrate ทุกโมเดลใน ensemble"""
        for i, (model, scaler, logits) in enumerate(
            zip(self.models, self.scalers, logits_list)
        ):
            print(f"Calibrating model {i+1}/{len(self.models)}...")
            scaler.calibrate(logits, labels, verbose=False)
    
    def ensemble_predict(self, inputs):
        """Predict ด้วย ensemble พร้อม uncertainty"""
        all_probs = []
        
        for model, scaler in zip(self.models, self.scalers):
            model.eval()
            with torch.no_grad():
                logits = model(inputs)
                probs = scaler.forward(logits)
                all_probs.append(probs)
        
        # รวม probability จากทุกโมเดล
        stacked_probs = torch.stack(all_probs)
        mean_probs = torch.mean(stacked_probs, dim=0)
        std_probs = torch.std(stacked_probs, dim=0)
        
        return mean_probs, std_probs

ตัวอย่างการใช้งาน

print("MC Dropout สำหรับ Uncertainty:") print("- ทำ inference หลายครั้งโดยเปิด dropout") print("- ความแปรปรวน (variance) คือ uncertainty") print("- ยิ่งทำหลายครั้ง ยิ่งแม่นยำ แต่ช้าลง")

การนำ Calibration ไปใช้กับ RAG System จริง

ในระบบ RAG ของผมที่ใช้กับอีคอมเมิร์ซ ผมใช้ calibration เพื่อตัดสินใจว่าควร trust คำตอบจาก retrieval หรือไม่

import requests
from typing import Dict, List, Optional

class RAG_Calibrated_Retriever:
    """
    RAG System พร้อม Calibration-based Trust Scoring
    """
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://api.holysheep.ai/v1"
        self.calibration_threshold = 0.75  # confidence threshold
    
    def query_with_confidence(self, question: str, context: str) -> Dict:
        """
        Query RAG system พร้อมวัด confidence
        ใช้ DeepSeek V3.2 ราคาเพียง $0.42/MTok
        """
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        prompt = f"""Based on the following context, answer the question.
If the context doesn't contain enough information, say so.

Context: {context}

Question: {question}

Answer with your confidence level (0-100%) and explain why."""

        payload = {
            "model": "deepseek-v3.2",
            "messages": [
                {"role": "system", "content": "You are a helpful assistant."},
                {"role": "user", "content": prompt}
            ],
            "temperature": 0.3,  # ต่ำเพื่อความสม่ำเสมอ
            "max_tokens": 300
        }
        
        response = requests.post(
            f"{self.base_url}/chat/completions",
            headers=headers,
            json=payload
        )
        
        if response.status_code == 200:
            result = response.json()
            answer = result['choices'][0]['message']['content']
            
            # ประมวลผล confidence จาก response
            confidence = self._extract_confidence(answer)
            
            return {
                'answer': answer,
                'confidence': confidence,
                'needs_human_review': confidence < self.calibration_threshold,
                'trust_level': self._get_trust_level(confidence)
            }
        
        return {'error': 'API request failed'}
    
    def _extract_confidence(self, text: str) -> float:
        """ดึง confidence percentage จาก text"""
        import re
        match = re.search(r'(\d+)%', text)
        if match:
            return int(match.group(1)) / 100
        
        # ถ้าไม่มี explicit percentage ใช้ heuristic
        high_confidence_words = ['certain', 'definitely', 'clearly', 'obviously']
        low_confidence_words = ['might', 'perhaps', 'possibly', 'uncertain']
        
        text_lower = text.lower()
        for word in high_confidence_words:
            if word in text_lower:
                return 0.85
        for word in low_confidence_words:
            if word in text_lower:
                return 0.45
        
        return 0.65  # default
    
    def _get_trust_level(self, confidence: float) -> str:
        """กำหนดระดับความน่าเชื่อถือ"""
        if confidence >= 0.9:
            return "HIGH - Auto-answer"
        elif confidence >= 0.75:
            return "MEDIUM - Monitor"
        elif confidence >= 0.5:
            return "LOW - Flag for review"
        else:
            return "VERY_LOW - Escalate to human"

ตัวอย่างการใช้งาน

rag_system = RAG_Calibrated_Retriever("YOUR_HOLYSHEEP_API_KEY") result = rag_system.query_with_confidence( question="สินค้า SKU-1234 มี stock กี่ชิ้น?", context="สินค้า SKU-1234 คือ กระเป๋าสตางค์หนังแท้ สีดำ มี stock 45 ชิ้น" ) print(f"คำตอบ: {result['answer']}") print(f"ความมั่นใจ: {result['confidence']:.0%}") print(f"Trust Level: {result['trust_level']}")

ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

1. ใช้ Temperature = 1.0 ตลอด (Underfitting)

ปัญหา: หลายคนไม่ calibrate เลย ใช้ temperature default ที่ 1.0 ซึ่งไม่เหมาะกับทุกโมเดล

# ❌ ผิด: ใช้ temperature แบบ fixed โดยไม่ calibrate
response = requests.post(
    f"{base_url}/chat/completions",
    headers=headers,
    json={
        "model": "gpt-4.1",
        "messages": [...],
        "temperature": 1.0  # ไม่ได้ calibrate
    }
)

✅ ถูกต้อง: Calibrate temperature ก่อนใช้งานจริง

สร้าง validation set ก่อน

val_logits = [] # เก็บ logits จาก validation data val_labels = [] # เก็บ labels จาก validation data

Optimize temperature

scaler = TemperatureScaler() optimal_temp = scaler.calibrate( torch.tensor(val_logits), torch.tensor(val_labels) ) print(f"Temperature ที่เหมาะสม: {optimal_temp}")

ใช้ temperature ที่ calibrated แล้ว

response = requests.post( f"{base_url}/chat/completions", headers=headers, json={ "model": "gpt-4.1", "messages": [...], "temperature": optimal_temp # ใช้ค่าที่ optimize แล้ว } )

2. Confusion ระหว่าง Confidence และ Uncertainty

ปัญหา: ใช้ confidence เป็น uncertainty ซึ่งไม่ถูกต้อง โมเดลอาจมั่นใจแม้ว่าจะไม่รู้

# ❌ ผิด: ใช้ softmax probability เป็น uncertainty
def bad_uncertainty_score(probs):
    confidence = np.max(probs, axis=1)
    # โมเดลอาจบอก 0.95 แม้ไม่รู้อะไรเลย
    return 1 - confidence  # นี่ไม่ใช่ uncertainty ที่แท้จริง

✅ ถูกต้อง: ใช้ entropy หรือ variance จาก ensemble

def proper_uncertainty_score(probs, use_entropy=True): if use_entropy: # Entropy: สูง = ไม่แน่นอน eps = 1e-10 entropy = -np.sum(probs * np.log(probs + eps), axis=1) max_entropy = np.log(probs.shape[1]) return entropy / max_entropy # normalize to [0, 1] else: # จาก ensemble: variance สูง = ไม่แน่นอน return np.std(probs, axis=1)

หรือใช้ MC Dropout

mc_estimator = MC_Dropout_Estimator(model, n_dropout_samples=50) mean_probs, uncertainty = mc_estimator.predict_with_uncertainty(inputs)

Decision boundary

needs_review = uncertainty > 0.15 # threshold ที่เหมาะสม

3. ลืมว่า Calibration ต้องทำบน Data ที่ Representative

ปัญหา: Calibrate บน training data แล้วนำไปใช้บน production data ที่ต่างกัน

# ❌ ผิด: Calibrate บน training set
train_logits, train_labels = get_model_outputs(model, train_data)
scaler.calibrate(train_logits, train_labels)  # ผิด!

✅ ถูกต้อง: แบ่งข้อมูลเป็น train/val/calibration

Step 1: Train โมเดล

model.fit(train_data, train_labels)

Step 2: Validation สำหรับ hyperparameters

val_logits, val_labels = get_model_outputs(model, val_data) tune_hyperparameters(model, val_logits, val_labels)

Step 3: Calibration set แยกต่างหาก (ไม่เคยเห็นตอน train)

calib_logits, calib_labels = get_model_outputs(model, calibration_data) scaler.calibrate(calib_logits, calib_labels)

Step 4: Test บน test set (เพื่อวัดผลจริง)

test_logits, test_labels = get_model_outputs(model, test_data) metrics = get_calibration_metrics(scaler.forward(test_logits), test_labels) print(f"ECE on Test Set: {metrics['ECE']:.4f}")

สำคัญ: Production data ควรคล้าย calibration data

ถ้า distribution เปลี่ยน → ต้อง recalibrate

4. ใช้ API Endpoint ผิด (Authentication Error)

ปัญหา: ใช้ base_url หรือ API key format ผิด

# ❌ ผิด: ใช้ OpenAI endpoint
WRONG_URL = "https://api.openai.com/v1/chat/completions"  # ห้ามใช้!

❌ ผิด: API key format ผิด

headers = { "Authorization": "sk-xxxxx", # format ผิดสำหรับ HolySheep }

✅ ถูกต้อง: ใช้ HolySheep endpoint

CORRECT_BASE_URL = "https://api.holysheep.ai/v1" headers = { "Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY", # รูปแบบที่ถูกต้อง "Content-Type": "application/json" }

ตรวจสอบ API key ก่อนใช้งาน

def verify_api_connection(api_key: str) -> bool: """ตรวจสอบว่า API key ใช้งานได้หรือไม่""" response = requests.get( "https://api.holysheep.ai/v1/models", headers={"Authorization": f"Bearer {api_key}"} ) return response.status_code == 200 if verify_api_connection("YOUR_HOLYSHEEP_API_KEY"): print("✅ API Key ถูกต้อง") else: print("❌ ตรวจสอบ API Key อีกครั้ง")

สรุป: Best Practices สำหรับ AI Model Calibration

การ calibrate โมเดล AI ไม่ใช่ทางเลือกอีกต่อไป แต่เป็นสิ่งจำเป็นสำหรับระบบที่ต้องการความน่าเชื่อถือ โดยเฉพาะในอุตสาหกรรมที่ต้องการ compliance และ audit trail

👉 สมัคร HolySheep AI — รับเครดิตฟรีเมื่อลงทะเบียน