Applying Restnet50 to Flower Classification

Import required libraries

In [ ]:
import numpy as np
import os
import shutil
from IPython.display import Image, display
from sklearn.model_selection import train_test_split
from tensorflow.python.keras.applications import ResNet50
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense, Flatten, GlobalAveragePooling2D
from tensorflow.python.keras.applications.resnet50 import preprocess_input
from tensorflow.python.keras.preprocessing.image import ImageDataGenerator

Helper functions to read flower images from dataset

In [ ]:
image_dir = '../input/flowers-recognition/flowers/flowers'

# Read all flower images (.jpg) from a folder
# The function returns both the path of the flower image and the corresponding label
# which is defined by the name of the foler in which the image is
def read_images_from_dir(base_dir, folder):
    path_folder = os.path.join(image_dir, folder)
    files_directory = os.listdir(path_folder)
    
    labels = []
    images = []
    for file in files_directory:
        if file.endswith('.jpg'):
            labels.append(folder)
            images.append(os.path.join(path_folder, file))
    return labels, images

def read_images(base_dir):
    labels = []
    images = []
    folders = os.listdir(image_dir)
    for folder in folders:
        labels_folder, images_folder = read_images_from_dir(base_dir, folder)
        labels.extend(labels_folder)
        images.extend(images_folder)
    return labels, images

labels, images = read_images(image_dir)

Show some images from the dataset

In [ ]:
from random import randrange

for i in range(3):
    random_index = randrange(len(images))
    display(Image(images[random_index]))

Split dataset into train and test

30% in the test dataset with stratified split in order to maintain the class balance in both train and test sets

In [ ]:
images_train, images_test, labels_train, labels_test = train_test_split(images, labels, test_size=0.3, random_state=8, stratify=labels)

Preprocess the images for using them with ResNet50

In [ ]:
# Remove output file directories
# shutil.rmtree('../input/output/')
In [ ]:
output_folder = '../input/output/'
train_folder = '../input/output/train'
test_folder = '../input/output/test'

def create_output_folders():
    if not os.path.exists(output_folder):
        print('Creating output directories')
        os.mkdir(output_folder)
        if not os.path.exists(train_folder):
            os.mkdir(train_folder)
            for label in set(labels):
                os.mkdir(train_folder + '/' + label)
        if not os.path.exists(test_folder):
            os.mkdir(test_folder)
            for label in set(labels):
                os.mkdir(test_folder + '/' + label)
            
def copy_files_to_train_and_validation_folders():            
    print('Copy training files to directory')
    for index, value in enumerate(images_train):
        dest = os.path.join(train_folder, labels_train[index])
        shutil.copy(value, dest)

    print('Copy test files to directory')        
    for index, value in enumerate(images_test):
        shutil.copy(value, test_folder + '/' + labels_test[index])
    
create_output_folders()
copy_files_to_train_and_validation_folders()

Create model and compile with pre-trained weights file (excluding top layer)

In [ ]:
num_classes = len(set(labels))
resnet_weights_path = '../input/resnet50/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5'

# Create model
model = Sequential()
model.add(ResNet50(include_top=False, pooling='avg', weights=resnet_weights_path))
model.add(Dense(num_classes, activation='softmax'))

# Do not train first layer (ResNet) as it is already pre-trained
model.layers[0].trainable = False

# Compile model 
model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy'])

Fit model

In [ ]:
image_size = 224
data_generator = ImageDataGenerator(preprocessing_function=preprocess_input)

train_generator = data_generator.flow_from_directory(train_folder, target_size=(image_size, image_size), batch_size=24, class_mode='categorical')
validation_generator = data_generator.flow_from_directory(test_folder, target_size=(image_size, image_size), class_mode='categorical')

model.fit_generator(train_generator, steps_per_epoch=100, validation_data=validation_generator, validation_steps=1, epochs=5)

Fit model with data augmentation

In [ ]:
image_size = 224
data_generator_aug = ImageDataGenerator(preprocessing_function=preprocess_input, horizontal_flip=True, width_shift_range=0.2, height_shift_range=0.2)

train_generator = data_generator_aug.flow_from_directory(train_folder, target_size=(image_size, image_size), batch_size=24, class_mode='categorical')
validation_generator = data_generator_aug.flow_from_directory(test_folder, target_size=(image_size, image_size), class_mode='categorical')

model.fit_generator(train_generator, steps_per_epoch=100, validation_data=validation_generator, validation_steps=1, epochs=5)