7.1. Wat is een neuraal netwerk

Een neuraal netwerk is een algoritme waarvan het gedrag wordt aangeleerd op basis van voorbeelden in plaats van met de hand te worden geprogrammeerd. Dezelfde netwerkarchitectuur leert gezichten te detecteren wanneer ze een miljoen gezichtsafbeeldingen krijgt. Dezelfde architectuur leert handen te detecteren wanneer ze een miljoen handafbeeldingen krijgt. Dezelfde architectuur leert ze allemaal tegelijk te detecteren wanneer ze een gelabelde set krijgt die veel objectcategorieën omvat. Alleen de gewichten verschillen per doel, en de gewichten worden geproduceerd door een extern trainingsproces dat de voorspellingen van het netwerk vergelijkt met gelabelde voorbeelden en de gewichten bijstelt totdat ze overeenkomen.

7.1.1. Het mechanisme

Een neuraal netwerk is een stapel lagen. Elke laag vermenigvuldigt de uitvoer van de vorige laag met een matrix van gewichten, telt er een bias-vector bij op en past een niet-lineaire functie toe op het resultaat. De uitvoer van de ene laag is de invoer voor de volgende. Een vastgelegde afbeelding komt bovenaan de stapel binnen, stroomt omlaag door tientallen of honderden lagen en komt onderaan tevoorschijn als een tensor waarvan de waarden beschrijven wat er op de afbeelding stond.

Wat de gewichten van elke laag doen hangt af van waarop het netwerk is getraind. Een gewichtenmatrix in een vroege laag van een visienetwerk kan reageren op een korte horizontale rand; een iets diepere laag kan reageren op een hoek; een nog diepere op een ronde oogvorm; de diepste lagen kunnen reageren op complete gezichtsarrangementen. Niets hiervan is met de hand geschreven. Het trainingsproces doorliep miljoenen gelabelde voorbeelden, duwde de gewichten omlaag langs een verliesfunctie, en de hiërarchie van rand-dan-hoek-dan-oog-dan-gezicht kwam vanzelf uit de data voort.

Een verticale stapel van negen gelabelde vakken die de lagen van een klein classificatienetwerk voorstellen. Het bovenste vak is gelabeld "Input image" met een tensorvorm van (192, 192, 3). Een pijl leidt omlaag naar een "Conv + ReLU"-vak met vorm (96, 96, 32). Een andere pijl leidt naar een tweede "Conv + ReLU"-vak met vorm (48, 48, 64). Een "MaxPool"-vak volgt met vorm (24, 24, 64). Nog twee "Conv + ReLU"-vakken volgen met vormen (12, 12, 128) en (6, 6, 256). Een "Global average pool"-vak heeft vorm (256,). Een "Fully connected"-vak heeft vorm (1000,). Het onderste vak is gelabeld "Class scores" met vorm (1000,). De tensorstroom loopt van boven naar beneden.

Een klein classificatienetwerk als een stapel lagen. De invoertensor komt bovenaan binnen met de vorm van de vastgelegde afbeelding en stroomt omlaag door de lagen, waarbij elke laag de dimensies van de tensor transformeert. De uitvoertensor onderaan heeft één waarde per klasse. Detectie- en sleutelpuntnetwerken delen dezelfde vorm van een stapel lagen; alleen de interpretatie van de uitvoertensor verandert.

De architectuur van het netwerk – hoe de lagen zijn gerangschikt, welke bewerkingen ze verbinden – bepaalt wat het netwerk kan doen. De gewichten zijn wat het netwerk heeft geleerd. Het aandeel van de cam hierin is om het gewichtenbestand te laden dat door training is geproduceerd en dezelfde rekenkundige bewerkingen uit te voeren die de trainer uitvoerde, maar dan op het vastgelegde frame in plaats van op de trainingsset.

7.1.2. Wat erin gaat, wat eruit komt

Beide uiteinden van het netwerk zijn tensoren – multidimensionale getallenarrays, hetzelfde soort object dat zojuist in het numpy-hoofdstuk werd geïntroduceerd. De invoertensor voor een visienetwerk is de vastgelegde afbeelding, omgevormd naar de indeling die het netwerk verwacht: doorgaans een 4-tuple-vorm (B, H, W, C) waarbij B de batchdimensie is (op de cam altijd 1, omdat er telkens één frame wordt verwerkt), H en W de door het netwerk verwachte pixelhoogte en -breedte zijn, en C het aantal kanalen is (3 voor een RGB-netwerk, 1 voor grijswaarden).

De uitvoertensor hangt af van waarvoor het netwerk bedoeld is:

  • Een classificatie-netwerk produceert een 1-D-tensor van betrouwbaarheidsscores, één per klasse. De index van de hoogste score is de voorspelde klasse. De van MobileNet afgeleide persoonsdetector die op de meeste cams meegeleverd wordt, heeft deze vorm: twee scores, één voor “person”, één voor “not person”.

  • Een detectie-netwerk produceert een 2-D-tensor waarvan de waarden een lijst van begrenzingsvakken plus klassewaarschijnlijkheden beschrijven. YOLOv8 heeft deze vorm: een (84, N)-tensor waarbij 4 van de 84 rijen box-regressiewaarden zijn en de andere 80 per-klasse-waarschijnlijkheden, herhaald over N ankerposities.

  • Een sleutelpunt-netwerk produceert een tensor waarvan de waarden pixelposities van benoemde herkenningspunten zijn. Het MediaPipe face-landmarks-model heeft deze vorm: 468 sleutelpunten per gedetecteerd gezicht.

  • Een segmentatie-netwerk produceert een 2-D-tensor waarvan de waarden per-pixel-klasselabels zijn – met dezelfde dimensies als de invoer, met een categorie-index op elke positie.

  • Een regressie-netwerk produceert een enkel getal of een korte vector van getallen – een diepteschatting, een hoek, een temperatuur.

Elke vorm heeft op de cam zijn eigen post-processor die de ruwe uitvoertensor terugzet in de resultaatvorm die de rest van de applicatie gebruikt – begrenzingsvakken, sleutelpuntlijsten, klasselabels, numerieke schattingen. De post-processor is code aan de applicatiekant die de uitvoerindeling van het netwerk kent; het netwerk zelf is enkel de rekenkunde die de tensor produceert.

7.1.3. Waarom dit werkt op een cam

Twee rekenkundige onderdelen maken dit haalbaar voor een onderdeel van microcontroller-klasse. Het eerste is kwantisatie. Training gebeurt in 32-bits drijvende-kommarekenkunde; inferentie kan voor de meeste netwerken in 8-bits gehele-getallenrekenkunde draaien met vrijwel geen verlies aan nauwkeurigheid. Acht-bits-gewichten nemen een kwart van de opslag in en draaien meerdere keren sneller dan de 32-bits drijvende-kommagetallen. Elk model dat met de cam wordt meegeleverd is al extern gekwantiseerd.

Het tweede is hardwareversnelling. Dezelfde rekenkunde die de CPU van een microcontroller instructie voor instructie afwerkt, voert een neuraal-netwerkversneller met honderden bewerkingen tegelijk uit. De nieuwere cams (de AE3 en de N6) dragen een speciale neural processing unit (NPU) – een tensorversneller op de SoC – die een model dat een seconde nodig zou hebben op de CPU omzet in een model dat in tientallen milliseconden draait. Het hoofdstuk over inferentie-engines behandelt hoe het aandeel van de cam hierin eruitziet.

7.1.4. Wat het hoofdstuk behandelt

Trainen is niet de taak van de cam. Een getraind model komt op de cam aan als een .tflite-bestand; de cam laadt het, voert elk vastgelegd frame erdoorheen en decodeert de resulterende tensor tot een resultaat waarop de applicatie kan reageren. Alles wat volgt gaat over elk van deze stappen:

  • het laden en inspecteren van een model;

  • de flashpartitie waar modelbestanden zich bevinden;

  • de vier fasen van een inferentieaanroep;

  • de engines die de rekenkunde daadwerkelijk uitvoeren;

  • en de post-processors die een uitvoertensor terugzetten in een lijst van vakken, sleutelpunten of klassen.

De detectoren in het hoofdstuk over afbeeldingen waren elk afgestemd op een bepaald doel. De detectoren die in de rest van dit hoofdstuk aan bod komen, worden in plaats daarvan vanuit data getraind, waarbij dezelfde engine elk model draait dat het script laadt. De werkstroomverandering die hiermee gepaard ging – een doelspecifiek algoritme vervangen door een doelspecifiek gewichtenbestand – is het volgende wat we gaan uitlichten.