Ga naar hoofdinhoud

TensorFlow-tutorial voor beginners

Leer hoe je een neuraal netwerk bouwt en hoe je het traint, evalueert en optimaliseert met TensorFlow
Bijgewerkt 2 okt 2026  · 15 min lezen

Verken met AI

ChatGPTClaudePerplexity

graphic

Deep learning is een deelgebied van machine learning en is een reeks algoritmes die geïnspireerd zijn op de structuur en werking van het brein.

TensorFlow is het tweede machine learning-framework dat Google heeft gemaakt en gebruikt om deep learning-modellen te ontwerpen, bouwen en trainen. Je kunt de TensorFlow-bibliotheek gebruiken om numerieke berekeningen uit te voeren. Op zich klinkt dat niet heel bijzonder, maar deze berekeningen worden gedaan met dataflowgrafen. In deze grafen vertegenwoordigen knooppunten wiskundige operaties, terwijl de randen de data voorstellen, meestal multidimensionale data-arrays of tensors, die tussen deze randen worden gecommuniceerd.

Zie je? De naam “TensorFlow” is afgeleid van de bewerkingen die neurale netwerken uitvoeren op multidimensionale data-arrays of tensors! Het is letterlijk een flow van tensors. Voor nu is dit alles wat je moet weten over tensors, maar je gaat hier in de volgende secties dieper op in!

De TensorFlow-tutorial van vandaag voor beginners laat je op een interactieve manier kennismaken met deep learning uitvoeren:

Download het notebook van deze tutorial hier.

Misschien ben je ook geïnteresseerd in een cursus over Deep Learning in Python, DataCamp’s Keras-tutorial of de Keras met R-tutorial.

Introductie tot tensors

Om tensors goed te begrijpen, is het handig om wat basiskennis te hebben van lineaire algebra en vectorrekening. Je las al in de inleiding dat tensors in TensorFlow zijn geïmplementeerd als multidimensionale data-arrays, maar er is misschien wat meer introductie nodig om tensors en hun gebruik in machine learning volledig te begrijpen.

Vlakke vectoren

Voordat je in vlakke vectoren duikt, is het een goed idee om kort het concept “vectoren” te herhalen; Vectoren zijn speciale soorten matrices, die rechthoekige arrays van getallen zijn. Omdat vectoren geordende verzamelingen van getallen zijn, worden ze vaak gezien als kolommatrices: ze hebben maar één kolom en een bepaald aantal rijen. Anders gezegd kun je vectoren ook beschouwen als scalairen met een richting.

Onthoud: een voorbeeld van een scalair is “5 meter” of “60 m/sec”, terwijl een vector bijvoorbeeld “5 meter noord” of “60 m/sec oost” is. Het verschil tussen deze twee is uiteraard dat de vector een richting heeft. Toch lijken de voorbeelden die je tot nu toe hebt gezien misschien ver af te staan van de vectoren die je tegenkomt als je met machine learning-problemen werkt. Dat is normaal; De lengte van een wiskundige vector is een puur getal: die is absoluut. De richting daarentegen is relatief: die wordt gemeten ten opzichte van een referentierichting en heeft eenheid radialen of graden. Meestal ga je ervan uit dat de richting positief is en tegen de klok in gemeten vanaf de referentierichting.

vector

Visueel stel je vectoren natuurlijk voor als pijlen, zoals je in de afbeelding hierboven ziet. Dit betekent dat je vectoren ook kunt zien als pijlen met richting en lengte. De richting wordt aangegeven door de punt van de pijl, terwijl de lengte wordt weergegeven door de lengte van de pijl.

Hoe zit het dan met vlakke vectoren?

Vlakke vectoren zijn de meest eenvoudige opzet van tensors. Ze lijken sterk op gewone vectoren zoals je die hierboven hebt gezien, met als enig verschil dat ze zich in een vectorruimte bevinden. Om dit beter te begrijpen, beginnen we met een voorbeeld: je hebt een vector die 2 X 1 is. Dit betekent dat de vector behoort tot de verzameling reële getallen die per twee samengaan. Of, anders gezegd, ze maken deel uit van de tweedimensionale ruimte. In zulke gevallen kun je vectoren op het coördinatenvlak (x,y) voorstellen met pijlen of stralen.

Werkend vanuit dit coördinatenvlak in een standaardpositie waar vectoren hun eindpunt hebben in de oorsprong (0,0), kun je de x-coördinaat afleiden door naar de eerste rij van de vector te kijken, terwijl je de y-coördinaat in de tweede rij vindt. Deze standaardpositie hoeft natuurlijk niet altijd aangehouden te worden: vectoren kunnen zich parallel aan zichzelf verplaatsen in het vlak zonder te veranderen.

Let op dat je op vergelijkbare wijze, voor vectoren van grootte 3 X 1, spreekt over de driedimensionale ruimte. Je kunt de vector voorstellen als een driedimensionale figuur met pijlen die wijzen naar posities in de vectorruimte: ze worden getekend op de standaard-assen x, y en z.

Het is mooi om deze vectoren te hebben en op het coördinatenvlak voor te stellen, maar in essentie heb je deze vectoren zodat je er bewerkingen op kunt uitvoeren. Iets wat je daarbij kan helpen is je vectoren uitdrukken als basissen of eenheidsvectoren.

Eenheidsvectoren zijn vectoren met een lengte van één. Je herkent de eenheidsvector vaak aan een kleine letter met een dakje (circumflex). Eenheidsvectoren komen goed van pas als je een 2D- of 3D-vector wilt uitdrukken als som van twee of drie orthogonale componenten, zoals de x- en y-assen, of de z-as.

En wanneer je het hebt over het uitdrukken van één vector, bijvoorbeeld als sommen van componenten, zie je dat je het hebt over componentvectoren, die twee of meer vectoren zijn waarvan de som die gegeven vector is.

Tip: bekijk deze video, die uitlegt wat tensors zijn met behulp van eenvoudige huishoudelijke objecten!

Tensors

Naar naast vlakke vectoren zijn ook covectoren en lineaire operatoren twee andere gevallen die alle drie één ding gemeen hebben: het zijn specifieke gevallen van tensors. Je herinnert je nog hoe een vector in de vorige sectie werd gekarakteriseerd als scalairen met een richting. Een tensor is dan de wiskundige representatie van een fysische entiteit die kan worden gekarakteriseerd door een grootte en meerdere richtingen.

