maandag 26 februari 2018

Zelf optimaliserende modellen - 1

Naar aanleiding van wat berichten over zelf optimaliserende modellen van Google ben ik zelf eens gaan kijken of ik iets dergelijks zou kunnen bouwen. Uitgaande van de 'beroemde' mnist nummer-dataset (waar geschreven nummers herkent moeten kunnen worden) en een eenvoudig convolutioneel netwerk:

model = Sequential()
model.add(Convolution2D(32, 3, 3, activation='relu', input_shape=(1,28,28)))
model.add(Convolution2D(32, 3, 3, activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.25))

model.add(Dense(10, activation='softmax'))

Ik voeg er wel nog wat Dropout lagen, na de conv lagen, aan toe om het effect mogelijk te vergroten. Uiteraard eerst weer wat worstelen met verouderde code standaarden. (Convolution2D heet nu Conv2D en de input_shape moet andersom - channel last). 

Het idee is om alle aanpasbare parameters random te laten veranderen en daarmee te testen of er beter presterende modellen te vinden zijn.  Omdat een model volledig doorrekenen veel tijd kost ga ik uit van een beperkt aantal 'epochs'. Dat is zeg maar een testronde waarin al het materiaal aan het netwerk wordt aangeboden. Ik kies voor 3 epochs per model. Tevens begin ik met de modellen te testen op een klein deel van de dataset. Ook om de snelheid te verhogen. De mate van 'mutatie' maak ik eerst groot en langzamerhand steeds kleiner.

Ik gebruik deze parameters:


data_part = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7,  0.9,  1.]
rounds    = [30, 20, 8, 7, 6, 5, 4, 3, 3, 3]
change    = [.3, .3, .3, .3, .3, .2, .2, .2, .2, .2]
variance  = [.8, .8, .5, .5, .5, .5, .5, .5, .3, .2, .2, .2]

data_part: geeft aan dat er slechts met een beperkt deel van de beschikbare data wordt getest. Ik maak dit wel 'random' zodat er steeds een nieuw deel van de data wordt gebruikt. Ook van de test data wordt maar een evenredig deel gebruikt. Later heb ik dit voor kleine waardes verdubbeld om toevalstreffers te vermijden. 
rounds: is het aantal testrondes met de gegeven waarden.
change: de kans dat er een verandering plaatsvind
variance: aandeel van de maximale grootte van de verandering  

Na de eerste volledige ronde heb ik deze resultaten:

Score after first full round:
    Score p [0.03745218972601251, 0.9898]
    Score pn [0.02542259713255735, 0.9929]
    
    32.0 3.0 3.0 0.05 32.0 3.0 3.0 0.05 2.0 2.0 0.25 128.0 0.25
  11.0 3.0 2.0 0.04 63.0 4.0 4.0 0.02 4.0 3.0 0.13 119.0 0.2 

Score p - geeft de uitkomsten (validation loss and accuracy) aan van de uitgangspositie. 
Score pn - geeft dat van de nieuw gevonden parameters. 
De parameters geven vooral een verkleining van de eerste conv layer van 32 naar 11 aan en een vergroting van de 2e van 32 naar 63. De poolsize is ook vergroot van 2x2 naar 4x3. De extra dropoutlayers lijken nauwelijks bij te dragen. (van .05 naar .04 en 0.05 naar .02) En lijken dus niet wezenlijk in het model.

Ik test het resultaat nogmaals met een 2e volledige ronde:

Score after second full round:
    Score p [0.027079543936137453, 0.9932]
    Score pn[0.024220995485605818, 0.9937]
    
    11.0 3.0 2.0 0.04  63.0 4.0 4.0 0.02 4.0 3.0 0.13 119.0 0.2
     8.0 4.0 2.0 0.05 111.0 4.0 4.0 0.01 4.0 6.0 0.12 119.0 0.09
Weer iets verbetering maar niet zoveel. Maar met 99,37% wordt het uiteraard steeds moeilijker naarmate je dichter bij de 100% probeert te komen. Het aangepaste model ziet er dus nu zo uit:


model = Sequential()
model.add(Convolution2D(8, 4, 2, activation='relu', input_shape=(1,28,28)))
model.add(Convolution2D(111, 4, 4, activation='relu'))
model.add(MaxPooling2D(pool_size=(4,6)))
model.add(Dropout(0.12))

model.add(Flatten())
model.add(Dense(119, activation='relu'))
model.add(Dropout(0.09))

model.add(Dense(10, activation='softmax'))

Ik heb de extra dropout layers weggelaten wegens het kleine effect. Wat opvalt is een vergroot verschil tussen de eerste en de tweede conv layer: Van 32 naar 8 en de 2e van 32 naar 111. Waarbij de omvang van de convolutie gebiedjes van 3x3 naar 4x3 en 4x4 is verhoogd. Ook de poolsize is stevig opgehoogd van 2x2 naar 4x6 en de oorspronkelijke dropoutlayers zijn verlaagd van .25 naar .12 en .09.
Eens kijken of we op basis hiervan een model kunnen maken dat gebruik maakt van de tendens van deze learnings en wellicht dus nog beter presteert.
Dat lijkt niet eenvoudig. Elke aanpassing geeft een minder resultaat. Het lijkt erop dat het model idd behoorlijk optimaal is binnen het gegeven aantal lagen.
Het blijft verrassen dat de dropout zo wordt teruggeschroefd. Wellicht zorgt de sterk verkleinde eerste convolutie-laag al voor voldoende compensatie voor 'overfitting'. (Waar normaliter drop-out lagen voor worden toegevoegd.)
   






     

Geen opmerkingen:

Een reactie posten