Technology

Computer Vision YOLO Post-mortem Analysis

computer vision yolo post mortem analysis
Computer Vision YOLO Post-mortem Analysis | SiamCafe Blog
2026-04-19· อ. บอม — SiamCafe.net· 10,955 คำ

YOLO Object Detection

YOLO เป็น Real-time Object Detection ที่เร็วมาก Single Pass ตรวจจับวัตถุในภาพ YOLOv8 เป็นเวอร์ชันล่าสุด รองรับ Detection Segmentation Classification Pose

Post-mortem Analysis วิเคราะห์หลังเกิด Incident หา Root Cause สำหรับ ML คือวิเคราะห์ว่า Model ทำนายผิดเพราะอะไร ปรับปรุง Data และ Model

YOLOv8 Setup และ Training

# === YOLOv8 Object Detection ===
# pip install ultralytics

from ultralytics import YOLO
import os

# 1. Load Pre-trained Model
model = YOLO("yolov8n.pt")  # nano (fastest)
# model = YOLO("yolov8s.pt")  # small
# model = YOLO("yolov8m.pt")  # medium
# model = YOLO("yolov8l.pt")  # large
# model = YOLO("yolov8x.pt")  # extra-large (most accurate)

# 2. Inference (Detection)
# results = model("image.jpg")
# results = model("video.mp4")
# results = model(0)  # Webcam

# 3. Process Results
# for result in results:
#     boxes = result.boxes
#     for box in boxes:
#         cls = int(box.cls[0])
#         conf = float(box.conf[0])
#         xyxy = box.xyxy[0].tolist()
#         name = model.names[cls]
#         print(f"  {name}: {conf:.2f} at {xyxy}")

# 4. Custom Training
# data.yaml format:
# path: /datasets/my_project
# train: images/train
# val: images/val
# test: images/test
# nc: 3
# names: ['car', 'person', 'bicycle']

# Train
# model = YOLO("yolov8n.pt")
# results = model.train(
#     data="data.yaml",
#     epochs=100,
#     imgsz=640,
#     batch=16,
#     lr0=0.01,
#     optimizer="AdamW",
#     augment=True,
#     patience=20,
#     save=True,
#     project="runs/detect",
#     name="my_model",
# )

# 5. Validate
# metrics = model.val(data="data.yaml")
# print(f"mAP50: {metrics.box.map50}")
# print(f"mAP50-95: {metrics.box.map}")

# 6. Export
# model.export(format="onnx")     # ONNX
# model.export(format="engine")   # TensorRT
# model.export(format="coreml")   # CoreML (iOS)
# model.export(format="tflite")   # TFLite (Android)

# CLI Alternative
# yolo detect train model=yolov8n.pt data=data.yaml epochs=100 imgsz=640
# yolo detect val model=best.pt data=data.yaml
# yolo detect predict model=best.pt source=image.jpg

print("YOLOv8 Setup:")
print("  Models: nano, small, medium, large, x-large")
print("  Tasks: detect, segment, classify, pose, obb")
print("  Export: ONNX, TensorRT, CoreML, TFLite")

Post-mortem Analysis สำหรับ ML

# postmortem_analysis.py — ML Model Post-mortem Analysis
import numpy as np
from dataclasses import dataclass, field
from typing import List, Dict, Tuple
from datetime import datetime
from collections import Counter

@dataclass
class Prediction:
    image_id: str
    true_class: str
    pred_class: str
    confidence: float
    iou: float  # Intersection over Union
    is_correct: bool

@dataclass
class ErrorPattern:
    pattern: str
    count: int
    examples: List[str]
    severity: str  # critical, high, medium, low

