7.13. Potiskivanje koje nije najveće (non-max suppression)¶
Mreža za detekciju obično oko istog stvarnog objekta proizvede nekoliko preklapajućih kandidata za okvire: svako sidro u blizini objekta okida sa sličnim rezultatom, a naknadni procesor vidi ih sve. Potiskivanje koje nije najveće (NMS) je korak koji taj skup pretvara u jedan okvir.
Algoritam je kratak: poredaj okvire kandidate po rezultatu, uzmi onaj s najvišim rezultatom, potisni svaki drugi okvir koji se s njim preklapa iznad odabranog praga, zatim uzmi sljedeći najviši od onoga što ostaje i ponovi. Mjera preklapanja je presjek-preko-unije (IoU) – zajednička površina dvaju okvira podijeljena s njihovom ukupnom površinom, vrijednost između 0 (nema preklapanja) i 1 (identični okviri). Argument konstruktora nms_threshold na svakom isporučenom naknadnom procesoru granica je iznad koje se okviri tretiraju kao duplikati već zadržanog okvira.
NMS sažima skup preklapajućih detekcija na onu s najvišim rezultatom.¶
7.13.1. Soft-NMS¶
Isporučena klasa ml.utils.NMS implementira Soft-NMS, poboljšanje koje smanjuje rezultat preklapajućeg okvira za iznos koji ovisi o tome koliko se preklapa, umjesto da okvir potpuno odbaci. Ako sniženi rezultat padne ispod praga, okvir se odbacuje; inače preživljava sa smanjenim rezultatom i natječe se u sljedećem krugu.
Parametar nms_sigma upravlja time koliko je smanjenje agresivno. S malim nms_sigma (isporučena zadana vrijednost 0.1) smanjenje je strmo: okviru s jakim preklapanjem rezultat se spušta gotovo na nulu i Soft-NMS se svodi na klasični NMS. S većim nms_sigma smanjenje je blago i preklapajući okviri različitih objekata češće preživljavaju, što je važno kada se stvarni objekti iste klase doista preklapaju (gomila lica, skup dlanova).
Postavljanje nms_sigma na <= 0 u potpunosti onemogućuje smanjenje: preklapajući okviri prolaze sa svojim izvornim rezultatima, a samo ih prag rezultata filtrira.
7.13.2. Izravna izgradnja¶
Svaki isporučeni naknadni procesor po zaključivanju gradi novi NMS, dodaje mu svakog kandidata i na kraju poziva get_bounding_boxes(). Prilagođeni naknadni procesor slijedi isti obrazac:
from ml.utils import NMS
iw = model.input_shape[0][2]
ih = model.input_shape[0][1]
nms = NMS(iw, ih, inputs[0].roi)
for box, score, class_idx in candidates:
nms.add_bounding_box(box.xmin, box.ymin,
box.xmax, box.ymax,
score, class_idx)
result = nms.get_bounding_boxes(threshold=nms_threshold,
sigma=nms_sigma)
Konstruktor uzima ulaznu širinu i visinu mreže u pikselima te ROI izvorne slike na kojoj se model izvodio; add_bounding_box() uzima koordinate okvira u tom pikselskom prostoru mrežnog ulaza, a get_bounding_boxes() preživjele okvire vraća natrag u koordinate slike koristeći ROI. Ponovno mapiranje automatski uzima u obzir razvlačenje normalizacije – isti ROI koji je predviđač vidio koristi se za projiciranje okvira natrag – pa su vraćeni okviri spremni za crtanje na uhvaćenu sličicu.
Vraćeni oblik je lista listi po klasi, indeksirana prema label_index proslijeđenom u add_bounding_box. Prazne liste klasa zadržane su tako da se indeks podudara s indeksom klase modela; enumerate(result) prolazi kroz klase zajedno s njihovim detekcijama.