Ultralytics YOLO27: Bekleme listesine katıl.
Get Started
Bilgisayarlı Görünün Temelleri·Ölçümleri Oku·Ders 8/10
Dersbaşlangıç düzeyi

Gerçeği Yansıtan Bölmeler

Eğitim ve doğrulama kümelerine sızan neredeyse yinelenen görüntüleri bul ve dağıtım sırasında yeni olacak birime göre bölme yap.

Bir model doğrulamada %95, üretimde %60 puan alıyorsa bölme genellikle yanıltıcıdır. Neredeyse aynı görüntüler (videodan ardışık kareler veya aynı gün aynı kamerayla çekilen görüntüler) her iki kümeye de düşmüştür; bu yüzden doğrulama, genelleme yerine ezberlemeyi sınamıştır. Gerçek bir veri kümesinde tam da bu sızıntıyı bulacak, ardından grup bölmesiyle düzelteceksin.

Sonuç

Kümeler arasındaki neredeyse yinelenen görüntüleri tespit et, grup anahtarına göre böl ve hiçbir grubun birden fazla kümede yer almadığını doğrula.

Hızlı Başlangıç
Nasıl ilerleyeceğini zaten biliyorsan, işte kısa sürüm.
  1. Eğitim ağırlıkları uyarlar, doğrulama kararları yönlendirir, test ise sonucu bir kez bildirir.

  2. Doğrulama puanına güvenmeden önce kümeler arasında neredeyse aynı görüntüler olup olmadığını kontrol et.

  3. Grup anahtarını bul: klip, kamera, gün veya denek.

  4. Görüntüleri değil grupları karıştır; ardından her sınıfın her kümede bulunduğunu kontrol et.

  5. Test kümesini sabitle ve tamamlanan her deneyde yalnızca bir kez kullan.

Uygulamalı

Üç bölme, üç görev#

BölmeKim öğreniyor?Ne zaman incelersin?
EğitimModel: ağırlıklar burada öğrenilirHer epoch'ta
DoğrulamaSen: hiperparametreler, epoch sayısı, model boyutu, eşiklerHer deneyden sonra
TestHiç kimse: yalnızca nihai sonucu bildirirTüm kararlar verildikten sonra, bir kez

Bir veri bölümüne bakarak verdiğin her karar, o bölümdeki bilgilerin bir kısmını modele sızdırır. Doğrulama kümesinin görevi budur. Test kümesinde ayar yaparsan test sonucu artık dürüst bir tahmin olmaktan çıkar; kendi seçimlerine aşırı uyum sağlamış olursun. Ultralytics'te model.val(split="test"), veri kümesi YAML dosyandaki test bölümünü puanlar.

Gerçek bir veri kümesindeki sızıntıyı bul#

Tıbbi hap görselleri Frame_0.jpg, Frame_4.jpg, Frame_8.jpg şeklinde adlandırılmış; bunlar bir videodan alınan kareler. Bu bir uyarı işaretidir: Birbirine komşu kareler neredeyse aynıdır ve rastgele bir bölme bunları her iki tarafa da yerleştirir. Her doğrulama görselinin küçük gri tonlamalı parmak izini her eğitim görselininkiyle karşılaştırarak bunu kontrol et:

from pathlib import Path

import numpy as np
from PIL import Image
from ultralytics.data.utils import check_det_dataset

data = check_det_dataset("medical-pills.yaml")

def thumbnail(path):
    """A 32x18 grayscale fingerprint: enough to spot near-identical frames."""
    return np.asarray(Image.open(path).convert("L").resize((32, 18)), dtype=float)

train = {p.name: thumbnail(p) for p in sorted(Path(data["train"]).glob("*.jpg"))}
pairs = []
for p in sorted(Path(data["val"]).glob("*.jpg")):
    v = thumbnail(p)
    name, diff = min(((n, np.abs(v - t).mean()) for n, t in train.items()), key=lambda x: x[1])
    pairs.append((diff, p.name, name))

pairs.sort()
print(f"{sum(d < 5 for d, _, _ in pairs)} of {len(pairs)} val images have a near-twin in train (difference < 5)")
for diff, val_name, train_name in pairs[:3]:
    print(f"  {val_name} ~ {train_name}  difference {diff:.1f}")
17 of 23 val images have a near-twin in train (difference < 5)
  Frame_344.jpg ~ Frame_56.jpg  difference 0.3
  Frame_28.jpg ~ Frame_312.jpg  difference 0.5
  Frame_24.jpg ~ Frame_308.jpg  difference 1.8

0–255 ölçeğinde 0,3'lük fark, iki görselin pratikte aynı görüntü olduğu anlamına gelir. val/Frame_24.jpg ve train/Frame_308.jpg dosyalarını yan yana aç; aynı açıdan çekilmiş aynı blister ambalajları göreceksin. 23 doğrulama görselinden 17'sinin eğitim kümesinde bir ikizi var. Dolayısıyla buradaki doğrulama puanı, çoğunlukla modelin daha önce gördüğü görselleri ne kadar iyi hatırladığını ölçüyor. Hızlı bir demo veri kümesi için bu sorun değil; ancak üretime asla böyle çıkmamalısın.

Tıbbi haplar için Ultralytics Platform Bölümleri Yeniden Dağıt iletişim kutusu; eğitim %80, doğrulama %20 ve test %0 olarak ayarlanmış

Aynı tuzak her araçta karşına çıkabilir. Bu iletişim kutusunun açıklaması, her görseli rastgele yeniden atadığını söylüyor; bu nedenle görsellerin bağımsız fotoğraflar olduğu durumlarda idealdir, ancak görseller video kareleriyse sızıntıya yol açar. Önce yinelenen görselleri kontrol et; kimsenin ayar yapmadığı bir nihai sonuç istiyorsan test payını %0'ın üzerinde tut.

Gruplara göre böl#

Kural: bölümler, dağıtım sırasında yeni olacak birime göre birbirinden bağımsız olmalı.

VeriBölme ölçütü
VideoKlip veya kayıt oturumu
Sabit kamera filosuKamera veya konum
Zaman içinde değişen sahnelerGün veya hafta
Tıbbi, spor veya kişi verileriHasta, sporcu veya denek
Ardışık fotoğraf çekimleriÇekim olayı

Dosya adları çoğu zaman grup anahtarını içerir. Bu örnek, 6 kameradan alınmış 900 görseli kullanarak iki stratejiyi karşılaştırıyor:

import random
from collections import defaultdict

# File names carry the unit that must never straddle splits: camera_day_frame.jpg
images = [f"cam{c:02d}_day{d}_{f:04d}.jpg" for c in range(1, 7) for d in range(1, 4) for f in range(50)]

# WRONG: shuffle individual frames, so near-identical neighbors land in both splits
random.seed(0)
shuffled = random.sample(images, len(images))
train, val = shuffled[: int(0.8 * len(images))], shuffled[int(0.8 * len(images)) :]
shared = {i.split("_")[0] for i in train} & {i.split("_")[0] for i in val}
print(f"per-image split: {len(shared)} of 6 cameras appear in both train and val")

# RIGHT: shuffle whole cameras, then expand them back into images
groups = defaultdict(list)
for image in images:
    groups[image.split("_")[0]].append(image)
cameras = random.sample(sorted(groups), len(groups))
train = [i for cam in cameras[:5] for i in groups[cam]]
val = [i for cam in cameras[5:] for i in groups[cam]]
print(f"per-camera split: train {len(train)} images, val {len(val)} images, val cameras {cameras[5:]}")
per-image split: 6 of 6 cameras appear in both train and val
per-camera split: train 750 images, val 150 images, val cameras ['cam05']

Görsel başına bölme yapıldığında doğrulama kümesi hiçbir zaman yeni bir kamera görmez. Kamera başına bölme yapıldığında ise puan, modelin daha önce hiç görmediği bir kamerada nasıl performans göstereceğini tahmin eder; ihtiyacın olan sonuç budur.

Yaygın Hatalar#

İlişkili verileri rastgele karıştırmak

Belirti: doğrulama sonuçları ilk saha testinden çok daha iyi. Çözüm: grup anahtarını bul — genellikle dosya adlarında veya çekim üst verilerinde gizlidir — bu anahtara göre böl ve doğrulamak için yakın yinelenenleri kontrol et.

Doğrulama kümesinde eksik bir sınıf

Belirti: AP değeri olmayan nadir bir sınıf veya yalnızca iki örnekten hesaplanan AP. Çözüm: grup bazında bölme yaptıktan sonra her bölmedeki sınıfları say ve her sınıf benzer oranlarda görünene kadar grupları bütün olarak değiştir. sklearn.model_selection.StratifiedGroupKFold bunu otomatikleştirir.

Test kümesinde ayar yapmak

Belirti: test puanı deneyler boyunca yükselmeye devam ediyor. Çözüm: test kümesini sabitle, üretime benzer koşullardan oluştur ve tamamlanan her deney için yalnızca bir kez raporla. Küçük veri kümelerinde tek bir bölmeyi tekrar kullanmak yerine k-katlı çapraz doğrulama ile birkaç bölmenin ortalamasını al.

Veri Kümesini Doğru Bölme, oranları ve bunların tümünü eksiksiz bir veri kümesinde uygulamayı ele alıyor.

Dene

Veri kümen (veya medical-pills) üzerinde yinelenen görsel kontrolünü çalıştır. Eğitim kümesinde yakın ikizi bulunan doğrulama görsellerinin sayısını kaydet. Ardından grup anahtarını belirle, veriyi bu anahtara göre yeniden böl ve yeni dosya listelerinde çözümdeki sızıntı kontrolünü çalıştır. Teslim etmen gerekenler, yeniden bölme öncesi ve sonrası yakın ikiz sayısı ile boş bir liste yazdıran sızıntı kontrolüdür.

Tamamlanma ölçütü
Aşağıdakilerin tümü doğru olduğunda dersi tamamlamış olursun.
  • Mevcut bölmen için yakın ikiz sayısını belirledin.

  • Grup anahtarını belirledin ve veriyi bu anahtara göre yeniden böldün.

  • Sızıntı kontrolü, yeni bölümlerin için boş bir liste yazdırıyor.

Çözümü göster

Grup anahtarını çıkaran bir işlev verildiğinde, herhangi bir dosya adı listesinde çalışan sızıntı kontrolü:

def leaked_groups(splits, key):
    """Return every group key that appears in more than one split."""
    owner, leaks = {}, set()
    for split, files in splits.items():
        for name in files:
            group = key(name)
            if owner.setdefault(group, split) != split:
                leaks.add(group)
    return sorted(leaks)

# Bu listeleri kendi dosya adlarınla değiştir; ör. [p.name for p in Path("images/train").glob("*.jpg")]
splits = {
    "train": ["cam01_day1_0001.jpg", "cam01_day1_0002.jpg", "cam02_day1_0001.jpg"],
    "val": ["cam03_day2_0001.jpg", "cam01_day1_0003.jpg"],
    "test": ["cam04_day3_0001.jpg"],
}
print(leaked_groups(splits, key=lambda name: name.split("_")[0]))  # kameraya göre grupla
['cam01']

cam01 hem train hem de val içinde görünüyor; yani bu bölmede sızıntı var. Her cam01 görselini tek bir bölüme taşı ve [] yazdırana kadar yeniden çalıştır. Tek bir videodan alınan karelerin aynı görüntüye tekrar tekrar dönüştüğü medical-pills veri kümesinde dosya adlarında temiz bir grup anahtarı yok: ya farklı ambalajları gösteren yeni doğrulama videoları kaydet ya da görselleri yinelenen görsel parmak izlerine göre kümelendirip kümelerin tamamını tek bir bölüme ata.

Sırada ne var

Dürüst bölmeler hazır olduğuna göre, şimdi bunların ürettiği metrikleri okuyacaksın.

İlerlemeni kaydetmek için giriş yap