Özel Anahtar Noktalar ve OKS Metrikleri
İnsan dışı nesneler için bir anahtar nokta şeması tasarla, veri kümesi YAML dosyasını yazıp denetle ve her noktanın ne kadar hassas yerleştirilebildiğine göre OKS sigmalarını belirle.
Poz yalnızca insanlar için değildir. Forklift çatalının uçları, kargo etiketi köşeleri, bir hayvanın burnu ve kuyruğu — sabit, adlandırılabilir noktaları olan her nesne bir poz veri kümesi olabilir. İlk gün yazdığın şema kalıcıdır: her etiket, her çevirme eşleşmesi ve her metrik bu şemaya bağlıdır; şemayı daha sonra değiştirmek her şeyi yeniden etiketlemek demektir. Bu derste, kimse binlerce görüntüyü etiketlemeden önce şema doğru şekilde oluşturuluyor ve metriğin şemayı nasıl değerlendireceği açıkça gösteriliyor.
Uygulamalı
Anahtar nokta şemasını tasarla#
İyi anahtar noktaların üç özelliği vardır: belirsiz olmama (iki etiketleyicinin noktayı aynı yere koyması), istikrarlı olma (noktanın nesnenin aldığı her pozda bulunması) ve işlevsel olma (sonraki bir hesaplamada kullanılması). Ürün sorusunun "araç hareket ederken çatallar yukarı kaldırılmış mı?" olduğu, tavana monte bir kameradan görülen forklifti ele alalım:
| İndeks | Anahtar nokta | Bulunma nedeni | Ayna eşi |
|---|---|---|---|
| 0 | left_fork_tip | çatalın uzanımı ve yönü | 1 |
| 1 | right_fork_tip | çatalın uzanımı ve yönü | 0 |
| 2 | mast_top | çatalın direğe göre yüksekliği | 2 (kendisi) |
| 3 | mast_base | şasi üzerindeki referans noktası | 3 (kendisi) |
Her nokta, hesaplamaya katkıda bulunduğu için yerini hak eder: çatal uçları yönü, direk çifti ise yüksekliği verir. Aday noktaların her birini aynı süzgeçten geçir:
Noktaları sırf "ne olur ne olmaz" diye eklemekten kaçın: her biri her örneğin etiketlenmesi için zaman harcatır ve kimsenin incelemediği noktalar metriğe yalnızca gürültü katar. Herkese açık veri kümeleri nokta sayılarındaki aralığı gösteriyor: Tiger-Pose görünürlük bilgisi olmadan 12 nokta kullanırken, Dog-Pose 24, El Anahtar Noktaları ise 21 nokta kullanıyor:


Veri kümesi YAML dosyasını yaz#
path: forklift-pose
train: images/train
val: images/val
kpt_shape: [4, 3] # 4 keypoints, each x, y, visibility
flip_idx: [1, 0, 2, 3] # fork tips swap, mast points stay
kpt_oks_sigmas: [0.05, 0.05, 0.08, 0.08] # tips are sharp, mast ends are fuzzier
names:
0: forklift
kpt_names:
0:
- left_fork_tip
- right_fork_tip
- mast_top
- mast_basekpt_names, insanlara ve araçlara ait noktaların sıralamasını her sınıf için ayrı ayrı tanımlar.flip_idxkendi tersini almalıdır: iki kez uygulandığında her indeks kendisine dönmelidir.kpt_oks_sigmasisteğe bağlıdır ve hem eğitimde anahtar nokta kaybını hem de doğrulamada OKS'yi ağırlıklandırır; varsa her anahtar nokta için bir pozitif değer içermelidir, aksi durumda çalışma birValueErrorile durur.
Ultralytics Platform'da aynı şema bir iskelet şablonudur. Yeni bir şablon mevcut bir şablondan başlayabilir (Şuradan başla…); böylece her anahtar noktayı elle yerleştirmek yerine noktaları yeniden adlandırıp azaltırsın — şema tablonun indeks sırasını koru:

