Transfer Learning en Fine Tuning van MobileNet model met 4 extra lagen

Keras documentatie https://keras.io/applications/#mobilenet
In dit voorbeeld wordt met argumenten in de constructor van MobileNet het model met aanpassingen gedownload
door het veranderen van argumenten in de constructor wordt een ander model gedownload
In het model worden 4 lagen toegevoegd waar onder een outputlaag met 2 neuronen
Het model wordt getraind met 40 passiebloemen en 40 waterlelies in de map images
dit is natuurlijk veel te weing voor een goed werkend model

In [87]:
# globale imports
import keras
import numpy as np
#from keras import backend as K
In [88]:
#Imports tbv downloaden en aanpassen van het model
from keras.models import Model
from keras.applications import MobileNet
#from keras.applications import imagenet_utils
In [89]:
#imports tbv normalisatie en pooling van de lagen
from keras.layers import Dense, GlobalAveragePooling2D, Dropout
In [90]:
#imports tbv de optimalisering en loss functies
from keras.optimizers import Adam
from keras.metrics import categorical_crossentropy
In [91]:
#Imports tbv de datagenerator
from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing import image
from keras.applications.mobilenet import preprocess_input
In [92]:
#default_model=MobileNet()
#default_model.summary()      # is het model zonder aanpassingen

Het downloaden van een aangepast MobileNet model Gekozen is voor input_shape=(128, 128, 3) met input_shape=None wordt de default shape gedownload (224, 224, 3)
met alfa bepaal je het aantal filters in iedere laag Met include_top = False wordt de outputlaag verwijdert wordt de output laag niet gedownload
If using weights as "imagenet" with include_top as true, classes should be 1000
weights = "imagenet" betekend dat het model is getrained met 1000 afbeeldingen van imagenet
daarom moet classes = 1000 zijn

In [93]:
base_model=MobileNet(input_shape=(128, 128, 3), alpha = 0.75,depth_multiplier = 1, dropout = 0.001,
include_top = False, weights = "imagenet", classes = 2, backend=keras.backend, layers=keras.layers,
models=keras.models,utils=keras.utils)
type(base_model)
Out[93]:
keras.engine.training.Model
In [94]:
#base_model.summary() #vergelijk default_model met het base_model

Onderstaande code voegt 4 lagen toe in de top van het base_model
en een global_average_pooling2d
De laatste laag preds heeft 2 neuronen, is het aantal classes

In [95]:
x=base_model.output
x=GlobalAveragePooling2D()(x)
#drie dense lagen worden toegevoegd
x=Dropout(0.5)(x)
x=Dense(100,activation='relu')(x) #is dense_10
x=Dense(50,activation='relu')(x)  #is dense_11
#de laatste, outputlaag heeft 2 neuronen
preds=Dense(2,activation='softmax')(x) # is dense_12
In [96]:
#De extra lagen aan het model toevoegen
model=Model(inputs=base_model.input,outputs=preds)
In [97]:
#model.summary()
In [98]:
preds
Out[98]:
<tf.Tensor 'dense_15/Softmax:0' shape=(None, 2) dtype=float32>
In [99]:
type(model)
Out[99]:
keras.engine.training.Model

De 92 namen van de layers van het netwerk uitprinten

In [100]:
#for i,layer in enumerate(model.layers):
#    print(i,layer.name)

Het netwerk heeft dus 0 t/m 91 lagen. De lagen vanaf 87 t/m 91 worden getrained Dit zijn de laatste 5 toegevoegde lagen

In [101]:
for layer in model.layers[:86]:
    layer.trainable=False
for layer in model.layers[86:]:
    layer.trainable=True
In [102]:
#imageDataGenerator maak van de afbeeldingen, batches van flatten tensoren tbv de model.fit_generator

train_datagen=ImageDataGenerator(preprocessing_function=preprocess_input)
#de afbeeldingen ziten in de sub mappen van de map "images"
#de namen van de submappen zijn de namen van de classes
train_generator=train_datagen.flow_from_directory('images',
                                                 target_size=(128,128),
                                                 color_mode='rgb',
                                                 batch_size=20,
                                                 class_mode='categorical', shuffle=True)
Found 80 images belonging to 2 classes.
In [103]:
type(train_generator)
Out[103]:
keras.preprocessing.image.DirectoryIterator
In [104]:
model.compile(optimizer='Adam',loss='categorical_crossentropy',metrics=['accuracy'])
In [105]:
step_size_train=train_generator.n//train_generator.batch_size
model.fit_generator(generator=train_generator,steps_per_epoch=step_size_train,epochs=10)
Epoch 1/10
4/4 [==============================] - 11s 3s/step - loss: 0.6856 - accuracy: 0.6000
Epoch 2/10
4/4 [==============================] - 4s 1s/step - loss: 0.2821 - accuracy: 0.8625
Epoch 3/10
4/4 [==============================] - 5s 1s/step - loss: 0.1034 - accuracy: 0.9750
Epoch 4/10
4/4 [==============================] - 4s 1s/step - loss: 0.0497 - accuracy: 1.0000
Epoch 5/10
4/4 [==============================] - 4s 1s/step - loss: 0.0655 - accuracy: 0.9750
Epoch 6/10
4/4 [==============================] - 4s 1s/step - loss: 0.3110 - accuracy: 0.9125
Epoch 7/10
4/4 [==============================] - 4s 954ms/step - loss: 0.1929 - accuracy: 0.9500
Epoch 8/10
4/4 [==============================] - 4s 990ms/step - loss: 0.0088 - accuracy: 1.0000
Epoch 9/10
4/4 [==============================] - 4s 975ms/step - loss: 0.0090 - accuracy: 1.0000
Epoch 10/10
4/4 [==============================] - 4s 1s/step - loss: 0.0052 - accuracy: 1.0000
Out[105]:
<keras.callbacks.callbacks.History at 0x7fb580a90f90>
In [106]:
model.save('bloem_model.h5') # het opgeslagen model is 8,6 MB