Artificial Intelligence

Hoe kom je van Python code naar een product?

Wat is een product?

Een product is in dit geval een stuk software dat generiek gebruikt kan worden door anderen. Het doel van mijn schrijven is niet om een probleem aan te kaarten of op te lossen noch probeer ik hier een tutorial te schrijven. Ik wil jullie alleen mijn gedachtegang laten lezen over hoe je een notebook-model kan laten uitlopen op een generiek te gebruiken product. Dit specifieke blog gaat over het eerste deel waarbij je bezig bent met het maken van zo’n notebook-model waar je uiteindelijk tevreden mee bent. Een toekomstige tweede blog, zal gaan over het ‘in productie brengen’ van een model uit een notebook, het tweede deel van mijn verhaal dus waarbij ik een prototype maak.

In het begin van een data science project open je in veel gevallen een IPython notebook (Jupyter notebook) en begin je met het inladen van de data, ga je kijken naar hoe je data eruitziet en probeer je wat verbanden te leggen. Daarna ga je nieuwe features genereren,  data normaliseren en uiteindelijk maak je een baseline model. Dat baseline model is een eerste voorspelling of classificatie op basis van je data en die probeer je in volgende iteraties te verbeteren.

Stel nou dat je een model hebt waar je tevreden mee bent, wat doe je dan? Als je bij de klant zit wil je dat model in productie brengen maar, als je thuis bent en je bent jezelf aan het vermaken met een eigen project, dan stopt het vaak hier. Om te oefenen en om ervaring op te doen heb ik toen besloten om vaker dit soort notebooks in ‘productie’ te brengen. Niet zozeer omdat ik allerlei websites en apps wil gaan hosten en onderhouden maar vooral om te leren hoe van A tot Z een data science project kan doen. Van een idee naar een prototype of een minimum viable product dus.

Afbeeldingen van ISIC archive

De data die ik heb gebruikt komt van een site die afbeeldingen van kwaadaardige en goedaardige moedervlekken host (let op: dit zijn niet altijd fijne afbeeldingen om te zien). Dit archief (https://challenge2018.isic-archive.com/) is een wereldwijde inzet van zorgverleners. Het archief kan door iedereen die dat wil, gebruikt worden om modellen op te trainen en om kennis mee te delen. Toen ik op zoek ging naar data waarmee ik een notebook-model in productie kan brengen, leek mij het classificeren van een moedervlek een haalbaar project. Je hebt slechts nodig: trainingsdata, een programmeertaal of meerdere talen, een GPU en een telefoon. Het eindproduct zoals ik het voor ogen heb is een app op je telefoon waarmee je een foto kunt maken van een moedervlek waarna de app zegt of je beter even naar de dokter kan of dat er (nog) niet zoveel aan de hand is. Het is niet de bedoeling dat de app medisch advies geeft en de data mag van mij niet buiten de telefoon komen. Dat laatste betekent dus dat ik een getraind model op de telefoon moet zien te krijgen binnen de app. De gebruiker hoeft dan niet de foto in de cloud te sturen en in verband met de gevoeligheid van dit soort data lijkt mij dat design principe zeer wenselijk. Het werpt wel allerlei moeilijkheden op maar, dat is nou juist de uitdaging.

Dit blog gaat dus alleen over het trainen van een classificatie model en hieronder komt een ietwat technisch verhaal over hoe ik dat heb gedaan.

Ten eerste heb ik data nodig. Via de REST-API van het ISIC-archief kwam ik erachter dat je de afbeelding kunt downloaden maar dat dit makkelijker gezegd dan gedaan is. Gelukkig kwam ik 2 auteurs van code tegen op GitHub (https://github.com/GalAvineri/ISIC-Archive-Downloader), zij hadden dit al eerder geprobeerd en hebben hun code gepubliceerd voor ieders gebruik.

Figuur 1 Downloaden van de afbeeldingen

Afbeeldingen voorverwerken

Nu is er dus data maar, er zitten nog wat haken en ogen aan. Zo is niet elke afbeelding van gelijke grootte. Dit is een probleem voor mijn toekomstige model want dat zal uiteindelijk een bepaalde input verwachten. Voldoet het niet aan die verwachting, dan zal het model niet werken. Een ander issue is sowieso de grootte. 1200×900 pixels zoals veel van deze afbeeldingen hebben, is op zichzelf niet heel erg groot maar wel als je allerlei matrix calculaties gaat doen waardoor het model ‘opblaast’, zoals dat onder data scientisten heet. Je hebt heel veel geheugen nodig om alle tijdelijke calculaties in op te slaan. Dat betekent dus: down scalen van je afbeeldingen. Dit heeft natuurlijk ongelofelijk veel nadelen want je gooit in feite informatie weg. Helaas heb ik geen andere keuze want ik zal mijn model in google colab (https://colab.research.google.com) gaan trainen en daardoor zit ik vast aan hardware beperkingen. Als oplossing hiervoor ga ik al mijn afbeeldingen resizen naar 128×128. Ik pas dus niet alleen de grootte aan, ook de ratio tussen de x en de y-as verandert. Ik weet niet zeker of dat een probleem is in de praktijk en dat zal moeten blijken als het model in het prototype wordt gebruikt.

Train, test en validatie split

Nu ben ik in het bezit van 2000 afbeeldingen waarvan er 1000 een kwaadaardige moedervlek zijn en de andere 1000 goedaardig. Ik heb dit bewust evenredig gesplitst want dat zorgt er straks voor dat mijn model niet neigt naar altijd ‘kwaadaardig’ of ‘goedaardig’ voorspellen.

In eerste instantie had ik dit niet gedaan en ik zag bijna meteen dat mijn model ging ‘overfitten’. Dat betekent dat het model heel goed werkt op de data die hij tijdens de training ziet maar heel slecht of zelfs steeds slechter wordt op het voorspellen van nieuwe data; testdata die het model niet ziet tijdens de training. We hebben daar een truc voor waardoor je tijdens de training kunt checken of je model het beter gaat doen tijdens de training op ongeziene data. Dat doe ik in dit geval met train_test_split van de library genaamd sklearn. In dit geval heb ik ervoor gekozen om:

  • 1500 afbeeldingen te gebruiken om op te trainen: m’n trainingsset (75%).
  • 400 afbeeldingen om op te testen: m’n testset (20%).
  • 100 afbeeldingen om mijn getrainde model op te valideren: m’n validatieset (5%)

Figuur 2 Een voorbeeld van hoe je een train-test-val set maakt

Trainen van het model

Voor het trainen van het model maak ik gebruik van Keras. Dat is een library in onder andere Python die gebruik maakt van tensorflow. Tensorflow is een state of the art product van Google waarmee zij in staat zijn zeer krachtige modellen te maken om AI mee te ondersteunen. Het model bestaat uit een input layer die de afbeeldingen bevat om op te trainen. Er zullen 1500 afbeeldingen waarvan 50% goedaardige en 50% kwaaraardige moedervlekken opstaan in het model gevoed worden door middel van brokjes (batches) van 10. Na de input layer volgt het volgende:

 

Figuur 3 Overzicht van alle layers in het model

We noemen dit een Convolutional Neural Network en dat is en neuraal netwerk dat gespecialiseerd is in het verwerken van afbeeldingen. Op YouTube staat een aantal goede video’s van wat dat is en hoe het werkt.

Ik train het neurale netwerk met 90 epochs. 1 epoch staat voor het zien van alle trainingsdata. 90 epochs betekent dus dat het netwerk alle trainingsdata 90 keer gaat zien. Na elke epoch doe ik test om te kijken of het model beter wordt of juist slechter. Dat doe ik om te kijken of het beter wordt in het classificeren van de trainingsdata en of het beter wordt in het voorspellen van de test data. Die 90 epochs is een arbitrair aantal wat gebaseerd is op het volgen van de accuracy progressie. Een betere methode is eigenlijk om een ‘early-stopping’ aan het model te voegen zodat het stopt zodra de accuracy op de test set niet meer omhooggaat (of na een tijdje zelfs omlaaggaat).

Ik mik op een accuracy van 80%. Dat betekent dat ik wil dat het model in 80% van de gevallen een juiste classificatie weet te geven. Eigenlijk zou ik moeten willen neigen naar 100% maar dat is in praktijk niet heel makkelijk. Een belangrijke benchmark voor modellen die door onderzoekers worden ontwikkeld is de MNIST-dataset. Dat is een set van handgeschreven getallen van 0 tot en met 9. De allerbeste modellen halen een accuracy van zo’n 98 of 99 procent. De afbeeldingen zijn veel kleiner in aantal pixels en de dataset heeft 10.000 afbeeldingen. De afbeeldingen die ik gebruik hebben heel veel ruis (sommige hebben bijvoorbeeld haar op de foto, andere moedervlekken, verschillende kleurtinten huid en verschillende vormen van eenzelfde classificatie. Al met al dus iets ingewikkelder voor een mens en wellicht dus ook voor een computer.

Het model geeft eigenlijk 2 componenten mee in zijn voorspelling namelijk: een bepaalde zekerheid dat het model heeft dat een moedervlek goedaardig is en een zekerheid dat een moedervlek kwaadaardig is. Een dergelijke voorspelling uit mijn model ziet er als volgt uit:

Tezamen is dat dus 100% en in dit geval is het model er meer zeker van dat het om een kwaadaardige moedervlek gaat dan om een goedaardige. In de app zal dit wellicht op ander manier worden weergegeven aangezien zo’n bericht tot paniek zou kunnen leiden. Bovendien wil ik ver van medisch advies blijven: Een arts zal bij twijfel extra onderzoek doen (dat is een aanname maar hopelijk doet een arts dat wel). Ik weet niet wanneer een arts twijfelt en op wat voor kennis de arts steunt, waar je op moet letten bijvoorbeeld. Dat is domeinkennis die ik niet heb en die ik mogelijk na het eerste prototype kan gaan opvragen bij een dermatoloog: Ik moet namelijk van mezelf wel wat te laten zien hebben.

Om het model extra nauwkeurig te maken, voeg ik nog iets extra toe aan de input layer. Elke afbeelding is onderwerp van lichte aanpassingen die ik random toevoeg aan iedere batch. Zo kan het zijn dat een willekeurige afbeelding een kleine rotatie krijgt, verticaal of horizontaal flipt, een beetje van de onder of bovenkant verandert of een beetje inzoomt of niet. Hierdoor kan ik van alle 1500 trainingsafbeeldingen heel veel meer versies laten zien aan het model. Een neuraal netwerk is zeer gevoelig en elke kleine aanpassing aan een pixel kan gevolgen hebben voor de uitkomst van het model. Door daar gebruik van te maken wordt het model robuuster waardoor de classificaties beter worden op nieuwe data.

Model evaluatie

De evaluatie van mijn model doe ik op de laatste 100 afbeeldingen die ik mijn validatie-set heb genoemd. Ik gebruik hiervoor de average precision score die een gemiddelde neemt van een precision-recalll curve as the weighted mean van de precisions. Ook gebruik ik een confusion matrix om te zien hoeveel een true positive, een true negative, et cetera is voorgekomen. Als laatste hoop ik op een accuracy van >80%

Figuur 4 Overzicht van model evaluatie metrics

Next up:

Het model wordt opgeslagen in een bestand met daarin de architectuur en alle getrainde onderdelen. In het volgende blog zal ik schrijven over hoe dit model uit een notebook gehaald wordt, voorbereidt wordt om binnen een app te werken en de stappen die nodig zijn om een app te ontwikkelen die een foto kan nemen om een classificatie te krijgen.

To be continued…

 

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *