Các phương pháp gán nhãn tốt nhất
Viết hướng dẫn gán nhãn, chọn công cụ, tránh mười lỗi âm thầm làm giảm độ chính xác và đo lường mức độ nhất quán giữa những người gán nhãn bằng script trước khi mở rộng quy mô.
Chất lượng nhãn giới hạn chất lượng model. Mười người gán nhãn, mỗi người hiểu "pallet" hơi khác nhau, sẽ tạo ra một dataset dạy cùng lúc cả mười cách hiểu, và dù huấn luyện bao nhiêu cũng không thể giải quyết mâu thuẫn đó. Hướng dẫn bằng văn bản, một vòng hiệu chuẩn có đo lường và danh sách ngắn các lỗi đã biết giúp nhãn nhất quán dù một người gán nhãn 500 ảnh hay cả nhóm gán nhãn 50.000 ảnh.
Thực hành
Chọn công cụ gán nhãn#
Công cụ phù hợp phụ thuộc vào tác vụ, nhóm và nơi diễn ra quá trình huấn luyện:
| Công cụ | Phù hợp nhất cho | Ghi chú |
|---|---|---|
| Ultralytics Platform | Cả bảy tác vụ YOLO: trình chỉnh sửa bounding box, polygon, semantic mask, keypoint, bounding box xoay và lớp ảnh, cùng với depth map đã tải lên; gán nhãn thông minh bằng SAM | Nhãn, biểu đồ dataset và huấn luyện tập trung tại một nơi; không cần bước xuất dữ liệu |
| CVAT | Nhóm lớn, video, quy trình đánh giá phức tạp | Tự lưu trữ hoặc trên cloud |
| Label Studio | Dự án đa phương thức (ảnh + văn bản + âm thanh) | Cấu hình linh hoạt, nhưng cần nhiều thời gian học hơn |
| Labelme | Gán nhãn polygon cho nhóm nhỏ | Ứng dụng desktop đơn giản |
| LabelImg | Tạo nhanh prototype chỉ dùng bounding box | Gọn nhẹ; repository đã được lưu trữ |
Trên Ultralytics Platform, tính năng gán nhãn thông minh SAM 2.1, SAM 3 và SAM 3.1 hoạt động với dataset detect, segment, semantic và OBB. Dù chọn công cụ nào, hãy xác nhận công cụ đó xuất được định dạng YOLO mà tác vụ của bạn cần; Chuẩn bị dataset tùy chỉnh trình bày định dạng nhãn và cách chuyển đổi.
Bảy loại nhãn#

| Loại nhãn | Nội dung cần vẽ | Tác vụ |
|---|---|---|
| Nhãn lớp | Một nhãn cho mỗi hình ảnh | Phân loại |
| Bounding box | Hình chữ nhật song song với trục cho từng đối tượng | Phát hiện |
| Polygon | Đường viền của từng đối tượng | Phân đoạn đối tượng |
| Mask dày đặc | Một class cho mỗi pixel | Phân đoạn ngữ nghĩa |
| Keypoint | Các điểm được đặt tên, chẳng hạn như khớp | Pose |
| Bounding box định hướng | Hình chữ nhật xoay cho từng đối tượng | OBB |
| Depth map | Không cần vẽ: bản đồ khoảng cách theo từng pixel từ cảm biến độ sâu, đi kèm với mỗi ảnh | Ước tính độ sâu |
Viết hướng dẫn gán nhãn trước#
Trước khi bất kỳ ai vẽ bounding box, hãy viết hướng dẫn gồm năm phần:
- Định nghĩa lớp: một đoạn cho mỗi lớp, gồm ví dụ phù hợp, các đối tượng trông tương tự nhưng không thuộc lớp đó và các trường hợp ngoại lệ.
- Quy tắc vẽ: bounding box ôm sát đối tượng nhìn thấy được; polygon bám theo đường viền nhìn thấy.
- Quy tắc về che khuất và kích thước: một ngưỡng cho đối tượng bị che khuất một phần ("gán nhãn nếu có thể nhận diện lớp") và một ngưỡng cho đối tượng rất nhỏ ("gán nhãn người cao hơn 10 pixel"), áp dụng nhất quán ở mọi nơi.
- Nhật ký trường hợp mơ hồ: ghi lại mọi câu hỏi kiểu "trường hợp này thì sao?" cùng câu trả lời đã thống nhất và ảnh chụp màn hình.
- Những gì cần bỏ qua: mọi thứ không đáng gán nhãn cho tác vụ này.
Một hoặc hai trang kèm ảnh chụp màn hình là đủ. Sau đó, hướng dẫn sẽ là cơ sở cho một vòng lặp ngắn cần thực hiện trước khi mở rộng quy mô gán nhãn:
Gán nhãn mọi đối tượng liên quan trong mọi ảnh. Xe nâng không được gán nhãn sẽ dạy model rằng đôi khi xe nâng là nền, khiến model học cách bỏ sót chúng. Dataset chỉ được gán nhãn một phần trông hệt như một dataset nhỏ hơn nhưng được gán nhãn đầy đủ cho đến khi bạn huấn luyện. Hoàn tất từng ảnh trước khi chuyển sang ảnh tiếp theo.
Mười lỗi làm giảm độ chính xác#
Những lỗi mà nhóm gán nhãn của Ultralytics thường gặp nhất, được minh họa bằng ảnh xe nâng, người và pallet (phỏng theo bộ slide của Alexis Schutzger). Hãy dùng các lỗi này làm những mục đầu tiên trong hướng dẫn của bạn.
1. Tự suy diễn hình dạng của đối tượng. Chỉ gán nhãn phần bạn nhìn thấy. Ở đây, xe nâng ở phía sau một người và một đống gỗ, nhưng bounding box lại kéo dài qua cả hai đến vị trí mà người gán nhãn tưởng tượng phần còn lại của xe tải. Chỉ đóng khung phần nhìn thấy được.

2. Bounding box không chính xác. Bounding box phải ôm sát đối tượng. Bounding box này cắt qua đèn trên khung bảo vệ phía trên; bounding box cắt mất một phần đối tượng hoặc chừa một khoảng sàn đều khiến model học sai phạm vi của đối tượng.

3. Quy ước không nhất quán giữa các đối tượng tương tự. Bounding box bên trái bao gồm càng nâng; bounding box bên phải lại không. Model nhận được hai câu trả lời cho cùng một câu hỏi, vì vậy hãy ghi rõ quy ước: có bao gồm càng nâng hay không.

4. Thiếu nhãn. Có hai người đứng cạnh xe nâng, nhưng chỉ một người được đóng khung. Người không có nhãn trở thành ví dụ dạy model rằng "người là nền".

5. Sai class. Kiểm tra class, không chỉ kiểm tra bbox. Một bbox chính xác quanh xe nâng nhưng được gán nhãn person sẽ làm sai cả hai class, thường do nhấn nhầm phím tắt.

6. Annotation rỗng hoặc thừa. Mỗi annotation cần có một object thực và một class thực. Một cú nhấp chuột lạc tạo ra bbox gần như rỗng như ở góc ảnh này; bbox được lưu mà không có class có thể được export thành None hoặc class 0. Hãy sửa hoặc xóa chúng.

7. Bbox trùng lặp. Một object, một bbox. Hai bbox chồng lên nhau trên cùng một xe nâng làm tăng số lượng instance và khiến model học cách dự đoán các bản trùng lặp.

8. Hướng dẫn không rõ ràng. Không có quy tắc bằng văn bản, người gán nhãn sẽ tự ứng biến: ở đây, một người chỉ khoanh đầu tài xế và gán class forklift. Tài xế thuộc xe nâng hay là một person riêng biệt? Hãy trả lời câu hỏi đó một lần trong tài liệu hướng dẫn.

9. Ảnh ngoại lệ. Loại bỏ những ảnh không phù hợp với môi trường triển khai. Một bức ảnh đường chân trời thành phố trong dataset xe nâng không mang lại thông tin hữu ích và làm loãng giá trị của mọi dữ liệu khác.

10. Mơ hồ do augmentation. Khi crop có thể loại bỏ đặc điểm định nghĩa một class, hai class sẽ trở nên giống hệt nhau. Cắt mất biểu tượng ở góc của lá ace cơ và lá bài đó trông giống các lá được gắn nhãn unknown. Sử dụng Augmentation Cẩn thận trình bày cách khắc phục.