En net zoals je een scalair voorstelt met één getal en een vector bijvoorbeeld met een reeks van drie getallen in een driedimensionale ruimte, kan een tensor worden voorgesteld door een array van 3R getallen in een driedimensionale ruimte.

De “R” in deze notatie stelt de rang van de tensor voor: dit betekent dat in een driedimensionale ruimte een tensor van de tweede rang kan worden voorgesteld door 3 tot de macht 2 of 9 getallen. In een N-dimensionale ruimte hebben scalairen nog steeds slechts één getal nodig, vectoren N getallen en tensors N^R getallen. Dit verklaart waarom je vaak hoort dat scalairen tensors van rang 0 zijn: omdat ze geen richting hebben, kun je ze met één getal weergeven.

Met dit in het achterhoofd is het relatief eenvoudig om scalairen, vectoren en tensors te herkennen en van elkaar te onderscheiden: scalairen kun je voorstellen met één enkel getal, vectoren met een geordende set getallen en tensors met een array van getallen.

Wat tensors zo uniek maakt, is de combinatie van componenten en basisvectoren: basisvectoren transformeren op een bepaalde manier tussen referentiekaders en de componenten transformeren precies zo dat de combinatie tussen componenten en basisvectoren gelijk blijft.

TensorFlow installeren

Nu je meer weet over TensorFlow, is het tijd om te beginnen en de bibliotheek te installeren. Het is goed om te weten dat TensorFlow API’s biedt voor Python, C++, Haskell, Java, Go, Rust en dat er ook een third-party package voor R is genaamd tensorflow.

Tip: als je meer wilt weten over deep learning-packages in R, bekijk dan DataCamp’s keras: Deep Learning in R Tutorial.

In deze tutorial download je een versie van TensorFlow waarmee je de code voor je deep learning-project in Python kunt schrijven. Op de TensorFlow-installatiepagina zie je enkele van de meest gebruikte manieren en nieuwste instructies om TensorFlow te installeren met virtualenv, pip, Docker en tot slot zijn er ook nog andere manieren om TensorFlow op je computer te installeren.

Let op Je kunt TensorFlow ook installeren met Conda als je op Windows werkt. Aangezien de installatie van TensorFlow echter door de community wordt ondersteund, kun je het beste de officiële installatie-instructies raadplegen.

Nu je het installatieproces hebt doorlopen, is het tijd om te controleren of je TensorFlow correct hebt geïnstalleerd door het in je workspace te importeren onder het alias tf:

import tensorflow as tf

Let op dat het alias dat je hierboven gebruikt, een soort conventie is – Het wordt gebruikt om ervoor te zorgen dat je consistent blijft met andere ontwikkelaars die TensorFlow gebruiken in data science-projecten enerzijds, en met open-source TensorFlow-projecten anderzijds.

Aan de slag met TensorFlow: basis

Je schrijft over het algemeen TensorFlow-programma’s die je als één geheel draait; Dit lijkt op het eerste gezicht wat tegenstrijdig wanneer je met Python werkt. Als je wilt, kun je echter ook de Interactive Session van TensorFlow gebruiken om interactiever met de bibliotheek te werken. Dit is vooral handig als je gewend bent aan IPython.

Voor deze tutorial focus je op de tweede optie: dit helpt je om snel te starten met deep learning in TensorFlow. Maar voordat je hier verder op ingaat, proberen we eerst wat kleins voordat je aan het zwaardere werk begint.

Importeer eerst de tensorflow-bibliotheek onder het alias tf, zoals je in de vorige sectie hebt gezien. Initialiseer vervolgens twee variabelen die eigenlijk constanten zijn. Geef een array van vier getallen door aan de functie constant().

Let op dat je ook een integer zou kunnen doorgeven, maar meestal werk je met arrays. Zoals je in de inleiding zag, draait het bij tensors allemaal om arrays! Zorg dus dat je een array doorgeeft :) Vervolgens kun je multiply() gebruiken om je twee variabelen te vermenigvuldigen. Sla het resultaat op in de variabele result. Print ten slotte de result met de functie print().

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgSW1wb3J0IGB0ZW5zb3JmbG93YFxuaW1wb3J0IHRlbnNvcmZsb3cgYXMgdGZcblxuIyBJbml0aWFsaXplIHR3byBjb25zdGFudHNcbngxID0gdGYuY29uc3RhbnQoWzEsMiwzLDRdKVxueDIgPSB0Zi5jb25zdGFudChbNSw2LDcsOF0pXG5cbiMgTXVsdGlwbHlcbnJlc3VsdCA9IHRmLm11bHRpcGx5KHgxLCB4MilcblxuIyBQcmludCB0aGUgcmVzdWx0XG5wcmludChyZXN1bHQpIn0=

Let op dat je in de DataCamp Light-codechunk hierboven constanten hebt gedefinieerd. Er zijn echter twee andere soorten waarden die je mogelijk kunt gebruiken, namelijk placeholders, waarden die niet toegewezen zijn en die door de sessie worden geïnitialiseerd wanneer je die draait. Zoals de naam al aangeeft, is het gewoon een placeholder voor een tensor die altijd wordt gevoed wanneer de sessie wordt uitgevoerd; Er zijn ook Variables, waarden die kunnen veranderen. De constanten zijn, zoals je misschien al had begrepen, waarden die niet veranderen.

Het resultaat van de code is een abstracte tensor in de rekengrafiek. Maar in tegenstelling tot wat je misschien verwacht, wordt de result niet echt berekend. Je hebt alleen het model gedefinieerd, maar er is geen proces uitgevoerd om het resultaat te berekenen. Dat zie je in de print: er is niet echt het resultaat dat je wilt zien (namelijk 30). Dit betekent dat TensorFlow lui evalueert!

