Đọc metric phát hiện một cách trung thực
Chạy validation, đọc precision, recall, mAP50-95, AP theo từng class và ma trận nhầm lẫn cùng nhau, rồi chọn ngưỡng triển khai dựa trên mục tiêu.
Một con số duy nhất tạo cảm giác yên tâm: mAP 0.83, xong. Nhưng cùng một mAP có thể che giấu một class thất bại một nửa số lần, các bounding box luôn quá rộng hoặc một ngưỡng khiến hệ thống gửi cảnh báo mỗi phút. Bạn sẽ chạy validation thực tế và đọc từng dòng cho đến khi kết quả cho biết cần sửa gì và đặt ngưỡng ở đâu.
Thực hành
Cách chấm điểm từng dự đoán#
Validation đối chiếu từng bounding box dự đoán với ground truth. Một dự đoán là dương tính thật (TP) khi có class đúng và IoU với một bounding box ground truth chưa được ghép vượt ngưỡng; nếu không, đó là dương tính giả (FP). Mỗi đối tượng ground truth chưa được ghép là một âm tính giả (FN).
| Chỉ số | Công thức | Câu hỏi được trả lời |
|---|---|---|
| Precision | TP / (TP + FP) | Khi model vẽ một bounding box, bao nhiêu lần dự đoán đó đúng? |
| Recall | TP / (TP + FN) | Trong số các đối tượng thực tế, model đã tìm thấy bao nhiêu? |
| F1 | 2 × P × R / (P + R) | Một con số cân bằng cả hai |
Giảm ngưỡng confidence sẽ bổ sung bounding box: recall tăng và precision giảm. Đường cong precision-recall thể hiện sự đánh đổi đó qua mọi ngưỡng, còn diện tích bên dưới là độ chính xác trung bình (AP) của một class. mAP50 lấy trung bình AP trên các class tại IoU 0.5, nơi một bounding box khá lỏng vẫn được tính. mAP50-95 lấy trung bình trên mười ngưỡng IoU từ 0.5 đến 0.95, vì vậy chỉ số này ưu tiên bounding box khớp sát; đây là con số nổi bật trong các bảng model của Ultralytics.
Chạy validation#
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
metrics = model.val(data="coco8.yaml")
print(f"precision={metrics.box.mp:.3f} recall={metrics.box.mr:.3f}")
print(f"mAP50={metrics.box.map50:.3f} mAP50-95={metrics.box.map:.3f}") Class Images Instances Box(P R mAP50 mAP50-95)
all 4 17 0.551 0.962 0.943 0.669
person 3 10 0.551 0.8 0.848 0.387
dog 1 1 0.36 1 0.995 0.597
horse 1 2 0.36 1 0.995 0.696
elephant 1 2 0.656 0.969 0.828 0.545
umbrella 1 1 0.543 1 0.995 0.895
potted plant 1 1 0.833 1 0.995 0.895Đọc từ trên xuống:
- Instances 17, Images 4. COCO8 là bài kiểm tra khói. Bốn ảnh không đủ cơ sở để quyết định triển khai; hãy xem mọi con số chỉ mang tính minh họa.
- mAP50 0.943 so với mAP50-95 0.669. Phần lớn đối tượng được phát hiện, nhưng nhiều bounding box còn lỏng. Khoảng cách lớn cho thấy điểm yếu nằm ở định vị, không phải phát hiện.
- AP50-95 của
personlà 0.387. Class phổ biến nhất lại là class yếu nhất. Đó là điểm nghẽn cổ chai của bạn. - P 0.551, R 0.962. Các cột này được đọc tại mức confidence duy nhất tối đa hóa F1 trên các class — tức là ngưỡng thấp ở đây — chứ không phải tại ngưỡng 0.25 bạn dùng để dự đoán. Đừng trích dẫn chúng là "precision của model".
AP theo từng class và ngưỡng triển khai#
Lần chạy tương tự lưu AP theo từng class, cùng precision và recall tại mọi ngưỡng confidence, vì vậy bạn có thể chọn ngưỡng dựa trên mục tiêu thay vì đoán:
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
metrics = model.val(data="coco8.yaml", plots=False, verbose=False)
box = metrics.box
# Per-class AP from the same run: the average hides the weakest class
for i, c in enumerate(box.ap_class_index):
print(f"{model.names[int(c)]:13} AP50={box.ap50[i]:.3f} AP50-95={box.ap[i]:.3f}")
# Precision and recall at every confidence threshold for one class
row = list(box.ap_class_index).index(0) # class 0 = person
for conf in (0.1, 0.25, 0.5, 0.75):
j = int(conf * (len(box.px) - 1))
print(f"person @ conf {conf:.2f}: precision {box.p_curve[row, j]:.2f}, recall {box.r_curve[row, j]:.2f}") all 4 17 0.551 0.962 0.943 0.669
person AP50=0.848 AP50-95=0.387
dog AP50=0.995 AP50-95=0.597
horse AP50=0.995 AP50-95=0.696
elephant AP50=0.828 AP50-95=0.545
umbrella AP50=0.995 AP50-95=0.895
potted plant AP50=0.995 AP50-95=0.895
person @ conf 0.10: precision 0.63, recall 0.80
person @ conf 0.25: precision 1.00, recall 0.54
person @ conf 0.50: precision 1.00, recall 0.40
person @ conf 0.75: precision 1.00, recall 0.14Giờ đây, ngưỡng là một quy tắc quyết định, không phải cảm tính:
| Mục tiêu theo tiêu chí quyết định của bạn | Chọn | Trong lần chạy này |
|---|---|---|
| Tối đa 5% cảnh báo được phép sai (precision ≥ 0.95) | Ngưỡng thấp nhất đáp ứng điều kiện, để giữ recall ở mức cao nhất | 0.25: precision 1.00, recall 0.54 |
| Bỏ sót tối đa 1 trong 5 người (recall ≥ 0.80) | Ngưỡng cao nhất đáp ứng điều kiện, để giữ precision ở mức cao nhất | 0.10: precision 0.63, recall 0.80 |
Cả hai đều chưa đủ tốt ở đây: precision cao khiến bỏ sót một nửa số người, còn recall cao khiến một phần ba cảnh báo là sai. Đó là bằng chứng cho thấy cần "lặp lại", chứ không phải vấn đề về ngưỡng. Validation cũng lưu BoxPR_curve.png, BoxP_curve.png, BoxR_curve.png, BoxF1_curve.png và confusion_matrix.png trong thư mục lần chạy, để bạn có thể đọc cùng sự đánh đổi đó qua các biểu đồ; hướng dẫn về metric hiệu năng trình bày từng metric.
Cần sửa gì tiếp theo#
Ma trận nhầm lẫn cho biết class yếu bị nhầm với class nào. Nếu AP của forklift thấp và xe nâng được dự đoán là pallet_jack, thì đây là nhầm lẫn class, không phải vấn đề định vị: bổ sung các ví dụ thể hiện khác biệt trực quan, hoặc gộp các class nếu không có code phía sau nào cần tách chúng. Hướng dẫn phân tích kết quả đánh giá model trình bày quy trình này.

Phần lớn giải pháp nằm ở khung thứ nhất và thứ ba: cải thiện dữ liệu và nhãn cho class nghẽn cổ chai. Chỉ thay đổi model hoặc thiết lập huấn luyện sau khi các bước kiểm tra dữ liệu trong ba bài học trước đã đạt yêu cầu.
| Bằng chứng trên tập test cố định | Quyết định |
|---|---|
| Mọi class quan trọng với doanh nghiệp đều đạt mục tiêu precision và recall | Triển khai, và giám sát |
| Một class hoặc điều kiện không đạt mục tiêu | Lặp lại: bổ sung dữ liệu và nhãn có mục tiêu cho khoảng thiếu đó |
| Mọi class đều cách xa mục tiêu, hoặc các class có hình ảnh chồng lấn | Xem xét lại đặc tả tác vụ, các class hoặc thiết lập camera |
Các lỗi thường gặp#
mAP 0.83 có thể che giấu một lớp chỉ đạt 0.40. Nếu lớp đó mang lại giá trị kinh doanh, thì model của bạn không đạt 0.83 — đó là một model lỗi được che đậy bằng giá trị trung bình đẹp mắt.
Triệu chứng: một model "đạt điểm 0.94" nhưng tạo hộp quá lỏng để đo lường hoặc cắt ảnh. Cách khắc phục: báo cáo mAP50-95 và xem độ chênh lệch so với mAP50 như một tín hiệu về khả năng định vị.
Triệu chứng: các con số trông hoàn hảo từ vài chục ảnh, hoặc từ những ảnh gần như trùng với tập huấn luyện. Cách khắc phục: tăng tập validation lên vài trăm đối tượng cho mỗi lớp quan trọng và chạy kiểm tra ảnh gần trùng lặp từ bài học trước đó trước khi xem bất kỳ metric nào.
Hiển thị lời giải
Bản đọc kết quả: bộ đếm người trên yolo26n.pt, tập validation COCO8
Nút thắt là person, với AP50-95 0.387, so với mức tổng thể 0.669. Đây cũng là class có nhiều instance nhất (10 trên 17), nên vừa yếu nhất vừa quan trọng nhất đối với bộ đếm người. AP50 của class này là 0.848, nghĩa là model phát hiện được hầu hết mọi người nhưng tạo bounding box chưa sát — điều này ít quan trọng hơn đối với việc đếm so với các tác vụ đo vị trí hoặc kích thước.
Để đạt precision ≥ 0.95, ngưỡng thấp nhất đáp ứng yêu cầu là conf 0.25, tại đó precision là 1.00 nhưng recall chỉ là 0.54: bộ đếm sẽ bỏ sót gần một nửa số người. Để đạt recall ≥ 0.80, ta cần conf 0.10, tại đó một phần ba số lượt đếm sẽ là false positive.
Quyết định: tiếp tục lặp lại. Thu thập và gán nhãn hình ảnh người từ camera triển khai — đặc biệt là người ở xa, bị che khuất và ở sát mép khung hình — rồi validation lại trên một tập test cố định gồm vài trăm người. Bốn ảnh validation không đủ để đưa ra quyết định triển khai theo bất kỳ hướng nào.