{"cells":[{"metadata":{"_uuid":"cac9915711fdcec7e8eb6431fd8dcae21649b6aa","_cell_guid":"9619b018-f7a0-4d13-90b4-f769a8906003"},"cell_type":"markdown","source":"**Building a strong image classification model from less data**\n\nThe implementation is a slight variation of the one in https://gist.github.com/fchollet/0830affa1f7f19fd47b06d4cf89ed44d\n\nMainly, in this kernel , the method flow(x,y) is used whereas, in the above gist, method flow_from_directory(directory) is used.\nFor more info, you can refer https://keras.io/preprocessing/image/\n\nThe change is made to have an appropriate kernel to deal with the way data is structured in kaggle. Appropriate changes in other parts of the source code is also done."},{"metadata":{"_uuid":"16fefbb9857aead05fe80ecbf3ffbabfae4fca22","_cell_guid":"e10726c1-a487-4d89-bf8f-7ff532592440"},"cell_type":"markdown","source":"**Perform the necessary imports.**"},{"metadata":{"_uuid":"49532c85c74dee05663bd7eda324d3df493c60ed","_cell_guid":"4f4ac6a4-708c-46ab-8269-e01978300bde","trusted":true,"collapsed":true},"cell_type":"code","source":"import os, cv2, re, random\nimport numpy as np\nimport pandas as pd\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.preprocessing.image import img_to_array, load_img\nfrom keras import layers, models, optimizers\nfrom keras import backend as K\nfrom sklearn.model_selection import train_test_split","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d57ed5db51e8c287e62a8b40d264c42ca64a9ecf","_cell_guid":"5fa55078-4136-47a1-9914-1cac54eec440"},"cell_type":"markdown","source":"**Data dimensions and paths**"},{"metadata":{"_uuid":"2eb716c4e9ad7d0bd7293f0f156b5a751263b800","_cell_guid":"25980d83-1f66-420b-a1dc-501699c3d707","trusted":true,"collapsed":true},"cell_type":"code","source":"\nTRAIN_DIR = '../input/dogs-vs-cats-redux-kernels-edition/train/'\nTEST_DIR = '../input/dogs-vs-cats-redux-kernels-edition/test/'\ntrain_images_dogs_cats = [TRAIN_DIR+i for i in os.listdir(TRAIN_DIR)] # use this for full dataset\ntest_images_dogs_cats = [TEST_DIR+i for i in os.listdir(TEST_DIR)]\nNO_EPOCHS=10\nRESNET_WEIGHTS_PATH = '../input/keras-pretrained-models/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5'","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"505895b51eb3ed5a1dee521c9adc0864639d0b96","_cell_guid":"7fd765e1-e4e1-4b59-b7b2-33336afd4848"},"cell_type":"markdown","source":"\n**Helper function to sort the image files based on the numeric value in each file name.**"},{"metadata":{"trusted":true,"_uuid":"ab823826f480c084baf6029949137eb19b1c018b","collapsed":true},"cell_type":"code","source":"len(train_images_dogs_cats)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"11a7c4072cdedd8f5b79d4bfcec3d1f31d448404","_cell_guid":"d4c8b492-315c-4c38-9b1e-32c05e368027"},"cell_type":"markdown","source":"**Sort the traning set. Use 1300 images each of cats and dogs instead of all 25000 to speed up the learning process.**\n\n**Sort the test set**"},{"metadata":{"trusted":true,"_uuid":"8ef287a9e467303aab3a7e3d08cf76e56d77ec02","collapsed":true},"cell_type":"code","source":"len(train_images_dogs_cats)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7f4cd017fba52ba3bf362112069358959f2ca74c","collapsed":true},"cell_type":"code","source":"train_images_dogs_cats","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d9bb401814a6f96751ad68c7974e42c33bcfd98a","collapsed":true},"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5d3a332070aadd998dcb3ac506f086d1cbe37b20","_cell_guid":"58d15bea-7674-46ff-ba0d-af6a920590be"},"cell_type":"markdown","source":"**Now the images have to be represented in numbers. For this, using the openCV library read and resize the image.  **\n\n**Generate labels for the supervised learning set.**\n\n**Below is the helper function to do so.**"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"b1e5d83b8eef340a598e45bb97271d3cc7bc0fda"},"cell_type":"code","source":"from tqdm import tqdm","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"4e466ba0cbed9298ab7628871ed2989ac7b2c1ce"},"cell_type":"code","source":"def prepare_data(list_of_images):\n    \"\"\"\n    Returns two arrays: \n        x is an array of resized images\n        y is an array of labels\n    \"\"\"\n    x = [] # images as arrays\n    y=[]\n    \n    for image in tqdm(list_of_images):\n        x.append(cv2.resize(cv2.imread(image), (224,224), interpolation=cv2.INTER_CUBIC))\n        z=(re.split('\\d+',image)[0][-4:-1])\n        if 'cat' in z:\n            y.append(0)\n        else:\n            y.append(1)\n\n                \n    \n    return x,y","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c42578104846f709ec064b3fa82c861597dd18f1","_cell_guid":"eaddc700-7124-4526-9615-46e96144af58"},"cell_type":"markdown","source":"**Generate X and Y using the helper function above**\n\n**Since K.image_data_format() is channel_last,  input_shape to the first keras layer will be (img_width, img_height, 3). '3' since it is a color image**"},{"metadata":{"trusted":true,"_uuid":"e5a898fd5cb40260f5dfefae9972cde4ba65da84","scrolled":true,"collapsed":true},"cell_type":"code","source":"train_images_dogs_cats[0]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0111553c02dd7e4d622aeb65c3d307038f32f000","_cell_guid":"9add14aa-3cd6-4160-a3f3-20a2f6b61af9","trusted":true,"collapsed":true},"cell_type":"code","source":"X ,Y= prepare_data(train_images_dogs_cats)\nprint(K.image_data_format())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"79e2ff58defcc1c4de412aebd0d30e2acc895bc4","collapsed":true},"cell_type":"code","source":"X[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e70810224a8fa94f3f331bd3f95d7019fc305abf","collapsed":true},"cell_type":"code","source":"Y[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c47e1733c265af7792ebdbc4a3cf139b21d1d89d","collapsed":true},"cell_type":"code","source":"len(X)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"10e1cbb6e5637399881c4d4ad1901d3dd7ebed5b","collapsed":true},"cell_type":"code","source":"print(type(X),type(Y))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3c5b384bc91a4abe708c2d21787352c552434097","collapsed":true},"cell_type":"code","source":"X = np.array(X)\nY = np.array(Y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b4ea8cfa0f8b01176be7dcac76b971a0ba7fdb8b","collapsed":true},"cell_type":"code","source":"X.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"66fcb69be47911c24423cf0bb65050cd4937bac6","collapsed":true},"cell_type":"code","source":"np.unique(Y,return_counts=True)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"13d1080aa11311bd3fe29857f621503797111080","_cell_guid":"110e7b06-d53d-4be4-ae4f-ca62a9beed89"},"cell_type":"markdown","source":"**Split the data set containing 2600 images into 2 parts, training set and validation set. Later, you will see that accuracy and loss on the validation set will also be reported while fitting the model using training set.**"},{"metadata":{"trusted":true,"_uuid":"91547673c39a0fe4f9c657025052f81f143fe4c3","collapsed":true},"cell_type":"code","source":"print(len(X),len(Y))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c868fcd9c6226ca5b0869eeb08c21b38ea7d4655","collapsed":true},"cell_type":"code","source":"Y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d2dc92c5034002b6eec37fbc15d994fb806867a2","collapsed":true},"cell_type":"code","source":"Y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"34f900bcb923c5e32eac97878763efefbe8c880a","collapsed":true},"cell_type":"code","source":"from keras.utils import to_categorical\nY1 = to_categorical(Y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2517c1d450590b32ff60b493e48a9da80c752d15","collapsed":true},"cell_type":"code","source":"Y[:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4bfe4a7d285d6eb41a6ca90cc5f2b05b8760055a","collapsed":true},"cell_type":"code","source":"Y1[:10]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"26eea9b27bcbf6a0ca3eba6f91cf5cace580f442","_cell_guid":"6a94930d-9c33-4361-ba3d-ef1f29707bce","trusted":true,"collapsed":true},"cell_type":"code","source":"# First split the data in two sets, 80% for training, 20% for Val/Test)\nX_train, X_val, Y_train, Y_val = train_test_split(X,Y1, test_size=0.2, random_state=7)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ad81d2045d5dd7777104d50d5aeaee7156e50d64","collapsed":true},"cell_type":"code","source":"len(X_val)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c5e3ba21cd44491307721204db024166a5028499","_cell_guid":"34977dad-9c51-4946-a465-d79138306b03","collapsed":true,"trusted":true},"cell_type":"code","source":"nb_train_samples = len(X_train)\nnb_validation_samples = len(X_val)\nbatch_size = 64","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6b998b641c185a10e809d95762b57a13a0065f56","_cell_guid":"f4cfc349-2ad8-46f8-9816-80b086401eff"},"cell_type":"markdown","source":"**We will be using the Sequential model from Keras to form the Neural Network. Sequential Model is  used to construct simple models with linear stack of layers. **\n\n**More info on Sequential model and Keras in general at https://keras.io/getting-started/sequential-model-guide/ and https://github.com/keras-team/keras**"},{"metadata":{"trusted":true,"_uuid":"85ab8cc9f7c03d714371ff56433af2a9879b93a0","collapsed":true},"cell_type":"code","source":"from tensorflow.python.keras.models import Sequential\nfrom tensorflow.python.keras.applications import ResNet50\nfrom tensorflow.python.keras.layers import Dense,Dropout","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c026b6bd5de4aa2b0c24f5fc53f0b9e206efae66","collapsed":true},"cell_type":"code","source":"model = Sequential()\nmodel.add(ResNet50(include_top=False, pooling='max', weights=RESNET_WEIGHTS_PATH))\nmodel.add(Dropout(0.2))\nmodel.add(Dense(2, activation='softmax'))\n# ResNet-50 model is already trained, should not be trained\nmodel.layers[0].trainable = True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"90afd82a61d287fb92f20b7486b10e558633903b"},"cell_type":"code","source":"model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"55286a4e571a5554b8d2817907595b42d57c8f9f","collapsed":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ded115b2acdec98f2430b24e0ca2792456571491","collapsed":true},"cell_type":"code","source":"print(X.shape,X_train.shape,X_val.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5a780a8841cd6ae6f013b5fb7fccef351ea48cef","collapsed":true},"cell_type":"code","source":"type(Y_val)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"920903d2359d5806823e24cf2d5c2abf38c3d34b","collapsed":true},"cell_type":"code","source":"print(np.unique(Y_train,return_counts=True),np.unique(Y_val,return_counts=True))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d46dd6f0d43b62a27e92fe1c0088d787709fc584","_cell_guid":"446727ad-a903-45c2-bf87-97152984baa9","trusted":true,"collapsed":true},"cell_type":"code","source":"train_model = model.fit(X_train,Y_train ,\n    batch_size=64,\n    epochs=10,\n    verbose=1,\n    validation_data=(X_val,Y_val))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fa18030d66055f9f40911fc47e9d4d45b1616246","collapsed":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nhist=train_model.history\nacc=hist['acc']\nval_acc=hist['val_acc']\nepoch=range(len(acc))\nloss=hist['loss']\nval_loss=hist['val_loss']\nf,ax=plt.subplots(1,2,figsize=(16,8))\nax[0].plot(epoch,acc,'b',label='Training Accuracy')\nax[0].plot(epoch,val_acc,'r',label='Validation Accuracy')\nax[0].legend()\nax[1].plot(epoch,loss,'b',label='Training Loss')\nax[1].plot(epoch,val_loss,'r',label='Training Loss')\nax[1].legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3d679de7accbe4df7daac93969900f4f2c8c3d75","_cell_guid":"e5ba296f-049f-407a-ae30-22a2226d4810"},"cell_type":"markdown","source":"\n\n**Saving the model in Keras is simple as this! ** \n\n**It is quite helpful for reuse.**"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"eab210a155ce804f1bea65d1aa6017aeb26f9fbe"},"cell_type":"code","source":"import keras","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c3dc5f39f8e8227b6fbc99dab80af96a48aa9c1b","_cell_guid":"32aa2713-f32d-458e-9f9c-8c0dcb5f50f0","trusted":true,"collapsed":true},"cell_type":"code","source":"model.save_weights('model_weights.h5')\nmodel.save('model_keras.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d9cb8c50a3dee7a68d3fc556aa4a2a4c60bd3ecc","collapsed":true},"cell_type":"code","source":"X,_=prepare_data(test_images_dogs_cats)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"b75a1898ed12fa6b7de79437bc6a3794ebe3a60b"},"cell_type":"code","source":"X = np.array(X)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fbb4f07da12e3961d879aea2c8094eb91acad8bc","collapsed":true},"cell_type":"code","source":"y_test=model.predict(X,verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"a1b797335f979e69e6056dc5f5a49e13327922b4"},"cell_type":"code","source":"import matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0a0fe10bce82610947357149a132a739b99ce4cc","collapsed":true},"cell_type":"code","source":"test_images_dogs_cats[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a85af66df0cbfab721687d794dc57adab9deef0e","collapsed":true},"cell_type":"code","source":"f,ax=plt.subplots(1,5,figsize=(10,5))\ni=0\nfor x in test_images_dogs_cats[:5]:\n    print(ax[i].imshow(cv2.imread(x))) \n    i+=1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bacd6e8d2d8b01e8ff9859c571e80b0ba031a783","collapsed":true},"cell_type":"code","source":"y_test[:,1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c39195dbe595d32ff4fd1203b40b913616eab348","collapsed":true},"cell_type":"code","source":"y_final=y_test[:,1]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5331a28934043fe6f9cc58abc9fa3be5de2389d2","collapsed":true},"cell_type":"code","source":"# y_final=[0 if x[0]>x[1] else 1 for x in y_test ]\n\n# y_final[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f942d17a292e7d228f9e89baead91b4d07815130","collapsed":true},"cell_type":"code","source":"len(test_images_dogs_cats)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bc2363729beecffd9c635a0a1f4d3d3d1470a97b","collapsed":true},"cell_type":"code","source":"len(X)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"027f6a62d997392d22c84af993c2650b25df4d94","collapsed":true},"cell_type":"code","source":"df_test=pd.DataFrame({'id':range(1,len(X)+1),'label':y_final})\ndf_test.to_csv('solution1.csv',index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"6654477b1cf0ec45213ec2be2014ac1f57f9eb21"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}