Eğitimden önce etiketleri denetle#
Poz veri kümelerindeki hatalar sessizce ortaya çıkar: bir satırda tek bir anahtar noktanın eksik olması sonraki tüm değerleri kaydırır; hatalı bir dışa aktarıcıdan gelen 3 görünürlük değeri ise sıradan bir sayı gibi okunur. Bu denetleyici YAML dosyasını Ultralytics'in kendi yükleyicisiyle yükler ve her satırı doğrular. COCO8-pose üzerinde doğrudan çalışır; kendi YAML yolunu kullanmak için yolu değiştir:
from pathlib import Path
from ultralytics.data.utils import check_det_dataset
data = check_det_dataset("coco8-pose.yaml") # resolves paths, downloads if needed
k, dims = data["kpt_shape"]
flip = data.get("flip_idx", [])
assert not flip or sorted(flip) == list(range(k)), "flip_idx must list every keypoint index once"
assert all(flip[flip[i]] == i for i in range(len(flip))), "flip_idx must undo itself: pairs swap, center points stay"
expected = 5 + k * dims # class + 4 box values + k keypoints of `dims` values
bad = 0
for label in Path(data["path"], "labels").rglob("*.txt"):
for n, row in enumerate(label.read_text().splitlines(), 1):
values = row.split()
if len(values) != expected:
bad += 1
print(f"{label.name}:{n} has {len(values)} values, expected {expected}")
elif dims == 3 and not {float(v) for v in values[7::3]} <= {0, 1, 2}:
bad += 1
print(f"{label.name}:{n} has a visibility flag outside 0/1/2")
print(f"kpt_shape={data['kpt_shape']}, flip_idx ok, {bad} bad rows")kpt_shape=[17, 3], flip_idx ok, 0 bad rowsvalues[7::3], ilk görünürlük bayrağından başlar (sınıf, dört kutu değeri, ardından x y v) ve sonrasında her üçüncü değeri alır.
OKS anahtar noktayı nasıl puanlar#
Poz mAP, kutu IoU yerine Nesne Anahtar Nokta Benzerliği (OKS) kullanır. OKS, etiketlenmiş her anahtar nokta için tahmin ile etiket arasındaki piksel mesafesini nesnenin boyutuna ve ilgili anahtar noktanın sigma değerine göre ölçeklenmiş 0 ile 1 arasında bir puana dönüştürür, ardından etiketlenmiş anahtar noktaların puanlarının ortalamasını alır. Poz mAP50-95, 0.50 ile 0.95 arasındaki OKS eşiklerinde hassasiyetin ortalamasını alır; bu, kutu mAP'nin IoU eşiklerinde yaptığıyla aynıdır. Ortak mekanizmayı performans metrikleri kılavuzu açıklar.
Sigmaları anlamanın en kolay yolu onları ölçmektir. Bu betik, poz doğrulayıcısının çağırdığı kpt_iou işlevini kullanarak aynı forklift tahminini iki sigma değeriyle puanlar:
import torch
from ultralytics.utils.metrics import kpt_iou
# One labeled forklift, 4 keypoints (x, y, visibility) in pixels, inside a 200 x 120 px box
label = torch.tensor([[[40.0, 30, 2], [40, 90, 2], [170, 20, 2], [170, 100, 2]]])
area = torch.tensor([200 * 120 * 0.53]) # Ultralytics scales box area by 0.53 to approximate object area
for offset in (2, 5, 10, 20):
pred = label.clone()
pred[..., 0] += offset # every predicted keypoint lands `offset` pixels to the right
sharp = kpt_iou(label, pred, area, sigma=[0.025] * 4).item()
loose = kpt_iou(label, pred, area, sigma=[0.10] * 4).item()
print(f"{offset:2d} px off: OKS {sharp:.2f} with sigma 0.025, {loose:.2f} with sigma 0.10") 2 px off: OKS 0.94 with sigma 0.025, 1.00 with sigma 0.10
5 px off: OKS 0.67 with sigma 0.025, 0.98 with sigma 0.10
10 px off: OKS 0.21 with sigma 0.025, 0.91 with sigma 0.10
20 px off: OKS 0.00 with sigma 0.025, 0.67 with sigma 0.10200 × 120 piksellik bir forkliftte 10 piksel hatalı tahmin, 0.025 sigma ile 0.50 OKS eşiğini geçemez; 0.10 sigma ile ise 0.90'a kadar tüm eşikleri geçer. Aynı model, aynı hata, ama poz mAP çok farklı.
| Sigma | Etki | Kullanım amacı |
|---|---|---|
| Küçük (≈ 0.025–0.05) | birkaç piksellik hata bile puanı düşürür | keskin noktalar: gözler, çatal uçları, köşeler |
| Büyük (≈ 0.08–0.10) | geniş tolerans | belirsiz noktalar: kalçalar, direğin ortası |
| Varsayılan | kpt_shape: [17, 3] için COCO sigmaları; aksi durumda her nokta için 1/K | buradan başla, sonra ölç |
Sigmalar, etiketleyicilerin her noktayı ne kadar tutarlı yerleştirdiğini yansıtmalıdır. Ölç: iki kişiye aynı 50 görüntüyü etiketlet ve her anahtar noktadaki mesafeleri karşılaştır. Anlaşmazlığa düştükleri noktalar daha büyük sigmalar gerektirir; aksi takdirde metrik, insan kaynaklı hatalar nedeniyle modeli cezalandırır.
kpt_oks_sigmas değerini değiştirmek, modeli değiştirmeden poz mAP değerini değiştirir; yukarıdaki tabloda da görüldüğü gibi. İlk temel ölçümünden önce sigmaları sabitle, her sonuçla birlikte kaydet ve farklı değerlerle doğrulanmış çalıştırmaları asla karşılaştırma.
Çözümü göster
Yukarıdan görülen ve sorunun "etiket yüzü yukarı bakıyor mu ve hangi yöne dönük?" olduğu bir konveyör bandındaki kargo örneği:
| İndeks | Anahtar nokta | Amaç | Ayna eşi | Sigma |
|---|---|---|---|---|
| 0 | label_top_left | etiketin yönü | 1 | 0.04 |
| 1 | label_top_right | etiketin yönü | 0 | 0.04 |
| 2 | label_bottom_right | etiketin yönü | 3 | 0.04 |
| 3 | label_bottom_left | etiketin yönü | 2 | 0.04 |
kpt_shape: [4, 3]
flip_idx: [1, 0, 3, 2]
kpt_oks_sigmas: [0.04, 0.04, 0.04, 0.04]flip_idx kendi tersi olma denetimini geçer: 0 → 1 → 0 ve 2 → 3 → 2. Yansıtılmış bir etiket sol ve sağı değiştirir ama üstü ve altı korur; bu nedenle sol üst, sağ altla değil sağ üstle eşleşir.
Toleransı bulmak için oks.py içinde sigma=[0.04] * 4 değerini ayarla ve ofsetleri genişlet; ölçeği etiketin kutusu belirlediğinden görüntülerindeki tipik bir kargo etiketinin boyutlarında bir kutu kullan. OKS'nin ilk kez 0.5'in altına düştüğü ofset, etiketleyicilerinin hassasiyetinin modele izin verdiği en büyük hatadır.