In [2]:
import tensorflow as tf
import keras as keras


Using TensorFlow backend.

In [3]:
# --------------------------------------------------------------------------------------- +
# Implementing VGG Model / Architecture
# https://www.tensorflow.org/tutorials/layers
# https://towardsdatascience.com/components-of-convolutional-neural-networks-6ff66296b456
# --------------------------------------------------------------------------------------- +

# 1. parameters

model_params = {
    "num_classes": 10,
    "input_shape": (32, 32, 3),
    "conv_kernel": (3,3),
    "pool_kernel": (2,2),
    "batch_size" : 32
}

hyper_params = {
    "l2_regularization" : 0.0005,
    "dropout": 0.5,
    "learning_rate": 0.0001
}

In [4]:
# 2a. conv2d layer

def conv2d(filters):
    return keras.layers.Conv2D(filters, 
                               model_params["conv_kernel"], 
                               padding='same',
                               activation=tf.nn.relu, 
                               kernel_regularizer=tf.contrib.layers.l2_regularizer(hyper_params["l2_regularization"]))

In [5]:
# 2b. convolutional block

def setConvBlock(filters, inputs):
    net = conv2d(filters)(inputs)
    net = keras.layers.BatchNormalization()(net)
    net = conv2d(filters)(net)
    net = keras.layers.MaxPool2D(model_params["pool_kernel"])(net)
    return keras.layers.Dropout(0.25)(net)

def convBlock(filters):
    def convBlockWrapped(inputs):
        return setConvBlock(filters, inputs)
    return convBlockWrapped

In [6]:
# 2c. dense block

def setDenseBlock(units, inputs):
    net = keras.layers.Dense(units)(inputs) 
    return keras.layers.Dropout(hyper_params["dropout"])(net)

def denseBlock(units):
    def denseBlockWrapped(inputs):
        return setDenseBlock(units, inputs)
    return denseBlockWrapped

In [7]:
# 3. Simplified VGG Model

def VGG():
    
    # tensorflow default graph
    tf.reset_default_graph()
    
    # input image tensor
    inputs = keras.layers.Input(shape=model_params["input_shape"])

    # convolutional blocks
    net = convBlock(64)(inputs)
    net = convBlock(128)(net)
    net = convBlock(256)(net)
    
    net = keras.layers.Flatten()(net)
    
    # fully connected
    net = denseBlock(1024)(net)
    net = denseBlock(512)(net)
    
    # final layer
    outputs = keras.layers.Dense(model_params["num_classes"],
                                 activation = tf.nn.softmax)(net)
    
    # model
    model = keras.models.Model(inputs=inputs, outputs=outputs)
    
    return model

In [8]:
# 4. Compile Model 
#    - add loss function, optimizer and the metrics

def compile_model(model):
    
    # loss
    loss = keras.losses.categorical_crossentropy
    
    # adam optimizer
    optimizer = keras.optimizers.Adam(lr=hyper_params["learning_rate"])
    
    # metrics
    metrics = [keras.metrics.categorical_accuracy,
               keras.metrics.top_k_categorical_accuracy]

    # compile
    model.compile(loss=loss,
                  optimizer=optimizer,
                  metrics=metrics)

    print(model.summary())
    
    return model

In [9]:
vgg = VGG()
vgg = compile_model(vgg)


_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 32, 32, 3)         0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 32, 32, 64)        1792      
_________________________________________________________________
batch_normalization_1 (Batch (None, 32, 32, 64)        256       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 32, 32, 64)        36928     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 16, 16, 64)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 16, 16, 64)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 16, 16, 128)       73856     
_________________________________________________________________
batch_normalization_2 (Batch (None, 16, 16, 128)       512       
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 16, 16, 128)       147584    
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 8, 8, 128)         0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 8, 8, 128)         0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 8, 8, 256)         295168    
_________________________________________________________________
batch_normalization_3 (Batch (None, 8, 8, 256)         1024      
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 8, 8, 256)         590080    
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 4, 4, 256)         0         
_________________________________________________________________
dropout_3 (Dropout)          (None, 4, 4, 256)         0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 4096)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 1024)              4195328   
_________________________________________________________________
dropout_4 (Dropout)          (None, 1024)              0         
_________________________________________________________________
dense_2 (Dense)              (None, 512)               524800    
_________________________________________________________________
dropout_5 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_3 (Dense)              (None, 10)                5130      
=================================================================
Total params: 5,872,458
Trainable params: 5,871,562
Non-trainable params: 896
_________________________________________________________________
None

In [34]:
#--------------------------------------------------------------------------+
# 5. Try it out on a dataset !
#--------------------------------------------------------------------------+
# load CIFAR10 dataset
# https://www.cs.toronto.edu/~kriz/cifar.html

(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()

In [35]:
# set target values to one-hot encoded vectors
y_train = keras.utils.to_categorical(y_train, model_params["num_classes"])
y_test  = keras.utils.to_categorical(y_test,  model_params["num_classes"])

In [36]:
# data augmentation : generate more dataset
train_aug = tf.contrib.keras.preprocessing.image.ImageDataGenerator(
    rescale=1./255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True)

test_aug = tf.contrib.keras.preprocessing.image.ImageDataGenerator(
    rescale=1./255)

In [37]:
# training generator
train_gen = train_aug.flow(x=x_train, y=y_train, batch_size=model_params["batch_size"])

# testing generator
test_gen = test_aug.flow(x=x_test, y=y_test, batch_size=model_params["batch_size"])

In [40]:


In [ ]:
# train Simplified-VGG on CIFAR10

fitvgg = vgg.fit_generator(train_aug.flow(x_train, y_train, batch_size=32),
                           validation_data=[x_test, y_test],
                           epochs=10,
                           steps_per_epoch=300,
                           verbose=1,
                           workers=4)

In [ ]:
# train Simplified-VGG on CIFAR10

fitvgg = vgg.fit_generator(train_gen,
                           steps_per_epoch=300,
                           epochs=10,
                           validation_data=test_gen,
                           validation_steps=100)

In [ ]:
#--------------------------------------------------------------------------+
# 6. evaluate model performance 
#--------------------------------------------------------------------------+

loss, acc, top_k_acc = vgg.evaluate_generator(test_gen, steps=200)
print("loss: {}".format(loss))
print("accuracy: {}".format(acc))
print("top 5 accuracy: {}".format(top_k_acc))

In [ ]:
# make predictions on trained VGG

predictions = vgg.predict_generator(test_gen, steps=100)

In [ ]:
# plot accuracy and loss over time

def plot_accuracy_and_loss(fitvgg):
    plt.figure(1, figsize=(15, 10))
    
    # plot train and test accuracy
    plt.subplot(221)
    plt.plot(fitvgg.history['categorical_accuracy'])
    plt.plot(fitvgg.history['val_categorical_accuracy'])
    plt.title('VGG Accuracy')
    plt.ylabel('accuracy')
    plt.xlabel('epoch')
    plt.legend(['train', 'test'], loc='upper left')
    
    # plot train and test loss
    plt.subplot(222)
    plt.plot(fitvgg.history['loss'])
    plt.plot(fitvgg.history['val_loss'])
    plt.title('VGG Loss')
    plt.ylable('loss')
    plt.xlabel('epoch')
    plt.legend(['train', 'test'], loc='upper right')
    
    plt.show()

In [ ]:
plot_accuracy_and_loss(fitvgg)

In [ ]:
#--------------------------------------------------------------------------+
# 7. save model architecture and weights
#--------------------------------------------------------------------------+
myvgg = vgg.to_json()
open('simplified_cifar10_vgg.json','w').write(myvgg)
vgg.save_weights('image_classifier_cifar10.h5', overwrite=True)

In [ ]:
## --+

In [ ]:
# Transfer Learning
# 1. via Feature Extraction
# 2. via Fine Tuning

In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]: