Ultralytics YOLO27: Bekleme listesine katıl.
Get Started
Bilgisayarlı Görünün Temelleri·Veri Kümeleri ve Etiketler·Ders 7/10
Dersbaşlangıç düzeyi

Etiketleme Kalitesi

Bir YOLO etiketinin neler içerdiğini öğren, bozuk satırlar için etiket dosyalarını lint işleminden geçir ve bir yönergeyle ölçümlü bir kalibrasyon turu kullanarak etiketleyicilerin tutarlı çalışmasını sağla.

Tutarsız etiketlerle eğitilen model tutarsızlığı öğrenir. Tek ve açık bir kurala göre çizilmiş elli bin kutu, kişiye özel yirmi farklı yoruma göre çizilmiş yarım milyon kutudan daha iyidir; etiketleri yeniden oluşturmak neredeyse her zaman daha büyük bir modelden ucuza gelir. Bu derste bir etiket linter'ı, tek sayfalık bir yönerge ve etiketleyiciler arası uyum için bir ölçüm elde edeceksin.

Sonuç

Bir veri kümesinin etiket dosyalarını lint işleminden geçir, bir sınıf için tek sayfalık bir yönerge yaz ve iki etiketleyici arasındaki uyumu ölç.

Hızlı Başlangıç
Nasıl ilerleyeceğini zaten biliyorsan, işte kısa sürüm.
  1. Görevine uygun etiket satırını tanı: kutu, çokgen, kilit noktaları veya köşeler.

  2. Her etiket dosyasını lint işleminden geçir: sütun sayısı, sınıf kimlikleri, 0–1 arası koordinatlar, yinelenen kutular.

  3. Her kural için örnek bir görüntü ve etiketlenmemesi gerekenlerin listesi bulunan tek sayfalık bir yönerge.

  4. Önce kalibrasyon turu: herkes aynı 50 görüntüyü etiketler; yalnızca uyum yeterli düzeye ulaştığında ölçeği büyüt.

  5. İnceleyenler bir gerekçe belirterek reddeder; sessizce düzeltme yapmaz.

Uygulamalı

Etiket aslında nedir?#

YOLO biçiminde her görüntünün, nesne başına bir satır içeren eşleşen bir .txt dosyası vardır. Koordinatlar görüntünün genişlik ve yüksekliğine göre 0–1 aralığında normalize edilir; böylece etiketler yeniden boyutlandırma sonrasında da geçerliliğini korur. Satır düzeni göreve bağlıdır:

GörevBir etiketNotlar
Algılamaclass x_center y_center width heightKutu merkezi ve boyutu
Örnek segmentasyonuclass x1 y1 x2 y2 ... xn ynÇokgen dış çizgisi
Pozclass x y w h px1 py1 v1 ... pxn pyn vnKutu, ardından isteğe bağlı görünürlük bilgisiyle kilit noktaları
OBBclass x1 y1 x2 y2 x3 y3 x4 y4Döndürülmüş kutunun dört köşesi
SınıflandırmaEtiket dosyası yokGörüntüler her sınıf için bir klasöre ayrılmış
Anlamsal segmentasyonGörüntü başına bir PNG maskesiHer pikselin değeri bir sınıf indeksidir
Derinlik tahminiGörüntü başına bir derinlik PNG'si veya NPY dosyasıHer pikselin değeri bir mesafedir

Sınıf indeksleri 0'dan başlar ve veri kümesi YAML dosyasındaki adlarla eşleşir. Nesne içermeyen bir görüntünün etiket dosyasına ihtiyacı yoktur; arka plan görüntüleri bu şekilde çalışır. Nesne algılama biçimi, anlamsal ve derinlik veri kümesi sayfalarında çalışan örnekler bulunur.

Etiket dosyalarını lint işleminden geçir#

Bozuk satırlar sessizce sorun çıkarır: 1'den büyük bir koordinat, YAML dosyasında tanımlanmamış bir sınıf kimliği veya aynı nesnenin iki kez kutulanması, modelin öğrenmeye çalıştığı gürültüye dönüşür. Kısa bir linter bunları eğitimden önce yakalar:

from itertools import combinations
from pathlib import Path

from ultralytics.data.utils import check_det_dataset

def iou(a, b):
    """IoU of two normalized (x_center, y_center, width, height) boxes."""
    ax1, ay1, ax2, ay2 = a[0] - a[2] / 2, a[1] - a[3] / 2, a[0] + a[2] / 2, a[1] + a[3] / 2
    bx1, by1, bx2, by2 = b[0] - b[2] / 2, b[1] - b[3] / 2, b[0] + b[2] / 2, b[1] + b[3] / 2
    inter = max(0, min(ax2, bx2) - max(ax1, bx1)) * max(0, min(ay2, by2) - max(ay1, by1))
    return inter / (a[2] * a[3] + b[2] * b[3] - inter)

def check_labels(text, names):
    """Return a list of problems in one YOLO detection label file."""
    problems, boxes = [], []
    for i, row in enumerate(text.split("\n"), 1):
        values = row.split()
        if not values:
            continue
        if len(values) != 5:
            problems.append(f"row {i}: {len(values)} values, expected 5")
        elif int(values[0]) not in names:
            problems.append(f"row {i}: unknown class {values[0]}")
        elif not all(0 <= float(v) <= 1 for v in values[1:]):
            problems.append(f"row {i}: coordinates outside 0-1")
        else:
            boxes.append((i, int(values[0]), [float(v) for v in values[1:]]))
    for (i, ca, a), (j, cb, b) in combinations(boxes, 2):
        if ca == cb and iou(a, b) > 0.8:
            problems.append(f"row {j}: duplicate of row {i} (IoU {iou(a, b):.2f})")
    return problems

broken = "0 0.50 0.50 0.20 0.30\n0 0.51 0.50 0.20 0.30\n3 0.40 0.40 0.10 0.10\n0 1.20 0.50 0.10 0.10\n0 0.50 0.50 0.10"
print("\n".join(check_labels(broken, {0: "pill"})))

data = check_det_dataset("medical-pills.yaml")
files = sorted(Path(data["path"], "labels").rglob("*.txt"))
found = sum(len(check_labels(f.read_text(), data["names"])) for f in files)
print(f"medical-pills: {found} problems in {len(files)} label files")
row 3: unknown class 3
row 4: coordinates outside 0-1
row 5: 4 values, expected 5
row 2: duplicate of row 1 (IoU 0.90)
medical-pills: 0 problems in 115 label files

Elle oluşturulan örnek, linter'ın yakaladığı her hatayı gösterir; gerçek veri kümesinde ise sorun yoktur. Her etiketleme grubundan sonra ve her eğitim çalıştırmasından önce linter'ı çalıştır; işlem saniyeler sürer.

Etiketler neden kayar?#

Tam ekran Ultralytics Platform etiketleme düzenleyicisi: depo robotları üzerindeki karton koliler çokgenlerle çevrelenmiş ve yanlarında sınıf listesi açık

Bu düzenleyicideki sınıf paneline bak: 14 koli çokgeni Grapes altında kaydedilmiş, listede daha aşağıda Box sınıfı yer alıyor; ayrıca plane ve Plane iki ayrı sınıf olarak mevcut. Her satır geçerli olduğundan linter bu sorunların hiçbirini yakalayamaz; ancak etiketleri yönergeyle karşılaştıran bir inceleyen ikisini de saniyeler içinde fark eder. Etiket hatalarının çoğu böyledir: dosyalar geçerlidir, kararlar yanlıştır.

Etiketleyiciler dikkatsiz oldukları için nadiren kötü etiketleme yapar. Kurallar belirsiz olduğu ve herkes makul ama farklı bir tahminde bulunduğu için tutarsız etiketleme yaparlar:

  • Kutu nerede bitiyor? Gölgede mi, taşınan çantada mı, forklift çatallarındaki yükte mi?
  • Kırpılma. Kadrajın yarısının dışında kalan bir kişi hâlâ person olarak etiketlenir mi? Görünen kısmı ne kadar olmalı?
  • Örtülme. Yalnızca bir tekerleği görünen otomobil etiketlenir mi, atlanır mı?
  • Sınıf sınırları. Bir pikap car mı, yoksa truck mi? Bir scooter bicycle mi, yoksa other mü?
  • Etiketlenmemesi gereken durumlar. Nesneyi gösteren yansımalar, posterler ve ekranlar.

Herkes aynı tercihi yaptığı sürece her seçim uygundur.

Tek sayfalık bir yönerge#

Tek sayfaya sığar, her kural için örnek bir görüntü içerir ve önce sınır durumlarını açıklar:

## Class: forklift

Include:
- Forklifts with at least 30% of the body visible, moving or parked, any size or color.

Do not label:
- Pallet jacks (no overhead mast) → class `pallet_jack`.
- Reflections in glass or polished floors, and forklifts on posters or screens.

Box rules:
- Include the mast and the full visible body.
- Exclude the load (pallets, boxes) — those have their own classes.
- For partly occluded forklifts, box the visible part only.

Kalibrasyon turunda uyumu ölç#

Bir etiketleyiciden yirmi etiketleyiciye geçmeden önce herkes aynı 50 görüntüyü etiketler ve sen sonuçları karşılaştırırsın:

Uyum, her iki etiketleyicinin de aynı sınıfla çizdiği ve IoU değeri en az 0.5 olan nesnelerin oranıdır; bu, değerlendiriciler arası güvenilirliğin pratik karşılığıdır:

def iou(a, b):
    """IoU of two (x1, y1, x2, y2) pixel boxes."""
    w = max(0, min(a[2], b[2]) - max(a[0], b[0]))
    h = max(0, min(a[3], b[3]) - max(a[1], b[1]))
    inter = w * h
    return inter / ((a[2] - a[0]) * (a[3] - a[1]) + (b[2] - b[0]) * (b[3] - b[1]) - inter)

def agreement(boxes_a, boxes_b, threshold=0.5):
    """Share of objects both annotators drew with the same class and IoU >= threshold."""
    unmatched, matched = list(boxes_b), 0
    for cls_a, box_a in boxes_a:
        best = max(unmatched, key=lambda b: iou(box_a, b[1]) if b[0] == cls_a else -1, default=None)
        if best and best[0] == cls_a and iou(box_a, best[1]) >= threshold:
            unmatched.remove(best)
            matched += 1
    return matched / max(len(boxes_a), len(boxes_b))

# Two annotators label the same calibration image
alice = [("forklift", (100, 200, 400, 600)), ("person", (450, 220, 520, 480)), ("person", (600, 230, 660, 470))]
bob = [("forklift", (100, 120, 400, 600)), ("person", (452, 218, 522, 478)), ("pallet_jack", (600, 230, 660, 470))]
print(f"agreement: {agreement(alice, bob):.0%}")
agreement: 67%

Bu %67'nin içinde iki tür anlaşmazlık gizli. Bob'un forklift kutusu 80 piksel daha yukarıdan başlıyor; direğin ucunu da dahil etmiş, ancak yine de IoU 0.83 olduğundan eşleşme sayılıyor. Ürünün yüksekliği ölçmesi gerekiyorsa kutu kuralını daralt. Üçüncü nesnede gerçek bir anlaşmazlık var: Alice person, Bob ise pallet_jack diyor. Bunun için daha açık bir kural ve örnek bir görüntü gerekiyor; ardından bir tur daha yap. 50 kalibrasyon görüntüsünü sakla: bunlar her yeni etiketleyici için işe alıştırma testine dönüşür.

İncelemeciler sessizce düzeltmez, reddeder

Etiketleri sessizce düzelten bir incelemeci geri bildirim döngüsünü ortadan kaldırır ve etiketleyiciler neyi yanlış yaptıklarını asla öğrenemez. Bir gerekçeyle reddet ve düzeltmeyi etiketleyiciye bırak. İlk yüz görüntü için daha yavaş, sonrasında çok daha hızlıdır.

Neleri izleyeceksin?#

ÖlçütSana ne anlatır?
Üretkenlik (saat başına nesne)Kapasite ve maliyet
Ret oranıKalitenin düşüp düşmediği
Ortak bir örtüşme kümesindeki uyumEtiketleyicilerin hâlâ aynı kuralları uygulayıp uygulamadığı

Uyum düştüğünde bir şey değişmiştir: yeni bir etiketleyici, yeni bir kamera, belirsiz bir etiketleme grubu veya yorgunluk. Model daha sonra belirli bir koşulda başarısız olduğunda, tam da o görüntüleri etiketleme sürecine geri gönder; aktif öğrenmenin otomatikleştirdiği döngü budur ve gerçek dünya doğruluk kazanımlarının çoğu bu şekilde elde edilir. Ultralytics Platform'daki veri kümelerinde hatalara göz atıp bunları filtrele; bu süreci büyük ölçekte yürütmek için Veri Kümesi Kalite Kontrolü ve Etiketleme için En İyi Uygulamalar bölümlerine bak.

Dene

Linter'ı veri kümenin etiket klasöründe çalıştır. Ardından en belirsiz sınıfın için, her kuralı örnekleyen bir görüntü ve etiketlenmemesi gerekenlerin listesini içeren tek sayfalık bir yönerge yaz. Hiçbir açıklama yapmadan yönergeyi ve etiketlenmemiş 10 görüntüyü bir ekip arkadaşına ver; aynı görüntüleri kendin de etiketle ve betiği kullanarak uyumu hesapla. Puanı ve anlaşmazlıklar nedeniyle değiştirdiğin her kuralı kaydet.

Tamamlanma ölçütü
Aşağıdakilerin tümü doğru olduğunda dersi tamamlamış olursun.
  • Linter etiketlerinde sıfır sorun raporluyor veya bulduğu her sorunu düzelttin.

  • Her kural için örnek ve etiketlenmemesi gerekenlerin listesini içeren tek sayfalık bir yönergen var.

  • İki etiketleyici için bir uyum puanın ve bu puan nedeniyle değiştirdiğin kuralların listesi var.

Çözümü göster

10 görüntüdeki kalibrasyon turundan sonra yazılmış, medical-pills pill sınıfı için bir yönerge:

## Class: pill

Include:
- Every tablet inside a blister cavity, including half-visible ones at the image edge.
- Tablets seen through clear plastic, even when glare covers part of them.

Do not label:
- Empty cavities, torn foil, or tablets outside the pack.
- Reflections of tablets in the foil.

Box rules:
- Box the tablet itself, not the plastic bubble around it.
- If two tablets touch, draw two boxes.

Uyum puanı şöyle yorumlanır: İlk turun puanının %82 olduğunu varsayalım. Eşleşmeyen nesneleri nedenlerine göre sırala. Blister ambalajlarda sık görülen iki neden şunlardır: tablet yerine plastik kabarcığın çevresine kutu çizilmesi (ilk kutu kuralına bir örnek görüntü eklenerek çözülür) ve bir etiketleyicinin parlamayla kapanan tabletleri atlaması (ikinci dahil etme kuralıyla çözülür). 10 yeni görüntüde tekrar dene; yalnızca puan %90 eşiğini geçtiğinde ölçeği büyüt.

Sırada ne var

Sıradaki adım: ölçümlerinin güvenilir kalması için etiketli verileri bölmek; işe bu veri kümesinde saklı olan bir veri sızıntısını bulmakla başlıyoruz.

İlerlemeni kaydetmek için giriş yap