A 27.2. U-Net, encoder–decoder és skip egységben felépítettük az encoder–decoder és a skip-kapcsolatos U-Net-alapú szegmentáló architektúrát. Ott a térbeli alakok és a csatornaszámok összeillesztése volt a fő kérdés. Most azt vizsgáljuk, hogyan mérjük a kimenő, pixelszintű bináris maszk minőségét. Egyetlen skalár pontosság nem elég: egy 24×24-es GlyphLab-képen a háttér gyakran a pixelek 80–90%-át teszi ki, így az „üres maszkot jósolok” stratégia is magas pixel-accuracyt kaphat, miközben a tényleges előtér-alakzatot teljesen elhibázza.
A szükséges előismeret: halmazművelet, a 27.2. U-Net, encoder–decoder és skip alfejezetből a bináris maszk mint 0/1 előtér-térkép fogalma, valamint a 23.3. Páros összehasonlítás és csoportszintű intervallum alfejezetből a csoportos kiértékelés és a jelenet-mintavételi egység. Ez az egység önálló matematikai fogalmat épít fel, ezért először a metrika bináris halmaz-definícióját rögzítjük, utána térünk a numerikus és aggregálási kérdésekre.
Induló becslés: ha egy 6 pixeles célmaszkra a predikció 6 találatot és 30 téves előtér-pixelt tartalmaz, akkor a pixel-accuracy , tehát kiválónak tűnik. Vajon a Dice vagy az IoU is ezt mondja? A második szakasz definíciói után ezt a példát ellenőrizzük.
Legyen a képpontok véges halmaza, egyetlen bináris maszkra. A target maszk által kijelölt előtér-halmaz legyen , a predikált maszké . A két halmaz közös része , uniója . Jelölje
A Jaccard-index, a szegmentálásban elterjedt angol nevén Intersection over Union (IoU):
feltéve, hogy az unió nem üres. A Sørensen–Dice-együttható (röviden Dice):
feltéve, hogy . Mindkét metrika -be esik, és az esetben 1-et, a diszjunkt halmazokra 0-t ad. A nevezőben az IoU az uniót használja, a Dice pedig a két halmaz méretének összegét; ez okozza, hogy a Dice mindig legalább akkora, mint az IoU.
A definíció számosságokat használ, ezért a maszkok tárolási formátuma
lényegtelen: ugyanazt az eredményt adják a uint8 0/1
tömbök, a bool tömbök és a küszöbölt float32
logitok is, ha a küszöbölés bináris döntést adott.
A GlyphLab-ban a maszk alakja
,
uint8, ahol
a képek száma, a csatorna mérete 1, a többi a térbeli kiterjedés. A
-adik
képre
a célmaszk,
a predikciós maszk. A számítás során a
-t
a
-re
redukáljuk a
tengelyek összegzésével; többosztályos esetben minden osztályra külön
binarizált
párt képzünk.
Az üres unió pontosan akkor fordul elő, ha . A nevező ekkor nulla, ezért a fenti osztás nem ad értelmes számot. Ebben a könyvben a páronkénti konvenció a következő: ha mindkét maszk üres, akkor , mert a predikció és a cél tökéletesen megegyezik. Ha az egyik üres, a másik nem, akkor az unió nem üres, így és , tehát . A globális aggregálásnál viszont az üres–üres pár egyetlen tagot sem ad a közös számlálóba; ha a teljes adathalmazon az összes unió üres, a globális metrika nem definiált, és ezt hibával jelezzük, nem pedig 1-gyel.
Ez a konvenció értelmezés kérdése, nem tétel. A szakirodalmi implementációk gyakran inkább kihagyják az üres–üres párokat az átlagból; a kettő nem azonos, mert a mi konvenciónk 1-es járulékot ad a képenkénti átlaghoz. A laborban ez láthatóvá válik.
A két metrika nem független: ugyanazt a statisztikát rendezi más skálán.
Tétel (Dice–IoU azonosság). Legyenek véges pixelhalmazok, , , , és tegyük fel, hogy . Ekkor az unió is nemüres, az IoU definiált, és
Bizonyítás. Az feltételből is következik, mert ha a két halmaz közül legalább az egyik nem üres, akkor az unió is nem üres. Ezért nevezője nem nulla. Helyettesítsünk be a jobb oldalba:
Az utolsó egyszerűsítésben , tehát a tört elhagyása megengedett.
Az állítás típusa tétel, a bizonyítás elemi algebra. A feltétel fontos: az üres–üres párt a tétel nem fedi le, mert ott . Az imént bevezetett 1-es konvenció nem következik a tételből, hanem külön definíció. A következő egyenlőtlenség szintén levezethető, és a gyakorlatban magyarázza, miért „szigorúbb” az IoU:
mert . Egyenlőség pontosan (diszjunkt maszkok) vagy (tökéletes egyezés) esetén áll; közbülső átfedésnél a Dice szigorúan nagyobb.
A metrikák egyetlen maszkpárra definiáltak. Egy tesztkészletre több aggregálási út létezik, és ezek különböző kérdésekre válaszolnak.
Képenkénti (per-image) átlag. Minden képre kiszámítjuk és értékét, majd
Ez minden képet azonos súllyal vesz, függetlenül az előtér méretétől. A 23.3. Páros összehasonlítás és csoportszintű intervallum alfejezetben bevezetett jelenet-bootstrap ehhez illeszkedik: először képenként számolunk, majd a két view eredményét jelenetenként átlagoljuk, és a bootstrap a független scene-egységeken húz. Így az intervallum a jelenetek közötti szórást becsli, nem a pixelek közötti függést.
Globális pixel-aggregálás. Az összes képet egyetlen, nagy pixelgyűjteménynek tekintjük. Legyen
Ekkor
A globális verzió minden pixelt azonos súllyal vesz, ezért a nagy előtérrel rendelkező képek dominálják. Az üres–üres párok a globális számlálóba semmit sem tesznek, míg a képenkénti átlagban 1-ként jelennek meg; ez önmagában is eltérést okoz.
Osztályegyensúly (class imbalance). Ha nagy és az előtér kicsi, akkor a pixel-accuracy a domináns háttér miatt megtévesztő. A Dice és az IoU ezt kiküszöböli, mert a nevező az és összhosszához, illetve uniójához viszonyít. Hátrányuk viszont, hogy ugyanaz az abszolút hiba egy kis objektumon sokkal nagyobb büntetést kap, mint egy nagyon: ha 4 pixeles és 8 pixeles teljes lefedéssel, akkor ; ha 400 pixeles és 404 pixeles teljes lefedéssel, akkor . Ez a tulajdonság a relatív átfedést méri, nem az abszolút tévedés költségét.
Határ (boundary). A Dice és az IoU kizárólag halmaz-kardinalitásokat használ, ezért nem bünteti közvetlenül a kontúr alakját. Két azonos IoU-jú hiba teljesen más irányú is lehet: egy 2×2-es célblokkra a tőle jobbra 1 pixellel eltolt 2×2-es predikció és a tőle lefelé 1 pixellel eltolt 2×2-es predikció egyaránt , , tehát és . Az egyik hibát a közös függőleges határon követjük el, a másikat a vízszintesen. Aki a határvonal pontos lefutását akarja mérni, kiegészítő metrikát használhat (például boundary-IoU vagy felületi távolság), de ez nem része a jelen egység főútjának; a területalapú metrika érvényességi korlátját mindig ki kell mondani.
Legyen a tér 4×4, tehát . Három maszkpárt vizsgálunk.
a bal felső 3×3-as blokk, tehát . A metszet , az unió . Így
pár: , , tehát , , . Ekkor .
pár: . Az unió üres, a páronkénti konvenció szerint .
A három pár képenkénti átlaga:
A globális pixel-számításhoz:
A globális IoU lényegesen kisebb, mint a képenkénti átlag, mert a globális változat nem kap 1-es járulékot az üres–üres pártól, és a 3×3-as téves predikció FP-pixeleit teljes súllyal számolja. A számok mutatják, hogy a két aggregálás nem felcserélhető.
A kód a saját NumPy-referenciánk stílusát követi. Bináris
maszkpárokra számol, a bemenet (N,1,H,W) alakú
uint8 vagy bool. A csatornatengely 1 méretű,
ezért a térbeli összegzés az utolsó két tengelyen történik.
# dice_iou_lab.py
import numpy as np
def binary_mask_metrics(pred, target, empty_empty_value=1.0):
"""Per-image IoU es Dice binaris (N,1,H,W) maszkparokra.
Konvencio: ha mindket maszk ures, mindket metrika empty_empty_value.
Ha az egyik ures, a masik nem, akkor a nevezo pozitiv, a metszet 0.
"""
p = np.asarray(pred).astype(bool)
t = np.asarray(target).astype(bool)
# shape ellenorzes
assert p.shape == t.shape and p.ndim == 4 and p.shape[1] == 1
inter = np.logical_and(p, t).sum(axis=(-2, -1)).astype(np.float64)
sum_a = np.logical_and(t, np.ones_like(t)).sum(axis=(-2, -1)).astype(np.float64)
sum_b = p.sum(axis=(-2, -1)).astype(np.float64)
union = np.logical_or(p, t).sum(axis=(-2, -1)).astype(np.float64)
with np.errstate(divide='ignore', invalid='ignore'):
iou = np.where(union > 0, inter / union, empty_empty_value)
dice = np.where(sum_a + sum_b > 0,
2.0 * inter / (sum_a + sum_b),
empty_empty_value)
return iou, dice # mindkettó alakja (N,1)
def global_binary_metrics(pred, target):
"""Globális pixel-IoU/Dice az összes képre együtt."""
p = np.asarray(pred).astype(bool).reshape(pred.shape[0], -1)
t = np.asarray(target).astype(bool).reshape(target.shape[0], -1)
TP = np.logical_and(p, t).sum().astype(np.float64)
FP = np.logical_and(p, np.logical_not(t)).sum().astype(np.float64)
FN = np.logical_and(t, np.logical_not(p)).sum().astype(np.float64)
# Üres unió az összes képre együtt: a metrika nem definialt.
union = TP + FP + FN
if union == 0:
raise ValueError("A globális IoU/Dice nem definialt: ures unió.")
iou = TP / union
dice = 2.0 * TP / (2.0 * TP + FP + FN)
return iou, dice
if __name__ == "__main__":
# Három 4x4-es példa, NCHW alakban.
t0 = np.array([[[[1,1,0,0],
[1,1,0,0],
[0,0,0,0],
[0,0,0,0]]]], dtype=np.uint8)
p0 = np.ones((1,1,3,3), dtype=np.uint8) # bal felső 3x3, padding nélkül 3x3
# A 3x3 blokkot 4x4-re kell helyezni, a jobb alsó részt nullázva nem kell,
# de az alaknak egyeznie kell; készítsünk 4x4-et:
p0 = np.pad(p0, ((0,0),(0,0),(0,1),(0,1)), mode='constant')
t1 = np.zeros((1,1,4,4), dtype=np.uint8)
p1 = np.zeros((1,1,4,4), dtype=np.uint8)
p1[0,0,0,0] = 1
p1[0,0,3,3] = 1
t2 = np.zeros((1,1,4,4), dtype=np.uint8)
p2 = np.zeros((1,1,4,4), dtype=np.uint8)
targets = np.concatenate([t0, t1, t2], axis=0) # (3,1,4,4)
preds = np.concatenate([p0, p1, p2], axis=0)
iou, dice = binary_mask_metrics(preds, targets)
print("per-image IoU :", iou.ravel())
print("per-image IoU mean:", iou.mean())
print("per-image Dice :", dice.ravel())
print("per-image Dice mean:", dice.mean())
gi, gd = global_binary_metrics(preds, targets)
print("global IoU :", gi)
print("global Dice:", gd)A kódból várt kimenet – a fenti kézi számítás alapján, nem jelen környezetben futtatott mérésként jelölve:
per-image IoU : [0.44444444 0. 1. ]
per-image IoU mean: 0.48148148148148145
per-image Dice : [0.61538462 0. 1. ]
per-image Dice mean: 0.5384615384615384
global IoU : 0.36363636363636365
global Dice: 0.5333333333333333
A labor célja, hogy a kézi példát a fenti kóddal saját környezetben lefuttassa, és számszerűen lássa a képenkénti és a globális aggregálás eltérését.
uint8,
(3,1,4,4). Nincs külső fájltól függés; a GlyphLab
data/masks.npy-jéből a hallgató a későbbi projektekben a
np.load után uint8 tömböt kap, és ugyanez a
függvény használható.numpy csak.np.random.seed(20261020)-at
teszünk a későbbi bootstrap-kompatibilitás érdekében, de a
metrikaértékek nem függnek tőle.uint8, belső konverzió
bool, a metrikák float64, hogy a
nagyságrendű pixelösszegek pontosan férjenek.lab/ munkakönyvtárból:
python dice_iou_lab.py.Adott és ugyanazon a 10×10-es rácson: , , . Számítsa ki és értékét, és igazolja a levezetett azonosságot. Adjon olyan két halmazpárt, ahol , és indokolja, miért.
Elvárt átadandó eredmény: a két számérték, a behelyettesítés, és a két egyenlőségi eset megnevezése.
Bizonyítsa be a különbségre vonatkozó állítást: ha , akkor , és az egyenlőség pontosan vagy esetén áll fenn.
Elvárt átadandó eredmény: teljes levezetés a definíciójából, az egyenlőség feltételének indoklása, és egy olyan számpélda, ahol .
Írjon dice_iou_multi(pred, target) függvényt, amely
(N,C,H,W) alakú, 0/1 uint8 többosztályos
maszkokat fogad, és osztályonként visszaadja a képenkénti IoU-átlagot,
valamint a mean IoU-t (a
osztály átlagát). Az üres–üres párokra minden osztályban 1-gyel
számoljon. Ellenőrizze a fenti három bináris példán
esetben, hogy a függvény a binary_mask_metrics kimenetével
egyezik.
Elvárt átadandó eredmény: futtatható kód, a három példán adódó vektor és a , továbbá a shape-ellenőrzés.
Adott a következő kódrészlet:
def iou_bad(pred, target):
inter = (pred * target).sum(axis=(-2, -1))
union = pred.sum(axis=(-2, -1)) + target.sum(axis=(-2, -1)) - inter
return (inter / union).mean()Tegyük fel, hogy a függvényt a hálózat nyers sigmoid-kimenetére
hívjuk, amely float32 értékeket tartalmaz
-ben.
Mi a hiba, mi a következménye, és hogyan javítaná? Ellenőrizze a
javítást azzal a kétpixeles példával, ahol pred=[0.6,0.4],
target=[1,0].
Elvárt átadandó eredmény: a hiba oka, a numerikus következmény, a küszöbölést tartalmazó javított függvény, és a javított kimenet.
A GlyphLab szegmentáló laborban a cél a 24×24-es előtér-maszk rekonstrukciója. Tervezzen kiértékelési protokollt, amely a 23.3. Páros összehasonlítás és csoportszintű intervallum alfejezetbeli class-stratified scene bootstrapet használja a képenkénti IoU átlagához. Adja meg:
Elvárt átadandó eredmény: protokoll-leírás, a baseline indoklása, és legalább egy konkrét korlát (például a bootstrap csak a tesztminta-mintavételi bizonytalanságot közelíti).
Az unió mérete , tehát . A Dice . Az azonosság: , egyezik.
A esetek a levezetett képletből: , azaz (diszjunkt halmazok, például a bal felső, a jobb alsó sarok), vagy , azaz (a két halmaz azonos). Ha üres és nem üres, az esethez tartozik, és ; az üres–üres pár külön konvenció.
A tétel szerint , feltéve, hogy . Ekkor
Mivel , a számláló nemnegatív, a nevező . Így . Az egyenlőség pontosan akkor, ha , azaz vagy . A ekvivalens -val, mert a nevező pozitív. A ekvivalens -vel, azaz . Mivel és , ez csak és mellett lehet, tehát , vagyis . Számpélda közbülső értékre: , , , ekkor , , és .
A többosztályos függvény minden osztályra binarizál:
def dice_iou_multi(pred, target):
# pred, target: (N,C,H,W), uint8, 0/1 one-hot vagy index-halmaz? Jelen
# megoldás: már binarizált C csatornás 0/1 tombot varunk.
pred = np.asarray(pred).astype(bool)
target = np.asarray(target).astype(bool)
assert pred.shape == target.shape and pred.ndim == 4
N, C, H, W = pred.shape
ious = np.empty((C, N), dtype=np.float64)
for c in range(C):
p = pred[:, c, None, :, :] # (N,1,H,W)
t = target[:, c, None, :, :]
iou, _ = binary_mask_metrics(p, t, empty_empty_value=1.0)
ious[c] = iou[:, 0]
per_class_mean = ious.mean(axis=1) # (C,)
miou = per_class_mean.mean()
return per_class_mean, miouA
esetben a három példa IoU-vektora
,
az osztályon belüli átlag
.
A kód az üres–üres konvenciót az empty_empty_value=1.0
argumentummal őrzi meg. Alakellenőrzés: bemenet (3,1,4,4),
kimenet per_class_mean alakja (1,), a
miou skalár.
A hiba: a pred nem bináris, hanem valós
-beli
sigmoid-kimenet. A pred * target ezért nem
metszet-számosságot ad, hanem súlyozott összeget; a union
sem halmaz-unió, hanem valós összeg. A következmény: a metrika nem IoU,
és érzékeny a küszöb alatti zajra; például a kétpixeles
[0.6,0.4] és [1,0] esetén az inter
,
a union
,
az IoU-hibrid
,
miközben a küszöbölt [1,0] predikcióval a valódi IoU
.
A javítás:
def iou_fixed(pred, target):
p = np.asarray(pred, dtype=np.float64) > 0.5
t = np.asarray(target, dtype=np.float64) > 0.5
inter = np.logical_and(p, t).sum(axis=(-2, -1))
union = np.logical_or(p, t).sum(axis=(-2, -1))
return (inter / union).mean()A kétpixeles példán a kimenet . Ha a predikció valószínűség, a kiértékelés előtt rögzíteni kell a küszöböt; a 23.2. Kalibráció és döntési küszöb alfejezetben a döntési küszöb kalibrációs szerepét tárgyaljuk, itt a metrika bináris definíciója a döntés utáni maszkot várja.
A protokoll:
A leggyakoribb tévedés: a globális pixel-IoU-t és a képenként átlagolt IoU-t ugyanannak a statisztikának tekinti. Ez csak speciális esetben, például azonos méretű és azonos előtér-számosságú maszkoknál adhat közeli értéket; általában különböző.
Ellenpélda: két tesztkép. Az elsőn , , , tehát . A másodikon , , tehát . A képenkénti átlag . A globális: , , , tehát
Ugyanaz a modell egyszer 0,5-ös teljesítményűnek, másszor 0,99-esnek látszik, attól függően, hogy képenként vagy pixelenként átlagolunk. A két statisztika más kutatási kérdésre válaszol: az első arra, hogy egy átlagos kép/jelenet milyen jól van szegmentálva, a második arra, hogy a pixelek mekkora hányada helyes.
Visszahívás a 15.3. Transposed convolution mint adjungált alfejezetből: a transposed convolution adjungált, nem általános inverz. A jelen egység kapcsolódása: az U-Net decoder a transzponált konvolúcióval állítja elő a térbeli maszklogitokat, de a metrika a logitok küszöbölése utáni bináris halmazt méri. Az inverzként való félreértés a metrikaoldalra is átvihető: a magas IoU nem azt jelenti, hogy a dekóder visszaállította az eredeti maszk minden határpixelét, csak azt, hogy a halmazátfedés nagy.
Önellenőrzés: a kézi példában
,
,
az unió
;
a Dice
és az IoU
közti azonosság
.
A harmadik pár üres–üres, a tétel nem alkalmazható, az 1-es konvenció
külön definíció. A labor kódja bool konverziót használ,
ezért a np.pad után a p0 4×4-es alakú; az
összegzések az utolsó két tengelyen futnak, a kimenet
(3,1).
A bináris szegmentálás két alappillére az IoU és a Dice. Az IoU a metszet és az unió, a Dice a kétszeres metszet és a méretösszeg hányadosa. Nemüres halmazokra , amit a közös statisztikából elemi algebrával levezettünk. Az üres–üres párra a könyv páronkénti 1-es konvenciót rögzít. A képenkénti és a globális pixel-aggregálás külön statisztika: az első képenként, a második pixelenként súlyoz, és az üres konvenciót is másként kezeli. A labor három maszkpáron mutatta az eltérést. A következő alkalmazás: 27.4. Instance mask és összetett feladat alfejezetben az instance mask és az összetett feladat kapcsolja össze a detektálásból ismert IoU-t a pixelszintű előtér-meghatározással.