diff --git a/README.md b/README.md index ccb3ecc..4b67903 100644 --- a/README.md +++ b/README.md @@ -1 +1,14 @@ -# finetune_neural_network \ No newline at end of file +# finetune_neural_network + +Starter Scripts to fine-tune Convolutional Neural Networks in Keras + +Implementation is available for the following CNN models: + +VGG16 - vgg16.py +VGG19 - vgg19.py +GoogLeNet (InceptionV1) - googlenet.py +InceptionV3 - inception_v3.py +ResNet - resnet.py + +ImageNet pretrained data should be stored in the `cache` directory. The directory is currently empty. Follow the link provided in the individual model files to dowload the data into this directory. + diff --git a/googlenet.py b/googlenet.py new file mode 100644 index 0000000..655d7eb --- /dev/null +++ b/googlenet.py @@ -0,0 +1,279 @@ +# -*- coding: utf-8 -*- + +from keras.models import Sequential +from keras.optimizers import SGD +from keras.optimizers import Adam +from keras.utils import np_utils +from keras.models import model_from_json +from keras.models import Model +from keras.layers import Input, Dense, Convolution2D, MaxPooling2D, AveragePooling2D, ZeroPadding2D, Dropout, Flatten, merge, Reshape, Activation +from keras.layers.advanced_activations import LeakyReLU, PReLU +from keras.layers.normalization import BatchNormalization +from keras import regularizers +from keras import backend as K +from keras.preprocessing import image + +from keras.layers.core import Layer +import theano.tensor as T + +from sklearn.metrics import log_loss, accuracy_score, confusion_matrix + +class LRN(Layer): + """ + Custom Layer for Local Response Normalization (LRN) + """ + + def __init__(self, alpha=0.0001,k=1,beta=0.75,n=5, **kwargs): + self.alpha = alpha + self.k = k + self.beta = beta + self.n = n + super(LRN, self).__init__(**kwargs) + + def call(self, x, mask=None): + b, ch, r, c = x.shape + half_n = self.n // 2 # half the local region + input_sqr = T.sqr(x) # square the input + extra_channels = T.alloc(0., b, ch + 2*half_n, r, c) # make an empty tensor with zero pads along channel dimension + input_sqr = T.set_subtensor(extra_channels[:, half_n:half_n+ch, :, :],input_sqr) # set the center to be the squared input + scale = self.k # offset for the scale + norm_alpha = self.alpha / self.n # normalized alpha + for i in range(self.n): + scale += norm_alpha * input_sqr[:, i:i+ch, :, :] + scale = scale ** self.beta + x = x / scale + return x + + def get_config(self): + config = {"alpha": self.alpha, + "k": self.k, + "beta": self.beta, + "n": self.n} + base_config = super(LRN, self).get_config() + return dict(list(base_config.items()) + list(config.items())) + + +class PoolHelper(Layer): + """ + Reconcile Keras and Caffe weights + """ + + def __init__(self, **kwargs): + super(PoolHelper, self).__init__(**kwargs) + + def call(self, x, mask=None): + return x[:,:,1:,1:] + + def get_config(self): + config = {} + base_config = super(PoolHelper, self).get_config() + return dict(list(base_config.items()) + list(config.items())) + +def googlenet_model(img_rows, img_cols, channel=1, num_class=None): + """ + GoogLeNet a.k.a. Inception v1 for Keras + + Model Schema is based on + https://gist.github.com/joelouismarino/a2ede9ab3928f999575423b9887abd14 + + ImageNet Pretrained Weights + https://drive.google.com/open?id=0B319laiAPjU3RE1maU9MMlh2dnc + + Blog Post: + http://joelouismarino.github.io/blog_posts/blog_googlenet_keras.html + + Parameters: + img_rows, img_cols - resolution of inputs + channel - 1 for grayscale, 3 for color + num_class - number of class labels for our classification task + """ + + input = Input(shape=(channel, img_rows, img_cols)) + conv1_7x7_s2 = Convolution2D(64,7,7,subsample=(2,2),border_mode='same',activation='relu',name='conv1/7x7_s2',W_regularizer=l2(0.0002))(input) + conv1_zero_pad = ZeroPadding2D(padding=(1, 1))(conv1_7x7_s2) + pool1_helper = PoolHelper()(conv1_zero_pad) + pool1_3x3_s2 = MaxPooling2D(pool_size=(3,3),strides=(2,2),border_mode='valid',name='pool1/3x3_s2')(pool1_helper) + pool1_norm1 = LRN(name='pool1/norm1')(pool1_3x3_s2) + conv2_3x3_reduce = Convolution2D(64,1,1,border_mode='same',activation='relu',name='conv2/3x3_reduce',W_regularizer=l2(0.0002))(pool1_norm1) + conv2_3x3 = Convolution2D(192,3,3,border_mode='same',activation='relu',name='conv2/3x3',W_regularizer=l2(0.0002))(conv2_3x3_reduce) + conv2_norm2 = LRN(name='conv2/norm2')(conv2_3x3) + conv2_zero_pad = ZeroPadding2D(padding=(1, 1))(conv2_norm2) + pool2_helper = PoolHelper()(conv2_zero_pad) + pool2_3x3_s2 = MaxPooling2D(pool_size=(3,3),strides=(2,2),border_mode='valid',name='pool2/3x3_s2')(pool2_helper) + + inception_3a_1x1 = Convolution2D(64,1,1,border_mode='same',activation='relu',name='inception_3a/1x1',W_regularizer=l2(0.0002))(pool2_3x3_s2) + inception_3a_3x3_reduce = Convolution2D(96,1,1,border_mode='same',activation='relu',name='inception_3a/3x3_reduce',W_regularizer=l2(0.0002))(pool2_3x3_s2) + inception_3a_3x3 = Convolution2D(128,3,3,border_mode='same',activation='relu',name='inception_3a/3x3',W_regularizer=l2(0.0002))(inception_3a_3x3_reduce) + inception_3a_5x5_reduce = Convolution2D(16,1,1,border_mode='same',activation='relu',name='inception_3a/5x5_reduce',W_regularizer=l2(0.0002))(pool2_3x3_s2) + inception_3a_5x5 = Convolution2D(32,5,5,border_mode='same',activation='relu',name='inception_3a/5x5',W_regularizer=l2(0.0002))(inception_3a_5x5_reduce) + inception_3a_pool = MaxPooling2D(pool_size=(3,3),strides=(1,1),border_mode='same',name='inception_3a/pool')(pool2_3x3_s2) + inception_3a_pool_proj = Convolution2D(32,1,1,border_mode='same',activation='relu',name='inception_3a/pool_proj',W_regularizer=l2(0.0002))(inception_3a_pool) + inception_3a_output = merge([inception_3a_1x1,inception_3a_3x3,inception_3a_5x5,inception_3a_pool_proj],mode='concat',concat_axis=1,name='inception_3a/output') + + inception_3b_1x1 = Convolution2D(128,1,1,border_mode='same',activation='relu',name='inception_3b/1x1',W_regularizer=l2(0.0002))(inception_3a_output) + inception_3b_3x3_reduce = Convolution2D(128,1,1,border_mode='same',activation='relu',name='inception_3b/3x3_reduce',W_regularizer=l2(0.0002))(inception_3a_output) + inception_3b_3x3 = Convolution2D(192,3,3,border_mode='same',activation='relu',name='inception_3b/3x3',W_regularizer=l2(0.0002))(inception_3b_3x3_reduce) + inception_3b_5x5_reduce = Convolution2D(32,1,1,border_mode='same',activation='relu',name='inception_3b/5x5_reduce',W_regularizer=l2(0.0002))(inception_3a_output) + inception_3b_5x5 = Convolution2D(96,5,5,border_mode='same',activation='relu',name='inception_3b/5x5',W_regularizer=l2(0.0002))(inception_3b_5x5_reduce) + inception_3b_pool = MaxPooling2D(pool_size=(3,3),strides=(1,1),border_mode='same',name='inception_3b/pool')(inception_3a_output) + inception_3b_pool_proj = Convolution2D(64,1,1,border_mode='same',activation='relu',name='inception_3b/pool_proj',W_regularizer=l2(0.0002))(inception_3b_pool) + inception_3b_output = merge([inception_3b_1x1,inception_3b_3x3,inception_3b_5x5,inception_3b_pool_proj],mode='concat',concat_axis=1,name='inception_3b/output') + + inception_3b_output_zero_pad = ZeroPadding2D(padding=(1, 1))(inception_3b_output) + pool3_helper = PoolHelper()(inception_3b_output_zero_pad) + pool3_3x3_s2 = MaxPooling2D(pool_size=(3,3),strides=(2,2),border_mode='valid',name='pool3/3x3_s2')(pool3_helper) + + inception_4a_1x1 = Convolution2D(192,1,1,border_mode='same',activation='relu',name='inception_4a/1x1',W_regularizer=l2(0.0002))(pool3_3x3_s2) + inception_4a_3x3_reduce = Convolution2D(96,1,1,border_mode='same',activation='relu',name='inception_4a/3x3_reduce',W_regularizer=l2(0.0002))(pool3_3x3_s2) + inception_4a_3x3 = Convolution2D(208,3,3,border_mode='same',activation='relu',name='inception_4a/3x3',W_regularizer=l2(0.0002))(inception_4a_3x3_reduce) + inception_4a_5x5_reduce = Convolution2D(16,1,1,border_mode='same',activation='relu',name='inception_4a/5x5_reduce',W_regularizer=l2(0.0002))(pool3_3x3_s2) + inception_4a_5x5 = Convolution2D(48,5,5,border_mode='same',activation='relu',name='inception_4a/5x5',W_regularizer=l2(0.0002))(inception_4a_5x5_reduce) + inception_4a_pool = MaxPooling2D(pool_size=(3,3),strides=(1,1),border_mode='same',name='inception_4a/pool')(pool3_3x3_s2) + inception_4a_pool_proj = Convolution2D(64,1,1,border_mode='same',activation='relu',name='inception_4a/pool_proj',W_regularizer=l2(0.0002))(inception_4a_pool) + inception_4a_output = merge([inception_4a_1x1,inception_4a_3x3,inception_4a_5x5,inception_4a_pool_proj],mode='concat',concat_axis=1,name='inception_4a/output') + + loss1_ave_pool = AveragePooling2D(pool_size=(5,5),strides=(3,3),name='loss1/ave_pool')(inception_4a_output) + loss1_conv = Convolution2D(128,1,1,border_mode='same',activation='relu',name='loss1/conv',W_regularizer=l2(0.0002))(loss1_ave_pool) + loss1_flat = Flatten()(loss1_conv) + loss1_fc = Dense(1024,activation='relu',name='loss1/fc',W_regularizer=l2(0.0002))(loss1_flat) + loss1_drop_fc = Dropout(0.7)(loss1_fc) + loss1_classifier = Dense(1000,name='loss1/classifier',W_regularizer=l2(0.0002))(loss1_drop_fc) + loss1_classifier_act = Activation('softmax')(loss1_classifier) + + inception_4b_1x1 = Convolution2D(160,1,1,border_mode='same',activation='relu',name='inception_4b/1x1',W_regularizer=l2(0.0002))(inception_4a_output) + inception_4b_3x3_reduce = Convolution2D(112,1,1,border_mode='same',activation='relu',name='inception_4b/3x3_reduce',W_regularizer=l2(0.0002))(inception_4a_output) + inception_4b_3x3 = Convolution2D(224,3,3,border_mode='same',activation='relu',name='inception_4b/3x3',W_regularizer=l2(0.0002))(inception_4b_3x3_reduce) + inception_4b_5x5_reduce = Convolution2D(24,1,1,border_mode='same',activation='relu',name='inception_4b/5x5_reduce',W_regularizer=l2(0.0002))(inception_4a_output) + inception_4b_5x5 = Convolution2D(64,5,5,border_mode='same',activation='relu',name='inception_4b/5x5',W_regularizer=l2(0.0002))(inception_4b_5x5_reduce) + inception_4b_pool = MaxPooling2D(pool_size=(3,3),strides=(1,1),border_mode='same',name='inception_4b/pool')(inception_4a_output) + inception_4b_pool_proj = Convolution2D(64,1,1,border_mode='same',activation='relu',name='inception_4b/pool_proj',W_regularizer=l2(0.0002))(inception_4b_pool) + inception_4b_output = merge([inception_4b_1x1,inception_4b_3x3,inception_4b_5x5,inception_4b_pool_proj],mode='concat',concat_axis=1,name='inception_4b_output') + + inception_4c_1x1 = Convolution2D(128,1,1,border_mode='same',activation='relu',name='inception_4c/1x1',W_regularizer=l2(0.0002))(inception_4b_output) + inception_4c_3x3_reduce = Convolution2D(128,1,1,border_mode='same',activation='relu',name='inception_4c/3x3_reduce',W_regularizer=l2(0.0002))(inception_4b_output) + inception_4c_3x3 = Convolution2D(256,3,3,border_mode='same',activation='relu',name='inception_4c/3x3',W_regularizer=l2(0.0002))(inception_4c_3x3_reduce) + inception_4c_5x5_reduce = Convolution2D(24,1,1,border_mode='same',activation='relu',name='inception_4c/5x5_reduce',W_regularizer=l2(0.0002))(inception_4b_output) + inception_4c_5x5 = Convolution2D(64,5,5,border_mode='same',activation='relu',name='inception_4c/5x5',W_regularizer=l2(0.0002))(inception_4c_5x5_reduce) + inception_4c_pool = MaxPooling2D(pool_size=(3,3),strides=(1,1),border_mode='same',name='inception_4c/pool')(inception_4b_output) + inception_4c_pool_proj = Convolution2D(64,1,1,border_mode='same',activation='relu',name='inception_4c/pool_proj',W_regularizer=l2(0.0002))(inception_4c_pool) + inception_4c_output = merge([inception_4c_1x1,inception_4c_3x3,inception_4c_5x5,inception_4c_pool_proj],mode='concat',concat_axis=1,name='inception_4c/output') + + inception_4d_1x1 = Convolution2D(112,1,1,border_mode='same',activation='relu',name='inception_4d/1x1',W_regularizer=l2(0.0002))(inception_4c_output) + inception_4d_3x3_reduce = Convolution2D(144,1,1,border_mode='same',activation='relu',name='inception_4d/3x3_reduce',W_regularizer=l2(0.0002))(inception_4c_output) + inception_4d_3x3 = Convolution2D(288,3,3,border_mode='same',activation='relu',name='inception_4d/3x3',W_regularizer=l2(0.0002))(inception_4d_3x3_reduce) + inception_4d_5x5_reduce = Convolution2D(32,1,1,border_mode='same',activation='relu',name='inception_4d/5x5_reduce',W_regularizer=l2(0.0002))(inception_4c_output) + inception_4d_5x5 = Convolution2D(64,5,5,border_mode='same',activation='relu',name='inception_4d/5x5',W_regularizer=l2(0.0002))(inception_4d_5x5_reduce) + inception_4d_pool = MaxPooling2D(pool_size=(3,3),strides=(1,1),border_mode='same',name='inception_4d/pool')(inception_4c_output) + inception_4d_pool_proj = Convolution2D(64,1,1,border_mode='same',activation='relu',name='inception_4d/pool_proj',W_regularizer=l2(0.0002))(inception_4d_pool) + inception_4d_output = merge([inception_4d_1x1,inception_4d_3x3,inception_4d_5x5,inception_4d_pool_proj],mode='concat',concat_axis=1,name='inception_4d/output') + + loss2_ave_pool = AveragePooling2D(pool_size=(5,5),strides=(3,3),name='loss2/ave_pool')(inception_4d_output) + loss2_conv = Convolution2D(128,1,1,border_mode='same',activation='relu',name='loss2/conv',W_regularizer=l2(0.0002))(loss2_ave_pool) + loss2_flat = Flatten()(loss2_conv) + loss2_fc = Dense(1024,activation='relu',name='loss2/fc',W_regularizer=l2(0.0002))(loss2_flat) + loss2_drop_fc = Dropout(0.7)(loss2_fc) + loss2_classifier = Dense(1000,name='loss2/classifier',W_regularizer=l2(0.0002))(loss2_drop_fc) + loss2_classifier_act = Activation('softmax')(loss2_classifier) + + inception_4e_1x1 = Convolution2D(256,1,1,border_mode='same',activation='relu',name='inception_4e/1x1',W_regularizer=l2(0.0002))(inception_4d_output) + inception_4e_3x3_reduce = Convolution2D(160,1,1,border_mode='same',activation='relu',name='inception_4e/3x3_reduce',W_regularizer=l2(0.0002))(inception_4d_output) + inception_4e_3x3 = Convolution2D(320,3,3,border_mode='same',activation='relu',name='inception_4e/3x3',W_regularizer=l2(0.0002))(inception_4e_3x3_reduce) + inception_4e_5x5_reduce = Convolution2D(32,1,1,border_mode='same',activation='relu',name='inception_4e/5x5_reduce',W_regularizer=l2(0.0002))(inception_4d_output) + inception_4e_5x5 = Convolution2D(128,5,5,border_mode='same',activation='relu',name='inception_4e/5x5',W_regularizer=l2(0.0002))(inception_4e_5x5_reduce) + inception_4e_pool = MaxPooling2D(pool_size=(3,3),strides=(1,1),border_mode='same',name='inception_4e/pool')(inception_4d_output) + inception_4e_pool_proj = Convolution2D(128,1,1,border_mode='same',activation='relu',name='inception_4e/pool_proj',W_regularizer=l2(0.0002))(inception_4e_pool) + inception_4e_output = merge([inception_4e_1x1,inception_4e_3x3,inception_4e_5x5,inception_4e_pool_proj],mode='concat',concat_axis=1,name='inception_4e/output') + + inception_4e_output_zero_pad = ZeroPadding2D(padding=(1, 1))(inception_4e_output) + pool4_helper = PoolHelper()(inception_4e_output_zero_pad) + pool4_3x3_s2 = MaxPooling2D(pool_size=(3,3),strides=(2,2),border_mode='valid',name='pool4/3x3_s2')(pool4_helper) + + inception_5a_1x1 = Convolution2D(256,1,1,border_mode='same',activation='relu',name='inception_5a/1x1',W_regularizer=l2(0.0002))(pool4_3x3_s2) + inception_5a_3x3_reduce = Convolution2D(160,1,1,border_mode='same',activation='relu',name='inception_5a/3x3_reduce',W_regularizer=l2(0.0002))(pool4_3x3_s2) + inception_5a_3x3 = Convolution2D(320,3,3,border_mode='same',activation='relu',name='inception_5a/3x3',W_regularizer=l2(0.0002))(inception_5a_3x3_reduce) + inception_5a_5x5_reduce = Convolution2D(32,1,1,border_mode='same',activation='relu',name='inception_5a/5x5_reduce',W_regularizer=l2(0.0002))(pool4_3x3_s2) + inception_5a_5x5 = Convolution2D(128,5,5,border_mode='same',activation='relu',name='inception_5a/5x5',W_regularizer=l2(0.0002))(inception_5a_5x5_reduce) + inception_5a_pool = MaxPooling2D(pool_size=(3,3),strides=(1,1),border_mode='same',name='inception_5a/pool')(pool4_3x3_s2) + inception_5a_pool_proj = Convolution2D(128,1,1,border_mode='same',activation='relu',name='inception_5a/pool_proj',W_regularizer=l2(0.0002))(inception_5a_pool) + inception_5a_output = merge([inception_5a_1x1,inception_5a_3x3,inception_5a_5x5,inception_5a_pool_proj],mode='concat',concat_axis=1,name='inception_5a/output') + + inception_5b_1x1 = Convolution2D(384,1,1,border_mode='same',activation='relu',name='inception_5b/1x1',W_regularizer=l2(0.0002))(inception_5a_output) + inception_5b_3x3_reduce = Convolution2D(192,1,1,border_mode='same',activation='relu',name='inception_5b/3x3_reduce',W_regularizer=l2(0.0002))(inception_5a_output) + inception_5b_3x3 = Convolution2D(384,3,3,border_mode='same',activation='relu',name='inception_5b/3x3',W_regularizer=l2(0.0002))(inception_5b_3x3_reduce) + inception_5b_5x5_reduce = Convolution2D(48,1,1,border_mode='same',activation='relu',name='inception_5b/5x5_reduce',W_regularizer=l2(0.0002))(inception_5a_output) + inception_5b_5x5 = Convolution2D(128,5,5,border_mode='same',activation='relu',name='inception_5b/5x5',W_regularizer=l2(0.0002))(inception_5b_5x5_reduce) + inception_5b_pool = MaxPooling2D(pool_size=(3,3),strides=(1,1),border_mode='same',name='inception_5b/pool')(inception_5a_output) + inception_5b_pool_proj = Convolution2D(128,1,1,border_mode='same',activation='relu',name='inception_5b/pool_proj',W_regularizer=l2(0.0002))(inception_5b_pool) + inception_5b_output = merge([inception_5b_1x1,inception_5b_3x3,inception_5b_5x5,inception_5b_pool_proj],mode='concat',concat_axis=1,name='inception_5b/output') + + pool5_7x7_s1 = AveragePooling2D(pool_size=(7,7),strides=(1,1),name='pool5/7x7_s2')(inception_5b_output) + loss3_flat = Flatten()(pool5_7x7_s1) + pool5_drop_7x7_s1 = Dropout(0.4)(loss3_flat) + loss3_classifier = Dense(1000,name='loss3/classifier',W_regularizer=l2(0.0002))(pool5_drop_7x7_s1) + loss3_classifier_act = Activation('softmax',name='prob')(loss3_classifier) + + # Create model + model = Model(input=input, output=[loss1_classifier_act,loss2_classifier_act,loss3_classifier_act]) + + # Load ImageNet pre-trained data + model.load_weights('cache/inception_v1_weights.h5') + + # Truncate and replace softmax layer for transfer learning + # Cannot use model.layers.pop() since model is not of Sequential() type + # The method below works since pre-trained weights are stored in layers but not in the model + loss3_classifier_statefarm = Dense(num_class,name='loss3/classifier',W_regularizer=l2(0.0002))(pool5_drop_7x7_s1) + loss3_classifier_act_statefarm = Activation('softmax',name='prob')(loss3_classifier_statefarm) + loss2_classifier_statefarm = Dense(num_class,name='loss2/classifier',W_regularizer=l2(0.0002))(loss2_drop_fc) + loss2_classifier_act_statefarm = Activation('softmax')(loss2_classifier_statefarm) + loss1_classifier_statefarm = Dense(num_class,name='loss1/classifier',W_regularizer=l2(0.0002))(loss1_drop_fc) + loss1_classifier_act_statefarm = Activation('softmax')(loss1_classifier_statefarm) + + # Create another model with our customized softmax + model = Model(input=input, output=[loss1_classifier_act_statefarm,loss2_classifier_act_statefarm,loss3_classifier_act_statefarm]) + + # Learning rate is changed to 0.001 + sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True) + model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy']) + + return model + +def load_data(): + """ + Load dataset and split data into training and validation sets + """ + return None + +if __name__ == '__main__': + + # Fine-tune Example + img_rows, img_cols = 224, 224 # Resolution of inputs + channel = 3 + num_class = 10 + batch_size = 16 + nb_epoch = 3 + + # TODO: Load training and validation sets + X_train, X_valid, Y_train, Y_valid = load_data() + + # Load our model + model = googlenet_model(img_rows, img_cols, channel, num_class) + + # Start Fine-tuning. + # Notice that googlenet takes 3 sets of labels for outputs, one for each auxillary classifier + model.fit(X_train, [Y_train, Y_train, Y_train], + batch_size=batch_size, + nb_epoch=nb_epoch, + shuffle=True, + verbose=1, + validation_data=(X_valid, [Y_valid, Y_valid, Y_valid]), + ) + + # Make predictions + predictions_valid = model.predict(X_valid, batch_size=batch_size, verbose=1) + + # Combine 3 set of outputs using averaging + predictions_valid = sum(predictions_valid)/len(predictions_valid) + + # Cross-entropy loss score + score = log_loss(Y_valid, predictions_valid) + diff --git a/inception_v3.py b/inception_v3.py new file mode 100644 index 0000000..0d6ec07 --- /dev/null +++ b/inception_v3.py @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- + +from keras.models import Sequential +from keras.optimizers import SGD +from keras.optimizers import Adam +from keras.utils import np_utils +from keras.models import model_from_json +from keras.models import Model +from keras.layers import Input, Dense, Convolution2D, MaxPooling2D, AveragePooling2D, ZeroPadding2D, Dropout, Flatten, merge, Reshape, Activation +from keras.layers.advanced_activations import LeakyReLU, PReLU +from keras.layers.normalization import BatchNormalization +from keras import regularizers +from keras import backend as K +from keras.preprocessing import image + +from sklearn.metrics import log_loss, accuracy_score, confusion_matrix + +def conv2d_bn(x, nb_filter, nb_row, nb_col, + border_mode='same', subsample=(1, 1), + name=None): + """ + Utility function to apply conv + BN for Inception V3. + """ + if name is not None: + bn_name = name + '_bn' + conv_name = name + '_conv' + else: + bn_name = None + conv_name = None + bn_axis = 1 + x = Convolution2D(nb_filter, nb_row, nb_col, + subsample=subsample, + activation='relu', + border_mode=border_mode, + name=conv_name)(x) + x = BatchNormalization(axis=bn_axis, name=bn_name)(x) + return x + +def inception_v3_model(img_rows, img_cols, channel=1, num_class=None): + """ + Inception-V3 Model for Keras + + Model Schema is based on + https://github.com/fchollet/deep-learning-models/blob/master/inception_v3.py + + ImageNet Pretrained Weights + https://github.com/fchollet/deep-learning-models/releases/download/v0.2/inception_v3_weights_th_dim_ordering_th_kernels.h5 + + Parameters: + img_rows, img_cols - resolution of inputs + channel - 1 for grayscale, 3 for color + num_class - number of class labels for our classification task + """ + channel_axis = 1 + img_input = Input(shape=(channels, img_rows, img_cols)) + x = conv2d_bn(img_input, 32, 3, 3, subsample=(2, 2), border_mode='valid') + x = conv2d_bn(x, 32, 3, 3, border_mode='valid') + x = conv2d_bn(x, 64, 3, 3) + x = MaxPooling2D((3, 3), strides=(2, 2))(x) + + x = conv2d_bn(x, 80, 1, 1, border_mode='valid') + x = conv2d_bn(x, 192, 3, 3, border_mode='valid') + x = MaxPooling2D((3, 3), strides=(2, 2))(x) + + # mixed 0, 1, 2: 35 x 35 x 256 + for i in range(3): + branch1x1 = conv2d_bn(x, 64, 1, 1) + + branch5x5 = conv2d_bn(x, 48, 1, 1) + branch5x5 = conv2d_bn(branch5x5, 64, 5, 5) + + branch3x3dbl = conv2d_bn(x, 64, 1, 1) + branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3) + branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3) + + branch_pool = AveragePooling2D( + (3, 3), strides=(1, 1), border_mode='same')(x) + branch_pool = conv2d_bn(branch_pool, 32, 1, 1) + x = merge([branch1x1, branch5x5, branch3x3dbl, branch_pool], + mode='concat', concat_axis=channel_axis, + name='mixed' + str(i)) + + # mixed 3: 17 x 17 x 768 + branch3x3 = conv2d_bn(x, 384, 3, 3, subsample=(2, 2), border_mode='valid') + + branch3x3dbl = conv2d_bn(x, 64, 1, 1) + branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3) + branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3, + subsample=(2, 2), border_mode='valid') + + branch_pool = MaxPooling2D((3, 3), strides=(2, 2))(x) + x = merge([branch3x3, branch3x3dbl, branch_pool], + mode='concat', concat_axis=channel_axis, + name='mixed3') + + # mixed 4: 17 x 17 x 768 + branch1x1 = conv2d_bn(x, 192, 1, 1) + + branch7x7 = conv2d_bn(x, 128, 1, 1) + branch7x7 = conv2d_bn(branch7x7, 128, 1, 7) + branch7x7 = conv2d_bn(branch7x7, 192, 7, 1) + + branch7x7dbl = conv2d_bn(x, 128, 1, 1) + branch7x7dbl = conv2d_bn(branch7x7dbl, 128, 7, 1) + branch7x7dbl = conv2d_bn(branch7x7dbl, 128, 1, 7) + branch7x7dbl = conv2d_bn(branch7x7dbl, 128, 7, 1) + branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7) + + branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same')(x) + branch_pool = conv2d_bn(branch_pool, 192, 1, 1) + x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], + mode='concat', concat_axis=channel_axis, + name='mixed4') + + # mixed 5, 6: 17 x 17 x 768 + for i in range(2): + branch1x1 = conv2d_bn(x, 192, 1, 1) + + branch7x7 = conv2d_bn(x, 160, 1, 1) + branch7x7 = conv2d_bn(branch7x7, 160, 1, 7) + branch7x7 = conv2d_bn(branch7x7, 192, 7, 1) + + branch7x7dbl = conv2d_bn(x, 160, 1, 1) + branch7x7dbl = conv2d_bn(branch7x7dbl, 160, 7, 1) + branch7x7dbl = conv2d_bn(branch7x7dbl, 160, 1, 7) + branch7x7dbl = conv2d_bn(branch7x7dbl, 160, 7, 1) + branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7) + + branch_pool = AveragePooling2D( + (3, 3), strides=(1, 1), border_mode='same')(x) + branch_pool = conv2d_bn(branch_pool, 192, 1, 1) + x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], + mode='concat', concat_axis=channel_axis, + name='mixed' + str(5 + i)) + + # mixed 7: 17 x 17 x 768 + branch1x1 = conv2d_bn(x, 192, 1, 1) + + branch7x7 = conv2d_bn(x, 192, 1, 1) + branch7x7 = conv2d_bn(branch7x7, 192, 1, 7) + branch7x7 = conv2d_bn(branch7x7, 192, 7, 1) + + branch7x7dbl = conv2d_bn(x, 160, 1, 1) + branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 7, 1) + branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7) + branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 7, 1) + branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7) + + branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same')(x) + branch_pool = conv2d_bn(branch_pool, 192, 1, 1) + x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], + mode='concat', concat_axis=channel_axis, + name='mixed7') + + # mixed 8: 8 x 8 x 1280 + branch3x3 = conv2d_bn(x, 192, 1, 1) + branch3x3 = conv2d_bn(branch3x3, 320, 3, 3, + subsample=(2, 2), border_mode='valid') + + branch7x7x3 = conv2d_bn(x, 192, 1, 1) + branch7x7x3 = conv2d_bn(branch7x7x3, 192, 1, 7) + branch7x7x3 = conv2d_bn(branch7x7x3, 192, 7, 1) + branch7x7x3 = conv2d_bn(branch7x7x3, 192, 3, 3, + subsample=(2, 2), border_mode='valid') + + branch_pool = AveragePooling2D((3, 3), strides=(2, 2))(x) + x = merge([branch3x3, branch7x7x3, branch_pool], + mode='concat', concat_axis=channel_axis, + name='mixed8') + + # mixed 9: 8 x 8 x 2048 + for i in range(2): + branch1x1 = conv2d_bn(x, 320, 1, 1) + + branch3x3 = conv2d_bn(x, 384, 1, 1) + branch3x3_1 = conv2d_bn(branch3x3, 384, 1, 3) + branch3x3_2 = conv2d_bn(branch3x3, 384, 3, 1) + branch3x3 = merge([branch3x3_1, branch3x3_2], + mode='concat', concat_axis=channel_axis, + name='mixed9_' + str(i)) + + branch3x3dbl = conv2d_bn(x, 448, 1, 1) + branch3x3dbl = conv2d_bn(branch3x3dbl, 384, 3, 3) + branch3x3dbl_1 = conv2d_bn(branch3x3dbl, 384, 1, 3) + branch3x3dbl_2 = conv2d_bn(branch3x3dbl, 384, 3, 1) + branch3x3dbl = merge([branch3x3dbl_1, branch3x3dbl_2], + mode='concat', concat_axis=channel_axis) + + branch_pool = AveragePooling2D( + (3, 3), strides=(1, 1), border_mode='same')(x) + branch_pool = conv2d_bn(branch_pool, 192, 1, 1) + x = merge([branch1x1, branch3x3, branch3x3dbl, branch_pool], + mode='concat', concat_axis=channel_axis, + name='mixed' + str(9 + i)) + + # Fully Connected Softmax Layer + x_fc = AveragePooling2D((8, 8), strides=(8, 8), name='avg_pool')(x) + x_fc = Flatten(name='flatten')(x_fc) + x_fc = Dense(1000, activation='softmax', name='predictions')(x_fc) + + # Create model + model = Model(img_input, x_fc) + + # Load ImageNet pre-trained data + model.load_weights('cache/inception_v3_weights_th_dim_ordering_th_kernels.h5') + + # Truncate and replace softmax layer for transfer learning + # Cannot use model.layers.pop() since model is not of Sequential() type + # The method below works since pre-trained weights are stored in layers but not in the model + x_newfc = AveragePooling2D((8, 8), strides=(8, 8), name='avg_pool')(x) + x_newfc = Flatten(name='flatten')(x_newfc) + x_newfc = Dense(num_class, activation='softmax', name='predictions')(x_newfc) + + # Create another model with our customized softmax + model = Model(img_input, x_newfc) + + # Learning rate is changed to 0.001 + sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True) + model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy']) + + return model + +def load_data(): + """ + Load dataset and split data into training and validation sets + """ + return None + +if __name__ == '__main__': + + # Fine-tune Example + img_rows, img_cols = 299, 299 # Resolution of inputs + channel = 3 + num_class = 10 + batch_size = 16 + nb_epoch = 3 + + # TODO: Load training and validation sets + X_train, X_valid, Y_train, Y_valid = load_data() + + # Load our model + model = inception_v3_model(img_rows, img_cols, channel, num_class) + + # Start Fine-tuning + model.fit(train_data, test_data, + batch_size=batch_size, + nb_epoch=nb_epoch, + shuffle=True, + verbose=1, + validation_data=(X_valid, Y_valid), + ) + + # Make predictions + predictions_valid = model.predict(X_valid, batch_size=batch_size, verbose=1) + + # Cross-entropy loss score + score = log_loss(Y_valid, predictions_valid) + diff --git a/resnet.py b/resnet.py new file mode 100644 index 0000000..92f8c8c --- /dev/null +++ b/resnet.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- + +from keras.models import Sequential +from keras.optimizers import SGD +from keras.optimizers import Adam +from keras.utils import np_utils +from keras.models import model_from_json +from keras.models import Model +from keras.layers import Input, Dense, Convolution2D, MaxPooling2D, AveragePooling2D, ZeroPadding2D, Dropout, Flatten, merge, Reshape, Activation +from keras.layers.advanced_activations import LeakyReLU, PReLU +from keras.layers.normalization import BatchNormalization +from keras import regularizers +from keras import backend as K +from keras.preprocessing import image + +from sklearn.metrics import log_loss, accuracy_score, confusion_matrix + +def identity_block(input_tensor, kernel_size, filters, stage, block): + """ + The identity_block is the block that has no conv layer at shortcut + Arguments + input_tensor: input tensor + kernel_size: defualt 3, the kernel size of middle conv layer at main path + filters: list of integers, the nb_filters of 3 conv layer at main path + stage: integer, current stage label, used for generating layer names + block: 'a','b'..., current block label, used for generating layer names + """ + + nb_filter1, nb_filter2, nb_filter3 = filters + bn_axis = 1 + conv_name_base = 'res' + str(stage) + block + '_branch' + bn_name_base = 'bn' + str(stage) + block + '_branch' + + x = Convolution2D(nb_filter1, 1, 1, name=conv_name_base + '2a')(input_tensor) + x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x) + x = Activation('relu')(x) + + x = Convolution2D(nb_filter2, kernel_size, kernel_size, + border_mode='same', name=conv_name_base + '2b')(x) + x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x) + x = Activation('relu')(x) + + x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) + x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x) + + x = merge([x, input_tensor], mode='sum') + x = Activation('relu')(x) + return x + +def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)): + """ + conv_block is the block that has a conv layer at shortcut + # Arguments + input_tensor: input tensor + kernel_size: defualt 3, the kernel size of middle conv layer at main path + filters: list of integers, the nb_filters of 3 conv layer at main path + stage: integer, current stage label, used for generating layer names + block: 'a','b'..., current block label, used for generating layer names + Note that from stage 3, the first conv layer at main path is with subsample=(2,2) + And the shortcut should have subsample=(2,2) as well + """ + + nb_filter1, nb_filter2, nb_filter3 = filters + bn_axis = 1 + conv_name_base = 'res' + str(stage) + block + '_branch' + bn_name_base = 'bn' + str(stage) + block + '_branch' + + x = Convolution2D(nb_filter1, 1, 1, subsample=strides, + name=conv_name_base + '2a')(input_tensor) + x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x) + x = Activation('relu')(x) + + x = Convolution2D(nb_filter2, kernel_size, kernel_size, border_mode='same', + name=conv_name_base + '2b')(x) + x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x) + x = Activation('relu')(x) + + x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x) + x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x) + + shortcut = Convolution2D(nb_filter3, 1, 1, subsample=strides, + name=conv_name_base + '1')(input_tensor) + shortcut = BatchNormalization(axis=bn_axis, name=bn_name_base + '1')(shortcut) + + x = merge([x, shortcut], mode='sum') + x = Activation('relu')(x) + return x + +def resnet50_model(img_rows, img_cols, color_type=1, num_class=None): + """ + Resnet Model for Keras + + Model Schema is based on + https://github.com/fchollet/deep-learning-models/blob/master/resnet50.py + + ImageNet Pretrained Weights + https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_th_dim_ordering_th_kernels.h5 + + Parameters: + img_rows, img_cols - resolution of inputs + channel - 1 for grayscale, 3 for color + num_class - number of class labels for our classification task + """ + + bn_axis = 1 + img_input = Input(shape=(color_type, img_rows, img_cols)) + x = ZeroPadding2D((3, 3))(img_input) + x = Convolution2D(64, 7, 7, subsample=(2, 2), name='conv1')(x) + x = BatchNormalization(axis=bn_axis, name='bn_conv1')(x) + x = Activation('relu')(x) + x = MaxPooling2D((3, 3), strides=(2, 2))(x) + + x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1)) + x = identity_block(x, 3, [64, 64, 256], stage=2, block='b') + x = identity_block(x, 3, [64, 64, 256], stage=2, block='c') + + x = conv_block(x, 3, [128, 128, 512], stage=3, block='a') + x = identity_block(x, 3, [128, 128, 512], stage=3, block='b') + x = identity_block(x, 3, [128, 128, 512], stage=3, block='c') + x = identity_block(x, 3, [128, 128, 512], stage=3, block='d') + + x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a') + x = identity_block(x, 3, [256, 256, 1024], stage=4, block='b') + x = identity_block(x, 3, [256, 256, 1024], stage=4, block='c') + x = identity_block(x, 3, [256, 256, 1024], stage=4, block='d') + x = identity_block(x, 3, [256, 256, 1024], stage=4, block='e') + x = identity_block(x, 3, [256, 256, 1024], stage=4, block='f') + + x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a') + x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b') + x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c') + + # Fully Connected Softmax Layer + x_fc = AveragePooling2D((7, 7), name='avg_pool')(x) + x_fc = Flatten()(x_fc) + x_fc = Dense(1000, activation='softmax', name='fc1000')(x_fc) + + # Create model + model = Model(img_input, x_fc) + + # Load ImageNet pre-trained data + model.load_weights('cache/input/resnet50_weights_th_dim_ordering_th_kernels.h5') + + # Truncate and replace softmax layer for transfer learning + # Cannot use model.layers.pop() since model is not of Sequential() type + # The method below works since pre-trained weights are stored in layers but not in the model + x_newfc = AveragePooling2D((7, 7), name='avg_pool')(x) + x_newfc = Flatten()(x_newfc) + x_newfc = Dense(num_class, activation='softmax', name='fc10')(x_newfc) + + # Create another model with our customized softmax + model = Model(img_input, x_newfc) + + # Learning rate is changed to 0.001 + sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True) + model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy']) + + return model + +def load_data(): + """ + Load dataset and split data into training and validation sets + """ + return None + + +if __name__ == '__main__': + + # Fine-tune Example + img_rows, img_cols = 224, 224 # Resolution of inputs + channel = 3 + num_class = 10 + batch_size = 16 + nb_epoch = 3 + + # TODO: Load training and validation sets + X_train, X_valid, Y_train, Y_valid = load_data() + + # Load our model + model = resnet50_model(img_rows, img_cols, channel, num_class) + + # Start Fine-tuning + model.fit(train_data, test_data, + batch_size=batch_size, + nb_epoch=nb_epoch, + shuffle=True, + verbose=1, + validation_data=(X_valid, Y_valid), + ) + + # Make predictions + predictions_valid = model.predict(X_valid, batch_size=batch_size, verbose=1) + + # Cross-entropy loss score + score = log_loss(Y_valid, predictions_valid) + diff --git a/vgg16.py b/vgg16.py new file mode 100644 index 0000000..52a0372 --- /dev/null +++ b/vgg16.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- + +from keras.models import Sequential +from keras.optimizers import SGD +from keras.optimizers import Adam +from keras.utils import np_utils +from keras.models import model_from_json +from keras.models import Model +from keras.layers import Input, Dense, Convolution2D, MaxPooling2D, AveragePooling2D, ZeroPadding2D, Dropout, Flatten, merge, Reshape, Activation +from keras.layers.advanced_activations import LeakyReLU, PReLU +from keras.layers.normalization import BatchNormalization +from keras import regularizers +from keras import backend as K +from keras.preprocessing import image + +from sklearn.metrics import log_loss, accuracy_score, confusion_matrix + +def vgg_std16_model(img_rows, img_cols, channel=1, num_class=None): + """ + VGG 16 Model for Keras + + Model Schema is based on + https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3 + + ImageNet Pretrained Weights + https://drive.google.com/file/d/0Bz7KyqmuGsilT0J5dmRCM0ROVHc/view?usp=sharing + + Parameters: + img_rows, img_cols - resolution of inputs + channel - 1 for grayscale, 3 for color + num_class - number of class labels for our classification task + """ + model = Sequential() + model.add(ZeroPadding2D((1, 1), input_shape=(channel, img_rows, img_cols))) + model.add(Convolution2D(64, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(64, 3, 3, activation='relu')) + model.add(MaxPooling2D((2, 2), strides=(2, 2))) + + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(128, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(128, 3, 3, activation='relu')) + model.add(MaxPooling2D((2, 2), strides=(2, 2))) + + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(256, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(256, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(256, 3, 3, activation='relu')) + model.add(MaxPooling2D((2, 2), strides=(2, 2))) + + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(MaxPooling2D((2, 2), strides=(2, 2))) + + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1, 1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(MaxPooling2D((2, 2), strides=(2, 2))) + + # Add Fully Connected Layer + model.add(Flatten()) + model.add(Dense(4096, activation='relu')) + model.add(Dropout(0.5)) + model.add(Dense(4096, activation='relu')) + model.add(Dropout(0.5)) + model.add(Dense(1000, activation='softmax')) + + # Loads ImageNet pre-trained data + model.load_weights('cache/vgg16_weights.h5') + + # Truncate and replace softmax layer for transfer learning + model.layers.pop() + model.outputs = [model.layers[-1].output] + model.layers[-1].outbound_nodes = [] + model.add(Dense(num_class, activation='softmax')) + + # Uncomment below to set the first 10 layers to non-trainable (weights will not be updated) + #for layer in model.layers[:10]: + # layer.trainable = False + + # Learning rate is changed to 0.001 + sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True) + model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy']) + + return model + +def load_data(): + """ + Load dataset and split data into training and validation sets + """ + return None + +if __name__ == '__main__': + + # Fine-tune Example + img_rows, img_cols = 224, 224 # Resolution of inputs + channel = 3 + num_class = 10 + batch_size = 16 + nb_epoch = 3 + + # TODO: Load training and validation sets + X_train, X_valid, Y_train, Y_valid = load_data() + + # Load our model + model = vgg_std16_model(img_rows, img_cols, channel, num_class) + + # Start Fine-tuning + model.fit(train_data, test_data, + batch_size=batch_size, + nb_epoch=nb_epoch, + shuffle=True, + verbose=1, + validation_data=(X_valid, Y_valid), + ) + + # Make predictions + predictions_valid = model.predict(X_valid, batch_size=batch_size, verbose=1) + + # Cross-entropy loss score + score = log_loss(Y_valid, predictions_valid) + diff --git a/vgg19.py b/vgg19.py new file mode 100644 index 0000000..4eaac7f --- /dev/null +++ b/vgg19.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- + +from keras.models import Sequential +from keras.optimizers import SGD +from keras.optimizers import Adam +from keras.utils import np_utils +from keras.models import model_from_json +from keras.models import Model +from keras.layers import Input, Dense, Convolution2D, MaxPooling2D, AveragePooling2D, ZeroPadding2D, Dropout, Flatten, merge, Reshape, Activation +from keras.layers.advanced_activations import LeakyReLU, PReLU +from keras.layers.normalization import BatchNormalization +from keras import regularizers +from keras import backend as K +from keras.preprocessing import image + +from sklearn.metrics import log_loss, accuracy_score, confusion_matrix + +def vgg_std19_model(img_rows, img_cols, channel=1, num_class=None): + """ + VGG 19 Model for Keras + + Model Schema is based on + https://gist.github.com/baraldilorenzo/8d096f48a1be4a2d660d + + ImageNet Pretrained Weights + https://drive.google.com/file/d/0Bz7KyqmuGsilZ2RVeVhKY0FyRmc/view?usp=sharing + + Parameters: + img_rows, img_cols - resolution of inputs + channel - 1 for grayscale, 3 for color + num_class - number of class labels for our classification task + """ + + model = Sequential() + model.add(ZeroPadding2D((1,1),input_shape=(channel, img_rows, img_cols))) + model.add(Convolution2D(64, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(64, 3, 3, activation='relu')) + model.add(MaxPooling2D((2,2), strides=(2,2))) + + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(128, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(128, 3, 3, activation='relu')) + model.add(MaxPooling2D((2,2), strides=(2,2))) + + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(256, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(256, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(256, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(256, 3, 3, activation='relu')) + model.add(MaxPooling2D((2,2), strides=(2,2))) + + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(MaxPooling2D((2,2), strides=(2,2))) + + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(ZeroPadding2D((1,1))) + model.add(Convolution2D(512, 3, 3, activation='relu')) + model.add(MaxPooling2D((2,2), strides=(2,2))) + + # Add Fully Connected Layer + model.add(Flatten()) + model.add(Dense(4096, activation='relu')) + model.add(Dropout(0.5)) + model.add(Dense(4096, activation='relu')) + model.add(Dropout(0.5)) + model.add(Dense(1000, activation='softmax')) + + # Loads ImageNet pre-trained data + model.load_weights('cache/vgg19_weights.h5') + + # Truncate and replace softmax layer for transfer learning + model.layers.pop() + model.outputs = [model.layers[-1].output] + model.layers[-1].outbound_nodes = [] + model.add(Dense(num_class, activation='softmax')) + + # Learning rate is changed to 0.001 + sgd = SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True) + model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy']) + + return model + +def load_data(): + """ + Load dataset and split data into training and validation sets + """ + return None + + +if __name__ == '__main__': + + # Fine-tune Example + img_rows, img_cols = 224, 224 # Resolution of inputs + channel = 3 + num_class = 10 + batch_size = 16 + nb_epoch = 3 + + # TODO: Load training and validation sets + X_train, X_valid, Y_train, Y_valid = load_data() + + # Load our model + model = vgg_std19_model(img_rows, img_cols, channel, num_class) + + # Start Fine-tuning + model.fit(train_data, test_data, + batch_size=batch_size, + nb_epoch=nb_epoch, + shuffle=True, + verbose=1, + validation_data=(X_valid, Y_valid), + ) + + # Make predictions + predictions_valid = model.predict(X_valid, batch_size=batch_size, verbose=1) + + # Cross-entropy loss score + score = log_loss(Y_valid, predictions_valid) +