Đo mức độ nhất quán, đừng phỏng đoán#
Một vòng hiệu chuẩn cung cấp cho hai người gán nhãn cùng một bộ ảnh rồi so sánh nhãn của họ theo từng object. Hai nhãn được xem là nhất quán khi có cùng class và độ chồng lấp đạt ít nhất 0.5 theo IoU. Script này tính điểm trên các ảnh val của COCO8. Để có thể chạy mà không cần người thứ hai, một model đã huấn luyện trước đóng vai người gán nhãn B; với một nhóm thực tế, hãy đọc bbox của B từ các file nhãn của họ:
from pathlib import Path
import torch
from ultralytics import YOLO
from ultralytics.data.utils import check_det_dataset, img2label_paths
from ultralytics.utils.metrics import box_iou
from ultralytics.utils.ops import xywh2xyxy
data = check_det_dataset("coco8.yaml")
model = YOLO("yolo26n.pt") # stands in for a second annotator; compare two label folders the same way
names = data["names"]
matched = total = 0
for image in sorted(Path(data["val"]).glob("*.jpg")):
rows = [r.split() for r in Path(img2label_paths([str(image)])[0]).read_text().splitlines() if r.strip()]
a_cls = torch.tensor([int(r[0]) for r in rows]) # annotator A: the dataset labels
a_box = xywh2xyxy(torch.tensor([[float(v) for v in r[1:]] for r in rows]))
b = model(image, conf=0.5, verbose=False)[0].boxes # annotator B: confident model proposals
iou = box_iou(a_box, b.xyxyn)
used = set()
for i in range(len(rows)): # pair each A object with the best unused same-class B box at IoU >= 0.5
ok = [j for j in range(len(b)) if j not in used and b.cls[j] == a_cls[i] and iou[i, j] >= 0.5]
if ok:
used.add(max(ok, key=lambda j: iou[i, j]))
else:
print(f"{image.name}: {names[int(a_cls[i])]} labeled by A only")
for j in set(range(len(b))) - used:
print(f"{image.name}: {names[int(b.cls[j])]} labeled by B only")
matched += len(used)
total += len(rows) + len(b) - len(used)
print(f"agreement: {matched}/{total} objects = {matched / total:.0%}")000000000049.jpg: person labeled by A only
000000000049.jpg: person labeled by A only
000000000049.jpg: potted plant labeled by A only
000000000049.jpg: person labeled by A only
000000000049.jpg: person labeled by A only
000000000049.jpg: person labeled by A only
000000000061.jpg: person labeled by A only
000000000061.jpg: elephant labeled by A only
000000000061.jpg: person labeled by A only
agreement: 8/17 objects = 47%Cách đọc kết quả:
- Điểm số là số object được ghép khớp chia cho tổng số object mà cả hai người gán nhãn đã vẽ: 8 trên 17.
- Các điểm bất đồng tập trung thành cụm. Cả chín trường hợp đều nằm trong hai ảnh, và phần lớn là người chiếm ít hơn nhiều so với 1% khung hình. Đây không phải chín lỗi ngẫu nhiên; chúng xuất phát từ một quy tắc còn thiếu: có gán nhãn người ở xa không?
- Cách khắc phục là bổ sung một mục vào hướng dẫn, chẳng hạn: "gán nhãn mọi người cao ít nhất 10 pixel ở độ phân giải 640 pixel". Cả hai người gán nhãn gán nhãn lại hai ảnh đó rồi đo lại điểm số.
Quy tắc ra quyết định: chỉ mở rộng quy mô gán nhãn khi mức độ nhất quán đạt 90%. Nếu thấp hơn, mỗi người gán nhãn mới sẽ làm mức độ không nhất quán tăng lên.
Dùng gán nhãn thông minh để tăng tốc#
Gán nhãn thông minh cho phép model YOLO hoặc SAM đề xuất nhãn để một người chấp nhận hoặc chỉnh sửa, nhờ đó năng suất có thể tăng gấp nhiều lần. Khởi động theo từng vòng: huấn luyện trên một batch đã được rà soát, dùng model đó đề xuất batch tiếp theo, rà soát rồi huấn luyện lại. Đây là vòng lặp học chủ động, và Gán nhãn Thông minh và Gán nhãn theo Batch hướng dẫn quy trình này trên Ultralytics Platform.
Model bỏ sót người nhỏ sẽ không đề xuất hộp cho người nhỏ, và người đánh giá nhấp "chấp nhận tất cả" sẽ không bao giờ bổ sung họ. Model tiếp theo, được huấn luyện trên những nhãn đó, sẽ bỏ sót họ với độ tin cậy cao hơn. Hãy xem xét mọi ảnh, đồng thời bổ sung những gì model bỏ sót và sửa những gì model đã vẽ.
Kiểm tra bằng mắt#
Mỗi lần chạy huấn luyện Ultralytics ghi labels.jpg và train_batch*.jpg vào thư mục run. File đầu tiên vẽ biểu đồ số lượng class, vị trí và kích thước bbox; các file còn lại hiển thị ảnh huấn luyện thực tế cùng nhãn được vẽ chồng lên. Hãy mở chúng trước khi epoch đầu tiên kết thúc. Mắt người phát hiện được những gì metric không bao giờ thấy: bbox vẽ quanh bóng, ID class bị hoán đổi và polygon chưa khép kín.
Hiển thị lời giải
Các điểm bất đồng trên COCO8 được chuyển thành những mục trong tài liệu hướng dẫn như sau:
| Điểm bất đồng | Quy tắc bổ sung vào hướng dẫn |
|---|---|
Người ở xa trong 000000000049.jpg chỉ được A gán nhãn | Gán nhãn mọi người cao ít nhất 10 pixel ở độ phân giải 640 pixel; bỏ qua người thấp hơn trong mọi ảnh. |
| Chậu cây ở mép khung hình chỉ được A gán nhãn | Gán nhãn object bị mép khung hình cắt nếu nhìn thấy ít nhất một nửa object. |
Voi bị một con voi khác che khuất một phần trong 000000000061.jpg | Gán nhãn động vật bị che khuất nếu nhìn thấy đầu hoặc một nửa thân; chỉ vẽ bbox quanh phần nhìn thấy. |
Để so sánh hai người thay vì một người với một model, hãy đọc các dòng của người gán nhãn B từ thư mục nhãn thứ hai, đúng như cách script đọc dữ liệu của A (Path("labels_b", image.stem + ".txt")), tạo b_cls và b_box từ dữ liệu đó bằng cùng hai dòng lệnh, rồi dùng chúng ở mọi nơi script đọc b.cls và b.xyxyn. Chạy lại sau khi gán nhãn lại; vòng này hoàn tất khi điểm số vượt 90%.