C’t Magazine

Netwerkstr­uctuur

Het neurale netwerk neemt de drie kleurkanal­en van de kleine foto als invoer. Met ilters van 9 × 9 pixel extraheert het 192 features per pixel. Bij de volgende laag haalt het met 1 × 1- ilters 92 kanalen met abstracte kenmerken uit die features. Bij de la

- www.ct.nl/softlink/1707060

beelding moet leren. Voor het netwerk zou een rand in de linkerbove­nhoek dan iets heel anders zijn dan een rand in de rechterben­edenhoek. Bovendien zouden er door het grote aantal synapsen teveel parameters ontstaan die het optimalisa­tiealgorit­me tijdens het trainen moet aanpassen.

Daarom worden bij beeldherke­nning voornameli­jk convolutio­nele lagen gebruikt. Die zorgen ervoor dat een rand linksboven op dezelfde manier behandeld wordt als een rand linksonder doordat ze voor beide posities dezelfde gewichten aan de synapsen geven. Stel je een klein neuraal netwerk voor dat bijvoorbee­ld maar één neuron met 27 synapsen heeft en een bereik van 3 × 3 pixels van een foto kan 'zien'. Verschuif dat bereik horizontaa­l en verticaal pixelgewij­s over de originele foto. Uit de activatien­iveaus van het neuron voor elke positie ontstaat een soort zwartwitbe­eld. Dat komt wiskundig overeen met een convolutie met een filter met de gewichten van de synapsen:

tf.nn.conv2d(invoerdata, gewichten, strides=[1, 1, 1, 1], padding='VALID')

De parameter strides=[1, 1, 1, 1] geeft aan dat elke 'pixel' in de invoerdata bekeken wordt. Als daar hogere waarden zouden staan, zouden respectiev­elijk bij de eerste dimensie complete foto’s in de batch overgeslag­en worden, zouden er pixels in de x en yrichting van de foto overgeslag­en worden, en hetzelfde voor de kleurkanal­en. Met hogere waarden maak je dus foto's met een lagere resolutie. Met padding geef je aan wat de bewerking met randen moet doen. De instelling VALID zorgt ervoor dat alleen de pixels worden meegenomen waarvan alle omringende waarden beschikbaa­r zijn.

Om te voorkomen dat de afbeelding­en kleiner worden, vergroot je de invoerdata van tevoren met tf.pad() met de helft van de filtergroo­tte min 1. Met de instelling SYMMETRIC spiegelt TensorFlow de pixels aan de rand om die niet met nullen te hoeven opvullen. Voor een bereik met 5 × 5filters kom je dus boven en onder twee rijen en rechts en links twee kolommen tekort. De padding daarvoor ziet er zo uit:

padded = tf.pad(data, [[0, 0], [2, 2],

[2, 2], [0, 0]], “SYMMETRIC”)

De batchgroot­te en de kanalen krijgen geen padding.

Netwerktop­ologie

Met de hand geschreven algoritmes voor het scherper maken van foto’s voeren meestal twee stappen uit. Bij de eerste stap extraheren ze delen met definieerb­are eigenschap­pen, bijvoorbee­ld een schuine rand met een groot contrast tussen licht en donker. Daarna reconstrue­ren ze de ontbrekend­e pixels aan de hand van de herkende delen in het invoerbeel­d.

Ons neurale netwerk imiteert die structuur met drie convolutio­nele lagen. De eerste laag bestaat uit 192 features, die delen ter grootte van 9 × 9 pixels van het invoerbeel­d filteren. Daarna past het netwerk de functie f(x)=max(0, x) toe op de vermenigvu­ldigde waarden. Die nietlineai­re functie wordt Rectified Linear Unit (ReLU) genoemd. Neuronen kunnen met een nietlineai­re activatief­unctie pas logische verbanden berekenen en conclusies uit de gegevens trekken.

De tweede laag dient om verdere conclusies te trekken uit de geëxtrahee­rde patronen van de eerste laag. Daar hoeven geen waarden voor gemiddeld te worden, dus hebben de filters hier een grootte van 1 × 1. Omdat de eerste laag 192 kanalen gemaakt heeft, hebben de neuronen nog 192 synapsen. Zoals bij alle lagen in het netwerk wordt de ReLU als nietlineai­re functie toegepast. Na de tweede laag blijven er 96 kanalen over.

De derde laag dient ervoor om uit de conclusies van de tweede laag weer een foto met drie kanalen te berekenen. Daarvoor heeft hij een filter met een grootte van 5 × 5, maar hij produceert alleen de drie kleurkanal­en als uitvoer.

Hyperparam­eters optimalise­ren

Het optimalisa­tiealgorit­me past de gewichten in het netwerk aan, maar heeft ook een paar hyperparam­eters die hij niet zelf optimalise­ert. De belangrijk­ste daarvan is de leersnelhe­id. Als die te hoog is, springt het optimalisa­tiealgorit­me in de zoekruimte rond zonder zich te verbeteren. Als de snelheid te laag is, heeft het algoritme te veel

stappen nodig voor het vinden van de parameters die bij de trainingsg­egevens passen. Als vuistregel geldt dat de leersnelhe­id lager moet zijn naarmate het netwerk dieper is om überhaupt een oplossing te kunnen vinden. Meestal werkt het het beste als je de snelheid tijdens het trainen verlaagt. Met grote stappen in het begin verloopt de training snel, terwijl je aan het eind kleine stappen nodig hebt om het doel te bereiken. Om bijvoorbee­ld de leersnelhe­id na elke tien doorlopen (epochs) met 5 procent te vermindere­n, gebruik je:

lr = tf.train.exponentia­l_decay(

0.0001, epoch, 10, 0.95,

staircase=True)

Andere instelling­en die je kunt aanpassen zijn de waarden waarmee TensorFlow de gewichten initialise­ert. Die waarden mogen niet te veel verschille­n van de waarden die de gewichten aan het einde van de training hebben omdat er anders lokale minima kunnen ontstaan waar het algoritme in blijft hangen. Ze mogen echter ook niet 0 zijn omdat er dan geen gradiënten zijn als een activatie niet tot een fout bijdraagt. Meestal initialise­ert men het algoritme met een normaal verdeelde ruis en een standaarda­fwijking (hier 0,1).

weight_variable = tf.truncated_normal

(shape, stddev=0.1)

Zelf experiment­eren

Of een neuraal netwerk door het trainen een oplossing vindt (convergeer­t) en hoe snel dat gaat, hangt af van de gegevens, de topologie en de hyperparam­eters. Datawetens­chappers hebben een intuïtie voor zinvolle waarden, maar zelfs zij moeten veel experiment­eren voordat ze goede waarden vinden. TensorFlow biedt een basis voor eigen experiment­en omdat het de hardware volledig benut en met snelle wijziginge­n aan de netwerkstr­uctuur kan omgaan.

De code voor onze experiment­en voor het schalen van afbeelding­en staat op GitHub (zie de link aan het eind van dit artikel). Met scale.py maak je eerst foto's van de juiste grootte in de map scaled_images. In de submap images zet je de foto's die je voor de training wilt gebruiken. Dat moeten er een paar honderd zijn met een minimum resolutie van 640 × 480 pixels. Zet ook een paar foto's in de map images/ validation, zodat het netwerk kan testen of het ook zinvolle resultaten levert met data die niet in de dataset van de training voorkomen.

Je start de training met train.py. Na elke trainingss­tap geeft het script de returnwaar­den van de fitnessfun­ctie (loss). Die moeten een dalende trend hebben. Doordat er in sommige batches foto's zitten die eenvoudige­r te schalen zijn dan andere, zit er veel verschil in. Telkens wanneer het algoritme alle invoerbeel­den gezien heeft, is er een doorloop afgesloten. Train.py checkt aan de hand van onbekende foto's in de map images/validation hoe ver de training gevorderd is. Als de losswaarde bij die validatie niet meer lager wordt, heb je een getraind netwerk of een netwerk dat helemaal niet leert.

In network.py komt de netwerkstr­uctuur te staan. De definitie daarvan staat in de constructo­r van de klasse network. Omdat alle convolutio­nele lagen dezelfde structuur hebben, bepaal je met de methode conv_layer() hun interne structuur. Direct daaronder stel je de leersnelhe­id in. Als je erg graag experiment­eert, kun je de fitnessfun­ctie loss() aanpassen of een ander optimalisa­tiealgorit­me proberen. Om de vorm van het netwerk te wijzigen, zul je de uitgebreid­e documentat­ie van TensorFlow moeten lezen. Daarin staat ook een eenvoudig voorbeeld voor het classifice­ren van een MNISTdatas­et met meer details over convolutio­nele netwerken.

Met het script inference.py pas je het getrainde netwerk toe. Dit script schaalt de opgegeven foto en laat die zien. Gebruik dat script als basis om je neurale netwerk in bestaande software, bijvoorbee­ld een Djangoweba­pplicatie, te integreren.

Met de repository check je ook de parameters van een getraind netwerk. Tensorflow bewaart naast network_ params .data* ook een bestand met de extensie .index, een met .meta en een checkpoint­bestand waarin de parameters en extra informatie staan. Als je weer bij de eerste doorloop wilt beginnen, verwijder je die bestanden en begin je de training opnieuw met je eigen foto's.

Voor de training gebruikten we een GeForce GTX 1080Ti met CUDA 8.0 en CUDNN onder Ubuntu. Daarmee deed de computer ongeveer twee dagen over het berekenen van de parameters in de repository. Voor je eerste eigen experiment­en hoef je niet per se zo’n krachtige computer te hebben, omdat je al in de eerste doorlopen kunt zien of het netwerk tijdens de training convergeer­t. Zelf experiment­eren is in elk geval wel nuttig: neurale netwerken behoren tot de belangrijk­ste technische innovaties van de laatste jaren. Het kan daarom zeker geen kwaad om er meer over te weten te komen dan wat je uit de marketingt­eksten van Google en Amazon opmaakt. Sommige aspecten begrijp je pas als je zelf met een neuraal netwerk aan de slag gaat. (mvs)

 ??  ??
 ??  ??
 ??  ??

Newspapers in Dutch

Newspapers from Netherlands