Als je het resultaat toch wilt zien, moet je deze code draaien in een interactieve sessie. Dat kan op een paar manieren, zoals wordt gedemonstreerd in de DataCamp Light-codechunks hieronder:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgSW1wb3J0IGB0ZW5zb3JmbG93YCBcbmltcG9ydCB0ZW5zb3JmbG93IGFzIHRmXG5cbiMgSW5pdGlhbGl6ZSB0d28gY29uc3RhbnRzXG54MSA9IHRmLmNvbnN0YW50KFsxLDIsMyw0XSlcbngyID0gdGYuY29uc3RhbnQoWzUsNiw3LDhdKVxuXG4jIE11bHRpcGx5XG5yZXN1bHQgPSB0Zi5tdWx0aXBseSh4MSwgeDIpXG5cbiMgSW50aWFsaXplIHRoZSBTZXNzaW9uXG5zZXNzID0gdGYuU2Vzc2lvbigpXG5cbiMgUHJpbnQgdGhlIHJlc3VsdFxucHJpbnQoc2Vzcy5ydW4ocmVzdWx0KSlcblxuIyBDbG9zZSB0aGUgc2Vzc2lvblxuc2Vzcy5jbG9zZSgpIn0=

Let op dat je ook de volgende regels code kunt gebruiken om een interactieve sessie te starten, de result te runnen en de sessie automatisch weer te sluiten na het printen van de output:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInNhbXBsZSI6IiMgSW1wb3J0IGB0ZW5zb3JmbG93YFxuaW1wb3J0IHRlbnNvcmZsb3cgYXMgdGZcblxuIyBJbml0aWFsaXplIHR3byBjb25zdGFudHNcbngxID0gdGYuY29uc3RhbnQoWzEsMiwzLDRdKVxueDIgPSB0Zi5jb25zdGFudChbNSw2LDcsOF0pXG5cbiMgTXVsdGlwbHlcbnJlc3VsdCA9IHRmLm11bHRpcGx5KHgxLCB4MilcblxuIyBJbml0aWFsaXplIFNlc3Npb24gYW5kIHJ1biBgcmVzdWx0YFxud2l0aCB0Zi5TZXNzaW9uKCkgYXMgc2VzczpcbiAgb3V0cHV0ID0gc2Vzcy5ydW4ocmVzdWx0KVxuICBwcmludChvdXRwdXQpIn0=

In de codechunks hierboven heb je zojuist een standaard sessie gedefinieerd, maar het is ook goed om te weten dat je ook opties kunt meegeven. Je kunt bijvoorbeeld het argument config specificeren en vervolgens het ConfigProto-protocolbuffer gebruiken om configuratieopties voor je sessie toe te voegen.

Als je bijvoorbeeld

config=tf.ConfigProto(log_device_placement=True)

aan je sessie toevoegt, zorg je ervoor dat je het GPU- of CPU-apparaat logt dat aan een bewerking is toegewezen. Je krijgt dan informatie over welke apparaten in de sessie voor elke bewerking worden gebruikt. Je zou de volgende configuratiesessie ook kunnen gebruiken, bijvoorbeeld wanneer je soft constraints voor de apparaatplaatsing gebruikt:

config=tf.ConfigProto(allow_soft_placement=True)

Nu je TensorFlow hebt geïnstalleerd en in je workspace hebt geïmporteerd en je de basis van het werken met dit pakket hebt doorgenomen, is het tijd om dit even te laten voor wat het is en je aandacht op je data te richten. Zoals altijd neem je eerst de tijd om je data te verkennen en beter te begrijpen voordat je je neurale netwerk gaat modelleren.

Belgische verkeersborden: achtergrond

Hoewel verkeer een onderwerp is dat jullie allemaal doorgaans kennen, kan het geen kwaad om kort de observaties in deze dataset door te nemen om te zien of je alles begrijpt voordat je begint. In wezen krijg je in deze sectie de domeinkennis die je nodig hebt om verder te gaan met deze tutorial.

Natuurlijk, omdat ik Belg ben, zorg ik ervoor dat je ook wat anekdotes krijgt :)

  • Belgische verkeersborden zijn meestal in het Nederlands en Frans. Dit is goed om te weten, maar voor de dataset waarmee je werkt is het niet heel belangrijk!
  • Er zijn zes categorieën verkeersborden in België: waarschuwingsborden, voorrangsborden, verbodsborden, gebodsborden, borden met betrekking tot parkeren en stilstaan op de weg en tot slot aanwijzingsborden.
  • Op 1 januari 2017 zijn meer dan 30.000 verkeersborden verwijderd van de Belgische wegen. Dit waren allemaal verbodsborden met betrekking tot snelheid.
  • Over verwijderen gesproken: de overweldigende aanwezigheid van verkeersborden is een voortdurende discussie in België (en bij uitbreiding de hele Europese Unie).

Data laden en verkennen

Nu je wat meer achtergrondinformatie hebt verzameld, is het tijd om de dataset hier te downloaden. Je zou de twee zip-bestanden moeten krijgen die naast "BelgiumTS for Classification (cropped images)" staan, namelijk "BelgiumTSC_Training" en "BelgiumTSC_Testing".

Tip: als je de bestanden hebt gedownload of dit na het voltooien van deze tutorial doet, bekijk dan de mapstructuur van de data die je hebt gedownload! Je ziet dat zowel de test- als de trainingsmappen 61 submappen bevatten, wat de 62 soorten verkeersborden zijn die je in deze tutorial voor classificatie gebruikt. Daarnaast hebben de bestanden de extensie .ppm of Portable Pixmap Format. Je hebt afbeeldingen van de verkeersborden gedownload!

Laten we beginnen met het importeren van de data in je workspace. We beginnen met de code onder de user-defined function (UDF) load_data():

  • Stel eerst je ROOT_PATH in. Dit pad is waar je de map met je trainings- en testdata hebt aangemaakt.
  • Vervolgens kun je de specifieke paden aan je ROOT_PATH toevoegen met behulp van de functie join(). Je slaat deze twee specifieke paden op in train_data_directory en test_data_directory.
  • Je ziet dat je daarna de functie load_data() kunt aanroepen en de train_data_directory eraan kunt doorgeven.
  • De functie load_data() zelf begint met het verzamelen van alle submappen die aanwezig zijn in de train_data_directory; Dit doet ze met behulp van list comprehension, wat een vrij natuurlijke manier is om lijsten te construeren – het zegt in feite dat, als je iets vindt in de train_data_directory, je dubbel controleert of dit een map is en als dat zo is, voeg je die toe aan je lijst. Onthoud dat elke submap een label vertegenwoordigt.
  • Vervolgens moet je door de submappen loopen. Je initialiseert eerst twee lijsten, labels en images. Daarna verzamel je de paden van de submappen en de bestandsnamen van de afbeeldingen die in deze submappen zijn opgeslagen. Vervolgens kun je de data verzamelen in de twee lijsten met behulp van de functie append().
def load_data(data_directory):
    directories = [d for d in os.listdir(data_directory) 
                   if os.path.isdir(os.path.join(data_directory, d))]
    labels = []
    images = []
    for d in directories:
        label_directory = os.path.join(data_directory, d)
        file_names = [os.path.join(label_directory, f) 
                      for f in os.listdir(label_directory) 
                      if f.endswith(".ppm")]
        for f in file_names:
            images.append(skimage.data.imread(f))
            labels.append(int(d))
    return images, labels

ROOT_PATH = "/your/root/path"
train_data_directory = os.path.join(ROOT_PATH, "TrafficSigns/Training")
test_data_directory = os.path.join(ROOT_PATH, "TrafficSigns/Testing")

images, labels = load_data(train_data_directory)

Let op dat in de bovenstaande codechunk de trainings- en testdata zich bevinden in mappen met de naam "Training" en "Testing", die beide submappen zijn van een andere map "TrafficSigns". Op een lokale machine kan dit er uitzien als "/Users/Name/Downloads/TrafficSigns", met twee submappen genaamd "Training" en "Testing".

Tip: herhaal hoe je functies schrijft in Python met DataCamp’s Python Functions Tutorial.

Verkeersbordstatistieken

Nu je data is geladen, is het tijd voor wat datainspectie! Je kunt beginnen met een vrij eenvoudige analyse met behulp van de attributen ndim en size van de array images:

Let op dat de variabelen images en labels lijsten zijn, dus je moet mogelijk np.array() gebruiken om de variabelen in je eigen workspace naar een array te converteren. Dat is hier voor je gedaan!

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IG51bXB5IGFzIG5wXG5pbXBvcnQgaW9cbmltcG9ydCB1cmxsaWJcbnVybF9pbWdzID0gXCJodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYXNzZXRzLmRhdGFjYW1wLmNvbS9ibG9nX2Fzc2V0cy9pbWFnZXMubnB6XCJcbmltZ3MgPSBucC5sb2FkKGlvLkJ5dGVzSU8odXJsbGliLnJlcXVlc3QudXJsb3Blbih1cmxfaW1ncykucmVhZCgpKSlcbmltYWdlcyA9IGltZ3NbXCJhcnJfMFwiXSIsInNhbXBsZSI6IiMgUHJpbnQgdGhlIGBpbWFnZXNgIGRpbWVuc2lvbnNcbnByaW50KGltYWdlcy5uZGltKVxuXG4jIFByaW50IHRoZSBudW1iZXIgb2YgYGltYWdlc2AncyBlbGVtZW50c1xucHJpbnQoaW1hZ2VzLnNpemUpXG5cbiMgUHJpbnQgdGhlIGZpcnN0IGluc3RhbmNlIG9mIGBpbWFnZXNgXG5pbWFnZXNbMF0ifQ==

Let op dat de images[0] die je hebt geprint in feite één enkele afbeelding is die wordt weergegeven door arrays in arrays! Dit lijkt in het begin misschien contra-intuïtief, maar je raakt hieraan gewend naarmate je meer met afbeeldingen werkt in machine learning- of deep learning-toepassingen.

Vervolgens kun je ook even naar de labels kijken, maar op dit punt zou je niet al te veel verrassingen moeten zien:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IG51bXB5IGFzIG5wXG5pbXBvcnQgaW9cbmltcG9ydCB1cmxsaWJcbnVybF9sYWJlbHMgPSBcImh0dHBzOi8vczMuYW1hem9uYXdzLmNvbS9hc3NldHMuZGF0YWNhbXAuY29tL2Jsb2dfYXNzZXRzL2xhYmVscy50eHRcIlxucmF3X2xhYmVscyA9IHVybGxpYi5yZXF1ZXN0LnVybG9wZW4odXJsX2xhYmVscylcbmxhYmVscyA9IG5wLmxvYWR0eHQocmF3X2xhYmVscywgZGVsaW1pdGVyPVwiLFwiKSIsInNhbXBsZSI6IiMgUHJpbnQgdGhlIGBsYWJlbHNgIGRpbWVuc2lvbnNcbnByaW50KGxhYmVscy5uZGltKVxuXG4jIFByaW50IHRoZSBudW1iZXIgb2YgYGxhYmVsc2AncyBlbGVtZW50c1xucHJpbnQobGFiZWxzLnNpemUpXG5cbiMgQ291bnQgdGhlIG51bWJlciBvZiBsYWJlbHNcbnByaW50KGxlbihzZXQobGFiZWxzKSkpIn0=

Deze getallen geven je al wat inzicht in hoe succesvol je import was en de exacte omvang van je data. Op het eerste gezicht is alles uitgevoerd zoals verwacht en zie je dat de grootte van de array aanzienlijk is als je bedenkt dat je met arrays in arrays te maken hebt.

Tip probeer de volgende attributen toe te voegen aan je arrays om meer informatie te krijgen over de geheugenlay-out, de lengte van één array-element in bytes en het totaal verbruikte aantal bytes door de elementen van de array met de attributen flags, itemsize en nbytes. Je kunt dit uitproberen in de IPython-console in de DataCamp Light-chunk hierboven!

Vervolgens kun je ook kijken naar de verdeling van de verkeersborden:

eyJsYW5ndWFnZSI6InB5dGhvbiIsInByZV9leGVyY2lzZV9jb2RlIjoiaW1wb3J0IG51bXB5IGFzIG5wXG5pbXBvcnQgdXJsbGliXG51cmxfbGFiZWxzID0gXCJodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYXNzZXRzLmRhdGFjYW1wLmNvbS9ibG9nX2Fzc2V0cy9sYWJlbHMudHh0XCJcbnJhd19sYWJlbHMgPSB1cmxsaWIucmVxdWVzdC51cmxvcGVuKHVybF9sYWJlbHMpXG5sYWJlbHMgPSBucC5sb2FkdHh0KHJhd19sYWJlbHMsIGRlbGltaXRlcj1cIixcIikiLCJzYW1wbGUiOiIjIEltcG9ydCB0aGUgYHB5cGxvdGAgbW9kdWxlXG5pbXBvcnQgbWF0cGxvdGxpYi5weXBsb3QgYXMgcGx0IFxuXG4jIE1ha2UgYSBoaXN0b2dyYW0gd2l0aCA2MiBiaW5zIG9mIHRoZSBgbGFiZWxzYCBkYXRhXG5wbHQuaGlzdChsYWJlbHMsIDYyKVxuXG4jIFNob3cgdGhlIHBsb3RcbnBsdC5zaG93KCkifQ==

Goed bezig! Laten we nu eens nader kijken naar het histogram dat je hebt gemaakt!

distribution of traffic sign labels

Je ziet duidelijk dat niet alle typen verkeersborden even sterk vertegenwoordigd zijn in de dataset. Dit is iets waar je later mee aan de slag gaat wanneer je de data manipuleert voordat je je neurale netwerk gaat modelleren.

Op het eerste gezicht zie je dat er labels zijn die sterker aanwezig zijn in de dataset dan andere: de labels 22, 32, 38 en 61 springen er zeker uit. Op dit moment is het goed om dit te onthouden, maar je gaat hier in de volgende sectie zeker verder op in!

De verkeersborden visualiseren

De vorige, kleine analyses of checks hebben je al enig idee gegeven van de data waarmee je werkt, maar wanneer je data voornamelijk uit afbeeldingen bestaat, is de stap die je zou moeten zetten om je data te verkennen het visualiseren ervan.

Laten we enkele willekeurige verkeersborden bekijken:

  • Zorg er eerst voor dat je de module pyplot van het pakket matplotlib importeert onder het gangbare alias plt.
  • Vervolgens ga je een lijst maken met 4 willekeurige getallen. Deze gebruik je om verkeersborden te selecteren uit de array images die je zojuist in de vorige sectie hebt bekeken. In dit geval kies je 300, 2250, 3650 en 4000.
  • Daarna zeg je dat je voor elk element in de lengte van die lijst, dus van 0 tot 4, subplots gaat maken zonder assen (zodat die niet alle aandacht opeisen en je focus volledig op de afbeeldingen ligt!). In deze subplots laat je een specifieke afbeelding zien uit de array images die overeenkomt met het getal op index i. In de eerste loop geef je 300 door aan images[], in de tweede ronde 2250, enzovoort. Tot slot pas je de subplots aan zodat er genoeg ruimte tussen zit.
  • Het laatste wat overblijft is je plot tonen met de functie show()!

Daar gaan we:

# Import the `pyplot` module of `matplotlib`
import matplotlib.pyplot as plt

# Determine the (random) indexes of the images that you want to see 
traffic_signs = [300, 2250, 3650, 4000]

# Fill out the subplots with the random images that you defined 
for i in range(len(traffic_signs)):
    plt.subplot(1, 4, i+1)
    plt.axis('off')
    plt.imshow(images[traffic_signs[i]])
    plt.subplots_adjust(wspace=0.5)

plt.show()

Zoals je al vermoedde aan de 62 labels die in deze dataset zijn opgenomen, verschillen de borden van elkaar.

Maar wat valt je nog meer op? Kijk nog eens goed naar de onderstaande afbeeldingen:

traffic signs

Deze vier afbeeldingen hebben niet hetzelfde formaat!

Je kunt natuurlijk spelen met de getallen in de lijst traffic_signs en deze observatie grondiger volgen, maar hoe dan ook is dit een belangrijke constatering waarmee je rekening moet houden wanneer je je data gaat manipuleren zodat je die aan het neurale netwerk kunt voeren.

Laten we de hypothese van de verschillende groottes bevestigen door de shape, de minimale en maximale waarden te printen van de specifieke afbeeldingen die je in de subplots hebt opgenomen.

De onderstaande code lijkt sterk op die waarmee je hierboven de 4 willekeurige afbeeldingen hebt geplot, maar verschilt doordat je hier afwisselend groottes en afbeeldingen toont in plaats van alleen de afbeeldingen naast elkaar te plotten:

# Import `matplotlib`
import matplotlib.pyplot as plt

# Determine the (random) indexes of the images
traffic_signs = [300, 2250, 3650, 4000]

# Fill out the subplots with the random images and add shape, min and max values
for i in range(len(traffic_signs)):
    plt.subplot(1, 4, i+1)
    plt.axis('off')
    plt.imshow(images[traffic_signs[i]])
    plt.subplots_adjust(wspace=0.5)
    plt.show()
    print("shape: {0}, min: {1}, max: {2}".format(images[traffic_signs[i]].shape, 
                                                  images[traffic_signs[i]].min(), 
                                                  images[traffic_signs[i]].max()))

Let op hoe je de methode format() gebruikt op de string "shape: {0}, min: {1}, max: {2}" om de argumenten {0}, {1} en {2} in te vullen die je hebt gedefinieerd.

traffic signs 2

Nu je losse afbeeldingen hebt gezien, wil je misschien ook terugkomen op het histogram dat je in de eerste stappen van je data-exploratie hebt geprint; Je kunt dit eenvoudig doen door een overzicht te plotten van alle 62 klassen en één afbeelding die bij elke klasse hoort:

# Import the `pyplot` module as `plt`
import matplotlib.pyplot as plt 

# Get the unique labels 
unique_labels = set(labels)

# Initialize the figure
plt.figure(figsize=(15, 15))

# Set a counter
i = 1

# For each unique label,
for label in unique_labels:
    # You pick the first image for each label
    image = images[labels.index(label)]
    # Define 64 subplots 
    plt.subplot(8, 8, i)
    # Don't include axes
    plt.axis('off')
    # Add a title to each subplot 
    plt.title("Label {0} ({1})".format(label, labels.count(label)))
    # Add 1 to the counter
    i += 1
    # And you plot this first image 
    plt.imshow(image)
    
# Show the plot
plt.show()

Let op dat hoewel je 64 subplots definieert, niet al deze subplots afbeeldingen zullen tonen (er zijn immers maar 62 labels!). Let er ook op dat je opnieuw geen assen toevoegt om ervoor te zorgen dat de aandacht van de lezers niet ver afdwaalt van het hoofdonderwerp: de verkeersborden!

traffic signs 3

Zoals je in het histogram hierboven al vermoedde, zijn er aanzienlijk meer verkeersborden met labels 22, 32, 38 en 61. Deze hypothese wordt nu bevestigd in deze plot: je ziet dat er 375 instanties met label 22 zijn, 316 met label 32, 285 met label 38 en tot slot 282 met label 61.

Eén van de interessantste vragen die je jezelf nu zou kunnen stellen, is of er een verband is tussen al deze instanties – misschien zijn het allemaal aanwijzingsborden?

Laten we eens beter kijken: je ziet dat label 22 en 32 verbodsborden zijn, maar dat labels 38 en 61 respectievelijk aanwijzings- en voorrangsborden zijn. Dit betekent dat er niet meteen een verband is tussen deze vier, behalve dat de helft van de borden die sterk aanwezig zijn in de dataset van het type verbodsbord is.

explore datacamp's python course library banner

Feature-extractie

Nu je je data grondig hebt verkend, is het tijd om je handen vuil te maken! Laten we kort samenvatten wat je hebt ontdekt om ervoor te zorgen dat je geen stappen vergeet bij de manipulatie:

  • De grootte van de afbeeldingen was ongelijk;
  • Er zijn 62 labels of targetwaarden (omdat je labels bij 0 beginnen en eindigen bij 61);
  • De verdeling van de verkeersbordwaarden is behoorlijk ongelijk; Er was niet echt een verband tussen de borden die sterk aanwezig waren in de dataset.

Nu je een duidelijk idee hebt van wat je moet verbeteren, kun je beginnen met het manipuleren van je data zodat die klaar is om aan het neurale netwerk of welk model dan ook gevoerd te worden. Laten we eerst beginnen met het extraheren van enkele features – je gaat de afbeeldingen reschalen en je converteert de afbeeldingen in de array images naar grijswaarden. Je doet deze kleurconversie vooral omdat kleur minder uitmaakt bij classificatievragen zoals die je nu probeert te beantwoorden. Voor detectie speelt kleur echter wel een grote rol! In die gevallen is de conversie dus niet nodig!

Afbeeldingen reschalen

Om de verschillende afbeeldingsgroottes aan te pakken, ga je de afbeeldingen reschalen; Dit kun je eenvoudig doen met behulp van de bibliotheek skimage of Scikit-Image, een verzameling algoritmes voor beeldverwerking.

In dit geval is de module transform handig, omdat die een functie resize() biedt; Je ziet dat je (opnieuw!) list comprehension gebruikt om elke afbeelding naar 28 bij 28 pixels te resizen. Je ziet opnieuw de manier waarop je de lijst vormt: voor elke afbeelding die je vindt in de array images, voer je de transformatie uit die je leent van de bibliotheek skimage. Ten slotte sla je het resultaat op in de variabele images28:

# Import the `transform` module from `skimage`
from skimage import transform 

# Rescale the images in the `images` array
images28 = [transform.resize(image, (28, 28)) for image in images]

Dat was vrij eenvoudig, toch?

Let op dat de afbeeldingen nu vierdimensionaal zijn: als je images28 naar een array converteert en het attribuut shape eraan toevoegt, zie je dat de print aangeeft dat de dimensies van images28 (4575, 28, 28, 3) zijn. De afbeeldingen zijn 784-dimensionaal (omdat je afbeeldingen 28 bij 28 pixels zijn).

Je kunt het resultaat van de rescaling controleren door de code te hergebruiken die je hierboven gebruikte om de 4 willekeurige afbeeldingen te plotten met behulp van de variabele traffic_signs. Vergeet alleen niet om alle verwijzingen naar images te wijzigen in images28.

Bekijk hier het resultaat:

4 random images

Let op dat doordat je hebt gerescaled, je min- en max-waarden ook zijn veranderd; Ze lijken nu allemaal in dezelfde bereiken te liggen, wat erg fijn is, want dan hoef je je data niet per se te normaliseren!

Afbeeldingen converteren naar grijswaarden

Zoals gezegd in de inleiding van deze sectie van de tutorial, is de kleur in de afbeeldingen minder belangrijk wanneer je een classificatievraag probeert te beantwoorden. Daarom ga je de afbeeldingen ook omzetten naar grijswaarden.

Let op dat je ook zelf kunt testen wat er met de uiteindelijke resultaten van je model gebeurt als je deze specifieke stap overslaat.

Net als bij het reschalen kun je opnieuw rekenen op de Scikit-Image-bibliotheek; In dit geval heb je de module color met de functie rgb2gray() nodig om te komen waar je moet zijn.

Dat wordt lekker makkelijk!

Vergeet echter niet om de variabele images28 terug te converteren naar een array, omdat de functie rgb2gray() een array als argument verwacht.

# Import `rgb2gray` from `skimage.color`
from skimage.color import rgb2gray

# Convert `images28` to an array
images28 = np.array(images28)

# Convert `images28` to grayscale
images28 = rgb2gray(images28)

Controleer het resultaat van je grijswaardeconversie door enkele afbeeldingen te plotten; Ook hier kun je wat code hergebruiken en licht aanpassen om de aangepaste afbeeldingen te tonen:

import matplotlib.pyplot as plt

traffic_signs = [300, 2250, 3650, 4000]

for i in range(len(traffic_signs)):
    plt.subplot(1, 4, i+1)
    plt.axis('off')
    plt.imshow(images28[traffic_signs[i]], cmap="gray")
    plt.subplots_adjust(wspace=0.5)
    
# Show the plot
plt.show()

Let op dat je inderdaad de colormap of cmap moet specificeren en instellen op "gray" om de afbeeldingen in grijswaarden te plotten. Dat komt omdat imshow() standaard, standaard een heatmap-achtige colormap gebruikt. Lees meer hier.

traffic signs 4

Tip: omdat je deze functie in deze tutorial al behoorlijk vaak hebt hergebruikt, kun je eens kijken hoe je er een functie van kunt maken :)

Deze twee stappen zijn heel basaal; Andere bewerkingen die je op je data had kunnen proberen zijn data-augmentatie (roteren, vervagen, verschuiven, helderheid aanpassen,…). Als je wilt, kun je ook een hele pijplijn opzetten van datamanipulatiebewerkingen waar je je afbeeldingen doorheen stuurt.

Deep learning met TensorFlow

Nu je je data hebt verkend en gemanipuleerd, is het tijd om je neurale netwerkarchitectuur te construeren met behulp van het TensorFlow-pakket!

Het neurale netwerk modelleren

Net zoals je misschien met Keras hebt gedaan, is het tijd om je neurale netwerk laag voor laag op te bouwen.

Als je dat nog niet hebt gedaan, importeer dan tensorflow in je workspace onder het conventionele alias tf. Vervolgens kun je de Graph initialiseren met behulp van Graph(). Je gebruikt deze functie om de berekening te definiëren. Let op dat je met de Graph niets berekent, omdat deze geen waarden bevat. Het definieert alleen de bewerkingen die je later wilt uitvoeren.

In dit geval stel je een standaardcontext in met behulp van as_default(), die een contextmanager retourneert die deze specifieke Graph de standaardgrafiek maakt. Je gebruikt deze methode als je meerdere grafieken in hetzelfde proces wilt maken: met deze functie heb je een globale standaardgrafiek waaraan alle bewerkingen worden toegevoegd als je niet expliciet een nieuwe grafiek maakt.

Vervolgens ben je klaar om bewerkingen aan je grafiek toe te voegen. Zoals je je misschien herinnert van werken met Keras, bouw je je model op en definieer je bij het compileren een verliesfunctie, een optimizer en een metriek. Dit gebeurt nu allemaal in één stap wanneer je met TensorFlow werkt:

    • Je definieert eerst placeholders voor inputs en labels, omdat je de “echte” data nog niet invoert. Onthoud dat placeholders waarden zijn die niet zijn toegewezen en die door de sessie worden geïnitialiseerd wanneer je die draait. Dus wanneer je de sessie uiteindelijk draait, krijgen deze placeholders de waarden van je dataset die je doorgeeft in de functie run()!
    • Daarna bouw je het netwerk op. Je begint met het flattenen van de input met de functie flatten(), die je een array geeft van shape [None, 784] in plaats van [None, 28, 28], de shape van je afbeeldingen in grijswaarden.
    • Nadat je de input hebt geflat, construeer je een volledig verbonden laag die logits van grootte [None, 62] genereert. Logits is de functie die werkt op de ongeschaalde output van vorige lagen en die de relatieve schaal gebruikt om de units lineair te begrijpen.
    • Met de multilayer perceptron opgebouwd, kun je de verliesfunctie definiëren. De keuze voor een verliesfunctie hangt af van de taak die je hebt: in dit geval maak je gebruik van
sparse_softmax_cross_entropy_with_logits()
  • Dit berekent sparse softmax cross-entropy tussen logits en labels. Met andere woorden, het meet de waarschijnlijkheidsfout in discrete classificatietaken waarin de klassen onderling uitsluitend zijn. Dit betekent dat elke invoer precies in één klasse valt. Hier kan een verkeersbord slechts één label hebben. Onthoud dat, terwijl regressie wordt gebruikt om continue waarden te voorspellen, classificatie wordt gebruikt om discrete waarden of klassen van datapunten te voorspellen. Je wikkelt deze functie in reduce_mean(), die het gemiddelde van elementen over dimensies van een tensor berekent.
  • Je wilt ook een trainingsoptimizer definiëren; Enkele van de populairste optimalisatie-algoritmes zijn Stochastic Gradient Descent (SGD), ADAM en RMSprop. Afhankelijk van welk algoritme je kiest, moet je bepaalde parameters afstemmen, zoals learning rate of momentum. In dit geval kies je de ADAM-optimizer, waarvoor je de learning rate definieert op 0.001.
  • Tot slot initialiseer je de bewerkingen die moeten worden uitgevoerd voordat je doorgaat naar de training.
# Import `tensorflow` 
import tensorflow as tf 

# Initialize placeholders 
x = tf.placeholder(dtype = tf.float32, shape = [None, 28, 28])
y = tf.placeholder(dtype = tf.int32, shape = [None])

# Flatten the input data
images_flat = tf.contrib.layers.flatten(x)

# Fully connected layer 
logits = tf.contrib.layers.fully_connected(images_flat, 62, tf.nn.relu)

# Define a loss function
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels = y, 
                                                                    logits = logits))
# Define an optimizer 
train_op = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)

# Convert logits to label indexes
correct_pred = tf.argmax(logits, 1)

# Define an accuracy metric
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

Je hebt nu met succes je eerste neurale netwerk met TensorFlow gemaakt!

Als je wilt, kun je ook de waarden van (de meeste van) de variabelen printen om snel te herhalen of te controleren wat je zojuist hebt gecodeerd:

print("images_flat: ", images_flat)
print("logits: ", logits)
print("loss: ", loss)
print("predicted_labels: ", correct_pred)

Tip: als je een fout ziet als “module 'pandas' has no attribute 'computation'”, overweeg dan de package dask te upgraden door pip install --upgrade dask in je commandline te draaien. Zie deze StackOverflow-post voor meer informatie.

Het neurale netwerk draaien

Nu je je model laag voor laag hebt opgebouwd, is het tijd om het daadwerkelijk te draaien! Hiervoor moet je eerst een sessie initialiseren met behulp van Session() waaraan je je graph kunt doorgeven die je in de vorige sectie hebt gedefinieerd. Vervolgens kun je de sessie draaien met run(), waaraan je de geïnitialiseerde bewerkingen doorgeeft in de vorm van de variabele init die je ook in de vorige sectie hebt gedefinieerd.

Vervolgens kun je deze geïnitialiseerde sessie gebruiken om epochs of trainingslussen te starten. In dit geval kies je 201 omdat je de laatste loss_value wilt registreren; In de lus draai je de sessie met de trainingsoptimizer en de verlies- (of nauwkeurigheids-)metriek die je in de vorige sectie hebt gedefinieerd. Je geeft ook een argument feed_dict door, waarmee je data aan het model voert. Na elke 10 epochs krijg je een log die je meer inzicht geeft in het verlies of de kosten van het model.

Zoals je in de sectie over de TensorFlow-basisprincipes hebt gezien, is het niet nodig om de sessie handmatig te sluiten; dit wordt voor je gedaan. Als je echter een andere setup wilt proberen, moet je dat waarschijnlijk wel doen met sess.close() als je je sessie hebt gedefinieerd als sess, zoals in de onderstaande codechunk:

tf.set_random_seed(1234)
sess = tf.Session()

sess.run(tf.global_variables_initializer())

for i in range(201):
        print('EPOCH', i)
        _, accuracy_val = sess.run([train_op, accuracy], feed_dict={x: images28, y: labels})
        if i % 10 == 0:
            print("Loss: ", loss)
        print('DONE WITH EPOCH')

Onthoud dat je ook het volgende stuk code kunt draaien, maar dat sluit de sessie direct daarna, zoals je in de inleiding van deze tutorial zag:

tf.set_random_seed(1234)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(201):
        _, loss_value = sess.run([train_op, loss], feed_dict={x: images28, y: labels})
        if i % 10 == 0:
            print("Loss: ", loss)

Let op dat je gebruikmaakt van global_variables_initializer() omdat de functie initialize_all_variables() is verouderd.

Je hebt je model nu met succes getraind! Dat viel best mee, toch?

Je neurale netwerk evalueren

Je bent er nog niet helemaal; Je moet je neurale netwerk nog evalueren. In dit geval kun je alvast een indruk krijgen van hoe goed je model presteert door 10 willekeurige afbeeldingen te kiezen en de voorspelde labels te vergelijken met de echte labels.

Je kunt ze eerst printen, maar waarom gebruik je niet matplotlib om de verkeersborden zelf te plotten en een visuele vergelijking te maken?

 # Import `matplotlib`
import matplotlib.pyplot as plt
import random

# Pick 10 random images
sample_indexes = random.sample(range(len(images28)), 10)
sample_images = [images28[i] for i in sample_indexes]
sample_labels = [labels[i] for i in sample_indexes]

# Run the "correct_pred" operation
predicted = sess.run([correct_pred], feed_dict={x: sample_images})[0]
                        
# Print the real and predicted labels
print(sample_labels)
print(predicted)

# Display the predictions and the ground truth visually.
fig = plt.figure(figsize=(10, 10))
for i in range(len(sample_images)):
    truth = sample_labels[i]
    prediction = predicted[i]
    plt.subplot(5, 2,1+i)
    plt.axis('off')
    color='green' if truth == prediction else 'red'
    plt.text(40, 10, "Truth:        {0}\nPrediction: {1}".format(truth, prediction), 
             fontsize=12, color=color)
    plt.imshow(sample_images[i],  cmap="gray")

plt.show()

traffic signs 6

Alleen naar willekeurige afbeeldingen kijken geeft je echter niet veel inzicht in hoe goed je model daadwerkelijk presteert. Daarom laad je de testdata in.

Let op dat je gebruikmaakt van de functie load_data(), die je aan het begin van deze tutorial hebt gedefinieerd.

# Import `skimage`
from skimage import transform

# Load the test data
test_images, test_labels = load_data(test_data_directory)

# Transform the images to 28 by 28 pixels
test_images28 = [transform.resize(image, (28, 28)) for image in test_images]

# Convert to grayscale
from skimage.color import rgb2gray
test_images28 = rgb2gray(np.array(test_images28))

# Run predictions against the full test set.
predicted = sess.run([correct_pred], feed_dict={x: test_images28})[0]

# Calculate correct matches 
match_count = sum([int(y == y_) for y, y_ in zip(test_labels, predicted)])

# Calculate the accuracy
accuracy = match_count / len(test_labels)

# Print the accuracy
print("Accuracy: {:.3f}".format(accuracy))

Onthoud om de sessie af te sluiten met sess.close() als je niet with tf.Session() as sess: hebt gebruikt om je TensorFlow-sessie te starten.

Waar ga je hierna naartoe?

Als je met deze dataset en het model uit deze tutorial wilt doorgaan, probeer dan het volgende:

  • Pas geregulariseerde LDA toe op de data voordat je die aan je model voert. Dit is een suggestie uit een van de originele papers, geschreven door de onderzoekers die deze dataset hebben verzameld en geanalyseerd.
  • Je zou, zoals in de tutorial zelf gezegd, ook kunnen kijken naar andere data-augmentatiebewerkingen die je kunt uitvoeren op de verkeersbordafbeeldingen. Daarnaast kun je ook proberen dit netwerk verder te finetunen; Het netwerk dat je nu hebt gemaakt was vrij eenvoudig.
  • Early stopping: Houd tijdens het trainen van het neurale netwerk de trainings- en testfout bij. Stop met trainen wanneer beide fouten omlaag gaan en vervolgens plotseling weer omhoog – dit is een teken dat het neurale netwerk de trainingsdata is gaan overfitten.
  • Experimenteer met de optimizers.

Zorg dat je het boek Machine Learning With TensorFlow bekijkt, geschreven door Nishant Shukla.

Tip bekijk ook de TensorFlow Playground en de TensorBoard.

Als je met afbeeldingen wilt blijven werken, bekijk dan zeker DataCamp’s scikit-learn-tutorial, die de MNIST-dataset behandelt met behulp van PCA, K-Means en Support Vector Machines (SVM’s). Of bekijk andere tutorials zoals deze die de Belgische verkeersborden-dataset gebruikt.

Onderwerpen
Python
Kunstmatige intelligentie
Machine Learning
Deep Learning

Leer meer over Python en Deep Learning

Cursus

Introductie tot TensorFlow in Python

4 uur
56.6K
Leer de basis van neurale netwerken en hoe je deep learning-modellen kunt bouwen met TensorFlow.
Bekijk detailsRight Arrow
Start Cursus
Meer bekijkenRight Arrow
Gerelateerd

blog

AI vanaf nul leren in 2026: een complete gids van de experts

Ontdek alles wat je moet weten om in 2026 AI te leren, van tips om te beginnen tot handige resources en inzichten van industrie-experts.
Adel Nehme's photo

Adel Nehme

15 min

Meer BekijkenMeer Bekijken