7.2. Vad ML förändrade

Bildmodulen bär en handfull äldre detekteringsmetoder – find_features() för Haar-cascade-ansiktsdetektering, find_eye() för den fasta pupillsökaren, find_hog() för sammanfattningar av gradientriktning, samt vägarna find_keypoints() och find_lbp() för godtyckliga nyckelpunkter. Alla fungerar fortfarande; alla har ersatts av maskininlärningspipelinen.

7.2.1. Den klassiska uppdelningen: handdesignade sammanfattningar, inlärda beslut

En klassisk synpipeline var en tvåstegsprocess. Det första steget förvandlade råa pixlar till en kompakt uppsättning tal valda för att sammanfatta vad som fanns i bilden – inte pixelvärdena själva, utan en kortare beskrivning av vilka mönster som dök upp var. Det andra steget tog den sammanfattningen och fattade ett beslut: ansikte eller inte, det här objektet eller det där, samma mål eller annat.

Uppdelningen spelade roll eftersom de två stegen hade olika upphovsmän. Det första steget skrevs av en människa. Någon satte sig ned och bestämde att ljushetsskillnaden mellan två specifika rektanglar var en bra sammanfattning av ett ögonområde, att den dominerande kantriktningen i varje cell i ett rutnät var en bra sammanfattning av en stående persons kontur, att det ljusa-eller-mörka mönstret runt varje pixel var en bra sammanfattning av lokal textur. Vart och ett av dessa val var en handskriven algoritm – skriven, felsökt och publicerad. De äldre metoderna ovan var alla sammanfattningar av detta slag som hade blivit standardverktyg:

  • find_features() sammanfattar ett fönster av bilden genom att summera ljusheten inuti flera rektanglar och jämföra summorna. Rektangellayouterna valdes eftersom mänskliga ansikten uppvisar tillförlitliga ljus-mot-mörker-kontraster: ögonbryn mot kinder, ögonhålor mot panna, näsa mot omgivande hud.

  • find_hog() sammanfattar en bild genom att gå igenom ett rutnät av små celler och registrera vilken kantriktning som dominerar i varje cell. Rutnätet valdes eftersom en stående persons kontur producerar ett igenkännbart mönster av kantriktningar oavsett kläder eller belysning.

  • find_lbp() sammanfattar varje pixels grannskap genom att koda vilka av dess omgivande pixlar som är ljusare och vilka som är mörkare. Kodningen valdes eftersom dessa ljusare-än / mörkare-än-mönster fångar texturen hos en yta oberoende av den övergripande belysningen.

  • find_keypoints() hittar hörnpunkter i bilden och beskriver området runt varje hörn på ett sätt som förblir detsamma när hörnet roteras. Hörn-och-rotationsschemat valdes eftersom samma hörn dyker upp igen när en scen betraktas från en annan vinkel.

När en sammanfattning väl hade skrivits för hand kunde ett litet inlärningssteg ovanpå den kombinera talen till ett beslut. Ansiktsdetekteringsalgoritmen kopplade ett inlärningssteg till rektangelskillnadssammanfattningen och tränade det på etiketterade ansikts- och icke-ansiktsbilder för att lära sig vilka kombinationer av skillnader som signalerar ett ansikte. Kantriktningssammanfattningen matades in i ett inlärningssteg som tränades på etiketterade person- och icke-personbilder. Hörndeskriptorerna matades in i ett matchningssteg som lärde sig hur mycket vikt varje hörn skulle ges. Vart och ett av dessa andra steg är en inlärningsalgoritm – en liten enligt moderna mått, men en inlärningsalgoritm.

Det var bidragsuppdelningen som spelade roll. Människan bidrog med sammanfattningen. Maskinen lärde sig kombinationen. Att lägga till ett nytt mål innebar att skriva en ny sammanfattning.

7.2.2. Vad neuronnät förändrade

Ett neuronnät raderar uppdelningen. De första lagren i nätverket gör det sammanfattningsarbete som de handskrivna algoritmerna brukade göra – att detektera kanter, hörn, orienterade staplar, texturer, precis de saker som de äldre metoderna ovan var var och en inställda på att detektera – men de är inte handskrivna. De lärs in från samma träningsdata som beslutssteget lärs in från, i en enda träningsomgång som justerar båda halvorna av nätverket på en gång. De djupare lagren gör den kombinering som det lilla inlärningssteget ovanpå de handskrivna sammanfattningarna brukade göra, också inlärt, i samma omgång.

Förändringen i vem som designar vad är total:

  • Människan designar indatan – infångade bildrutor av en given storlek och format.

  • Människan designar utdatan – layouten för resultattensorn (en poäng per klass för klassificering, en lista med rutor för detektering, ett rutnät av nyckelpunkter för landmärken).

  • Människan tillhandahåller etiketterad träningsdata – tillräckligt med exempel på målet och tillräckligt med exempel på icke-mål för att träningsprocessen ska ha något att lära sig av.

Allt mellan indata och utdata genereras av träningsprocessen. Det finns inget separat steg för att skriva sammanfattningar. De tidiga lagren slår sig till ro som kant- och texturdetektorer inte för att någon skrev dem på det sättet, utan för att kant- och texturdetektering är det som får nätverkets förutsägelser att stämma med etiketterna. De djupare lagren slår sig till ro som form- och objektdetektorer av samma skäl. Båda halvorna tränas tillsammans, vilket gör att sammanfattningarna varje lager producerar kan vara exakt de sammanfattningar nästa lager behöver – inte de generiska som en handskriven pipeline var tvungen att nöja sig med.

7.2.3. Att komponera med bildmodulen

Neuronnätspipelines fångar fortfarande in via samma sensor-API:er, ritar resultat via samma primitiver draw_rectangle() och draw_circle(), och avgränsar arbete via samma ROI:er (x, y, w, h). En typisk pipeline fångar en bildruta, hittar valfritt ett grovt mål med en klassisk detektor som find_blobs() och skickar dess begränsningsruta till inferensen som ett ROI, kör inferensen och annoterar de returnerade detekteringarna tillbaka i den ursprungliga bildrutan. De klassiska primitiverna är substratet; nätverket är det nya steget i mitten.