class MLPostMortem:
    """ML Model Post-mortem Analysis"""

    def __init__(self, model_name, version):
        self.model_name = model_name
        self.version = version
        self.predictions: List[Prediction] = []
        self.error_patterns: List[ErrorPattern] = []

    def add_prediction(self, pred: Prediction):
        self.predictions.append(pred)

    def analyze_errors(self):
        """วิเคราะห์ Error Patterns"""
        errors = [p for p in self.predictions if not p.is_correct]
        correct = [p for p in self.predictions if p.is_correct]

        # Confusion pairs
        confusion = Counter()
        for e in errors:
            pair = f"{e.true_class} -> {e.pred_class}"
            confusion[pair] += 1

        # Low confidence correct predictions
        low_conf = [p for p in correct if p.confidence < 0.5]

        # False Positives (predicted but wrong class)
        false_pos = [e for e in errors if e.pred_class != "none"]

        # False Negatives (missed detections)
        false_neg = [e for e in errors if e.pred_class == "none"]

        # Error patterns
        patterns = []
        for pair, count in confusion.most_common(5):
            patterns.append(ErrorPattern(
                f"Misclassification: {pair}",
                count,
                [e.image_id for e in errors
                 if f"{e.true_class} -> {e.pred_class}" == pair][:3],
                "critical" if count > 10 else "high",
            ))

        if low_conf:
            patterns.append(ErrorPattern(
                "Low confidence correct predictions",
                len(low_conf),
                [p.image_id for p in low_conf[:3]],
                "medium",
            ))

        self.error_patterns = patterns
        return patterns

    def generate_report(self):
        """สร้าง Post-mortem Report"""
        total = len(self.predictions)
        correct = sum(1 for p in self.predictions if p.is_correct)
        accuracy = correct / total * 100 if total > 0 else 0

        errors = [p for p in self.predictions if not p.is_correct]
        avg_conf_correct = np.mean([p.confidence for p in self.predictions if p.is_correct]) if correct > 0 else 0
        avg_conf_error = np.mean([p.confidence for p in errors]) if errors else 0

        print(f"\n{'='*60}")
        print(f"ML Post-mortem Report: {self.model_name} v{self.version}")
        print(f"{'='*60}")
        print(f"  Date: {datetime.now().strftime('%Y-%m-%d')}")
        print(f"  Total Predictions: {total}")
        print(f"  Accuracy: {accuracy:.1f}%")
        print(f"  Errors: {len(errors)}")
        print(f"  Avg Confidence (correct): {avg_conf_correct:.3f}")
        print(f"  Avg Confidence (error): {avg_conf_error:.3f}")

        # Error Patterns
        if self.error_patterns:
            print(f"\n  Error Patterns:")
            for pattern in self.error_patterns:
                print(f"    [{pattern.severity:>8}] {pattern.pattern} "
                      f"(count: {pattern.count})")

        # Recommendations
        print(f"\n  Recommendations:")
        recommendations = [
            "เพิ่ม Training Data สำหรับ Classes ที่ผิดบ่อย",
            "ปรับ Augmentation สำหรับ Edge Cases",
            "เพิ่ม Hard Negative Mining",
            "ลอง Larger Model (yolov8s -> yolov8m)",
            "ตรวจสอบ Label Quality ใน Training Data",
        ]
        for i, rec in enumerate(recommendations, 1):
            print(f"    {i}. {rec}")

    def action_items(self):
        """Action Items จาก Post-mortem"""
        items = [
            {"action": "Review misclassified images", "owner": "ML Engineer",
             "priority": "high", "deadline": "1 week"},
            {"action": "Add edge case data to training set", "owner": "Data Team",
             "priority": "high", "deadline": "2 weeks"},
            {"action": "Retrain with augmented data", "owner": "ML Engineer",
             "priority": "medium", "deadline": "3 weeks"},
            {"action": "Update monitoring dashboards", "owner": "MLOps",
             "priority": "medium", "deadline": "1 week"},
            {"action": "Document findings in wiki", "owner": "ML Lead",
             "priority": "low", "deadline": "1 week"},
        ]

        print(f"\n  Action Items:")
        for item in items:
            print(f"    [{item['priority']:>6}] {item['action']}")
            print(f"            Owner: {item['owner']} | Due: {item['deadline']}")

# ตัวอย่าง
pm = MLPostMortem("YOLOv8-custom", "1.2.0")

np.random.seed(42)
classes = ["car", "person", "bicycle", "truck"]
for i in range(200):
    true_cls = np.random.choice(classes)
    is_correct = np.random.random() > 0.15  # 85% accuracy
    pred_cls = true_cls if is_correct else np.random.choice([c for c in classes if c != true_cls])
    conf = np.random.uniform(0.7, 0.99) if is_correct else np.random.uniform(0.3, 0.8)

    pm.add_prediction(Prediction(
        f"img_{i:04d}", true_cls, pred_cls, conf,
        np.random.uniform(0.5, 0.95), is_correct))

pm.analyze_errors()
pm.generate_report()
pm.action_items()

Production Deployment

# === YOLO Production Deployment ===
# pip install ultralytics fastapi uvicorn pillow

from dataclasses import dataclass
from typing import List, Dict
import time

@dataclass
class DetectionResult:
    class_name: str
    confidence: float
    bbox: List[float]  # [x1, y1, x2, y2]

class YOLOProductionServer:
    """YOLO Production Server"""

    def __init__(self, model_path="yolov8n.pt"):
        self.model_path = model_path
        self.request_count = 0
        self.total_latency = 0
        self.errors = 0

    def predict(self, image_path):
        """Run Prediction"""
        start = time.time()
        self.request_count += 1

        # model = YOLO(self.model_path)
        # results = model(image_path, conf=0.25, iou=0.45)

        # Simulated results
        detections = [
            DetectionResult("car", 0.92, [100, 200, 400, 350]),
            DetectionResult("person", 0.87, [450, 150, 550, 400]),
        ]

        latency = (time.time() - start) * 1000
        self.total_latency += latency

        return detections, latency

    def health_check(self):
        """Health Check"""
        avg_latency = self.total_latency / self.request_count if self.request_count > 0 else 0
        error_rate = self.errors / self.request_count * 100 if self.request_count > 0 else 0

        return {
            "status": "healthy",
            "model": self.model_path,
            "requests": self.request_count,
            "avg_latency_ms": f"{avg_latency:.1f}",
            "error_rate": f"{error_rate:.1f}%",
        }

# FastAPI Server
# from fastapi import FastAPI, UploadFile
# app = FastAPI()
# server = YOLOProductionServer("best.pt")
#
# @app.post("/detect")
# async def detect(file: UploadFile):
#     contents = await file.read()
#     with open("/tmp/upload.jpg", "wb") as f:
#         f.write(contents)
#     detections, latency = server.predict("/tmp/upload.jpg")
#     return {
#         "detections": [
#             {"class": d.class_name, "confidence": d.confidence, "bbox": d.bbox}
#             for d in detections
#         ],
#         "latency_ms": latency,
#     }
#
# @app.get("/health")
# async def health():
#     return server.health_check()

# Docker Deployment
# FROM python:3.11-slim
# WORKDIR /app
# COPY requirements.txt .
# RUN pip install -r requirements.txt
# COPY . .
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

server = YOLOProductionServer()
detections, latency = server.predict("test.jpg")
print(f"\nDetections: {len(detections)}")
for d in detections:
    print(f"  {d.class_name}: {d.confidence:.2f}")
print(f"Latency: {latency:.1f}ms")
print(f"Health: {server.health_check()}")

Best Practices

YOLO คืออะไร

Real-time Object Detection Algorithm ตรวจจับวัตถุเร็วมาก Single Pass YOLOv8 Ultralytics ล่าสุด Detection Segmentation Classification Pose Estimation

Post-mortem Analysis คืออะไร

วิเคราะห์หลังเกิด Incident หา Root Cause ML Model วิเคราะห์ทำนายผิดเพราะอะไร False Positives Negatives Edge Cases ปรับปรุง Training Data Model

YOLOv8 ต่างจาก YOLOv5 อย่างไร

Architecture ใหม่แม่นยำเร็วกว่า Tasks มากกว่า Detection Segmentation Classification Pose OBB API ง่าย CLI Python Auto-augmentation Export ONNX TensorRT CoreML

วิธี Train Custom YOLO Model ทำอย่างไร

เตรียม Dataset YOLO Format images labels Label Roboflow LabelImg data.yaml Classes yolo train epochs=100 ประเมิน mAP Precision Recall Confusion Matrix Error Patterns

สรุป

YOLO เป็น Real-time Object Detection ที่เร็วและแม่นยำ YOLOv8 รองรับหลาย Tasks Training Custom Model ด้วย data.yaml Post-mortem Analysis วิเคราะห์ Errors หา Root Cause Production Deploy ด้วย FastAPI Export ONNX TensorRT Monitor mAP Latency

📖 บทความที่เกี่ยวข้อง

Computer Vision YOLO Container Orchestrationอ่านบทความ → Computer Vision YOLO Micro-segmentationอ่านบทความ → Computer Vision YOLO Architecture Design Patternอ่านบทความ → Computer Vision YOLO Career Development ITอ่านบทความ → Computer Vision YOLO Consensus Algorithmอ่านบทความ →

📚 ดูบทความทั้งหมด →