In [1]:
import matplotlib.pyplot as plt
from matplotlib import ticker

import seaborn as sns

from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.callbacks import ModelCheckpoint, Callback, EarlyStopping, TensorBoard


Using TensorFlow backend.

In [2]:
# dimensions of our images.
img_width, img_height = 50, 50

train_data_dir = 'data/symlinks/train'
validation_data_dir = 'data/symlinks/validation'
test_data_dir = 'data/symlinks/test'
nb_epoch = 10
batch_size=128

In [3]:
# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
        samplewise_center=True,
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)

# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(
        samplewise_center=True,
        rescale=1./255
)

In [4]:
train_generator = train_datagen.flow_from_directory(
        train_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode='binary',
        follow_links=True)

validation_generator = test_datagen.flow_from_directory(
        validation_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        class_mode='binary',
        follow_links=True)

test_generator = test_datagen.flow_from_directory(
        test_data_dir,
        target_size=(img_width, img_height),
        batch_size=batch_size,
        shuffle=False,
        class_mode='binary',
        follow_links=True)


Found 325298 images belonging to 2 classes.
Found 219720 images belonging to 2 classes.
Found 150833 images belonging to 2 classes.

In [5]:
def get_model():
    model = Sequential()
    model.add(Convolution2D(32, (3, 3), input_shape=(img_width, img_height, 3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    
    model.add(Convolution2D(32, (3, 3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    
    model.add(Convolution2D(64, (3, 3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    
    model.add(Flatten())
    model.add(Dense(64))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))
    
    return model

model = get_model()

In [6]:
model.summary()


_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 48, 48, 32)        896       
_________________________________________________________________
activation_1 (Activation)    (None, 48, 48, 32)        0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 24, 24, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 22, 22, 32)        9248      
_________________________________________________________________
activation_2 (Activation)    (None, 22, 22, 32)        0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 11, 11, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 9, 9, 64)          18496     
_________________________________________________________________
activation_3 (Activation)    (None, 9, 9, 64)          0         
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 4, 4, 64)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 1024)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 64)                65600     
_________________________________________________________________
activation_4 (Activation)    (None, 64)                0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 64)                0         
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 65        
_________________________________________________________________
activation_5 (Activation)    (None, 1)                 0         
=================================================================
Total params: 94,305.0
Trainable params: 94,305.0
Non-trainable params: 0.0
_________________________________________________________________

In [7]:
## Callback for loss logging per epoch
class LossHistory(Callback):
    def on_train_begin(self, logs={}):
        self.losses = []
        self.val_losses = []

    def on_epoch_end(self, batch, logs={}):
        self.losses.append(logs.get('loss'))
        self.val_losses.append(logs.get('val_loss'))
        
history = LossHistory()

In [8]:
tensorboard = TensorBoard(log_dir='./logs', histogram_freq=1, write_graph=True, write_images=False)
checkpointer = ModelCheckpoint(filepath="weights.hdf5", verbose=0, save_best_only=True)

In [ ]:
model.compile(loss='binary_crossentropy',
              optimizer='adam',
              metrics=['accuracy'])

model.fit_generator(
        train_generator,
        steps_per_epoch=train_generator.samples/batch_size,
        epochs=nb_epoch,
        validation_data=validation_generator,
        verbose=1,
        validation_steps=validation_generator.samples/batch_size,
        workers=8,
        pickle_safe=True,
        callbacks=[history, tensorboard, checkpointer])


Epoch 1/10
2542/2541 [==============================] - 144s - loss: 0.0697 - acc: 0.9773 - val_loss: 0.0529 - val_acc: 0.9825
Epoch 2/10
2542/2541 [==============================] - 161s - loss: 0.0343 - acc: 0.9901 - val_loss: 0.0371 - val_acc: 0.9876
Epoch 3/10
2542/2541 [==============================] - 183s - loss: 0.0287 - acc: 0.9920 - val_loss: 0.0381 - val_acc: 0.9881
Epoch 4/10
2542/2541 [==============================] - 201s - loss: 0.0232 - acc: 0.9936 - val_loss: 0.0298 - val_acc: 0.9901
Epoch 5/10
2542/2541 [==============================] - 202s - loss: 0.0215 - acc: 0.9941 - val_loss: 0.0328 - val_acc: 0.9898
Epoch 6/10
2542/2541 [==============================] - 195s - loss: 0.0204 - acc: 0.9947 - val_loss: 0.0307 - val_acc: 0.9906
Epoch 7/10
2412/2541 [===========================>..] - ETA: 8s - loss: 0.0189 - acc: 0.9950

In [10]:
loss = history.losses
val_loss = history.val_losses

plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Loss Trend')
plt.plot(loss, 'blue', label='Training Loss')
plt.plot(val_loss, 'green', label='Validation Loss')
plt.xticks(range(0,nb_epoch)[0::2])
plt.legend()

plt.show()



In [11]:
test_loss, test_acc = model.evaluate_generator(
         test_generator,
         workers=8,
         pickle_safe=True,
         steps=test_generator.samples/batch_size)

print("test_loss: %.4f - test_acc: %.4f"%(test_loss, test_acc))


test_loss: 0.0122 - test_acc: 0.9961

In [12]:
from IPython.display import SVG
from keras.utils.vis_utils import model_to_dot

SVG(model_to_dot(model,show_shapes=True, show_layer_names=True).create(prog='dot', format='svg'))


Out[12]:
G 139951372596448 conv2d_1_input: InputLayer input: output: (None, 50, 50, 3) (None, 50, 50, 3) 139951372596392 conv2d_1: Conv2D input: output: (None, 50, 50, 3) (None, 48, 48, 32) 139951372596448->139951372596392 139951433816496 activation_1: Activation input: output: (None, 48, 48, 32) (None, 48, 48, 32) 139951372596392->139951433816496 139951372597400 max_pooling2d_1: MaxPooling2D input: output: (None, 48, 48, 32) (None, 24, 24, 32) 139951433816496->139951372597400 139951356110496 conv2d_2: Conv2D input: output: (None, 24, 24, 32) (None, 22, 22, 32) 139951372597400->139951356110496 139951372122040 activation_2: Activation input: output: (None, 22, 22, 32) (None, 22, 22, 32) 139951356110496->139951372122040 139951372121928 max_pooling2d_2: MaxPooling2D input: output: (None, 22, 22, 32) (None, 11, 11, 32) 139951372122040->139951372121928 139951372201936 conv2d_3: Conv2D input: output: (None, 11, 11, 32) (None, 9, 9, 64) 139951372121928->139951372201936 139951372277688 activation_3: Activation input: output: (None, 9, 9, 64) (None, 9, 9, 64) 139951372201936->139951372277688 139951372277576 max_pooling2d_3: MaxPooling2D input: output: (None, 9, 9, 64) (None, 4, 4, 64) 139951372277688->139951372277576 139951371833296 flatten_1: Flatten input: output: (None, 4, 4, 64) (None, 1024) 139951372277576->139951371833296 139951371831168 dense_1: Dense input: output: (None, 1024) (None, 64) 139951371833296->139951371831168 139951371897936 activation_4: Activation input: output: (None, 64) (None, 64) 139951371831168->139951371897936 139951371898216 dropout_1: Dropout input: output: (None, 64) (None, 64) 139951371897936->139951371898216 139951371898664 dense_2: Dense input: output: (None, 64) (None, 1) 139951371898216->139951371898664 139951371623560 activation_5: Activation input: output: (None, 1) (None, 1) 139951371898664->139951371623560

In [ ]: