{"cells":[{"metadata":{"_uuid":"fdab5fbc3c28084244b375f59ffb44d6e7992e9a"},"cell_type":"markdown","source":"This kernel is my first attempt to use CNN on images with varying sizes. Analyzing the images given in train directory, I found that there are more than 8000 unique sizes in the the dataset. Resizing all of them to a fixed size image may distort some features in the image."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"collapsed":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"00bba0e42e86745103221581f403ab4061a5d5e2"},"cell_type":"markdown","source":"Some basic import statements.\nRegarding Keras Callbacks, if these sound unfamiliar, please read up on them in the documentation."},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"collapsed":true},"cell_type":"code","source":"import cv2\nimport math\nfrom operator import itemgetter\nfrom keras.utils import to_categorical\nfrom keras.layers import Input, Conv2D, BatchNormalization, GlobalMaxPooling2D, Lambda, Dense\nfrom keras.models import Model\nfrom keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a931b31c50fac462ed93f20068b8d962285a1944","collapsed":true},"cell_type":"code","source":"inputDir = os.path.join(os.getcwd(),\"..\",\"input\")\n\n# Any results you write to the current directory are saved as output.\ntrainDirLen = len(os.listdir(os.path.join(inputDir,\"train\")))\nactTestDirLen = len(os.listdir(os.path.join(inputDir,\"test\")))\ntrainDirImgList = os.listdir(os.path.join(inputDir,\"train\"))\ntrainDir = os.path.join(inputDir,\"train\")\ntestDir= os.path.join(inputDir,\"test\")\n\ntrainGenerator = None\nvalidGenerator = None\ntestGenerator = None\nnumClasses = 2\nlabelDict = {\n'cat':0,\n'dog':1\n}","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d5d3129b180a9b939557f0465e037f6373c0bbe9"},"cell_type":"markdown","source":"Some funcitons to extract labels. Here I have modified the data to fit a softmax classifier with 2 classes rather than using a sigmoid function for predicting one value and inferringthe class from that value."},{"metadata":{"trusted":true,"_uuid":"33396b76846bbde451a5499ec039d317b5cd38f3","collapsed":true},"cell_type":"code","source":"def convertToOHE(x):\n    try:\n        return labelDict[x]\n    except:\n        return None\n\ndef extractLabels(dataDir):\n    fileList = os.listdir(dataDir)\n    nameDf = pd.DataFrame(fileList, columns=[\"filename\"])\n    nameDf[\"basename\"] = nameDf[\"filename\"].apply(lambda x: os.path.splitext(x)[0])\n    nameDf = nameDf.merge(nameDf.basename.apply(lambda x:pd.Series({'left':x.split('.')[0],'right':x.split('.')[1]})),left_index=True,right_index=True)\n    nameDf[\"labels\"] = nameDf.left.apply(convertToOHE)\n    labels = to_categorical(nameDf[\"labels\"],num_classes=2)\n    return labels","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f5fbce9bed8f7b958bd17b192cbcea5fcf1840d4"},"cell_type":"markdown","source":"Since, loading all the images will generally take up a lot of time and system resources, I find it better to make some python generators that can do the training data load part on the fly."},{"metadata":{"trusted":true,"_uuid":"7af2bdb852686098c0a3ec9396b5bbaf42a313ad","collapsed":true},"cell_type":"code","source":"def createGenerator(fileList,labels,batch_size,imgDir):\n    global numClasses\n    fileListLength = len(fileList)\n    labelContainer = np.zeros((batch_size,numClasses))\n    maxX=0\n    maxY=0\n    while True:\n        randArr = np.random.permutation(fileListLength)\n        imageList = list()\n        maxX=maxY=0\n        for i in range(batch_size):\n            fi = os.path.join(imgDir,fileList[randArr[i]])\n            image = cv2.imread(fi,cv2.IMREAD_GRAYSCALE)\n            labelContainer[i] = labels[randArr[i]]\n            imageList.append(image)\n            if image.shape[0]>maxX:\n                maxX= image.shape[0]\n            if image.shape[1]>maxY:\n                maxY = image.shape[1]\n        imageContainer = np.zeros((batch_size,maxX,maxY))\n        for i in range(batch_size):\n            image = imageList[i]\n            imageContainer[i,:image.shape[0],:image.shape[1]] = image\n        imageContainer = np.expand_dims(imageContainer,axis=3)\n        \n        yield np.array(imageContainer),labelContainer\n\n\ndef prepareGenerator(dataDir,labels, batch_size):\n    global trainGenerator\n    global validGenerator\n    global testGenerator\n    fileList = os.listdir(dataDir)\n    fileListLen = len(fileList)\n    index = np.random.permutation(fileListLen)\n    trainMarker = math.floor(index.size*(0.6))\n    validateMarker = math.floor(index.size*(0.8))\n    trainIndex = index[0:trainMarker]\n    validateIndex = index[trainMarker:validateMarker]\n    testIndex = index[validateMarker:]\n    trainFiles = itemgetter(*trainIndex)(fileList)\n    trainLabels = labels[trainIndex,...]\n    validateFiles = itemgetter(*validateIndex)(fileList)\n    validateLabels = labels[validateIndex,...]\n    testFiles = itemgetter(*testIndex)(fileList)\n    testLabels = labels[testIndex,...]\n    trainGenerator = createGenerator(trainFiles,trainLabels,batch_size,dataDir)\n    validGenerator = createGenerator(validateFiles,validateLabels,batch_size,dataDir)\n    testGenerator = createGenerator(testFiles, testLabels, batch_size,dataDir)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"67745cf7d1193a56517633646fd5725fc8f5040c"},"cell_type":"markdown","source":"Using three callbacks during training:\n1. ModelCheckpoint to save the models with the best performance so far. These may not be the best model, but it is helpful if after completion of training, the model does not give good result.\n2. EarlyStopping: to terminate the training to stop the training if some improvement is not found in a pre-defined number of iterations.\n3. ReduceLROnPlateau: To reduce the learning rate if no improvement is found in successive epochs.\n"},{"metadata":{"trusted":true,"_uuid":"2e934cf1dac60f4090a3b325e92b089b858b2aa6","collapsed":true},"cell_type":"code","source":"def get_callbacks(filepath, patience=5):\n    checkpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_best_only=True, mode='min')\n    es = EarlyStopping(monitor='val_loss', patience=patience)\n    reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2,patience=5, min_lr=0.0001)\n    return [es,checkpoint,reduce_lr]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"901858ed37839cd232cbaf0d7668f7c4885dbd14"},"cell_type":"code","source":"import matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"294c3586674ef2484a71e021a1e20a363fb3e67a"},"cell_type":"code","source":"from keras.models import load_model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"308909d68959de8015f0d61031283196c5ba47b6"},"cell_type":"code","source":"labels = extractLabels(trainDir)\nprepareGenerator(trainDir,labels,16)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1db7cbf9824bb85ae419fda33bac108581fa8b66"},"cell_type":"markdown","source":"Model Definition."},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"3e48532248151888a52f6ce1afb08d554f84a90d","collapsed":true},"cell_type":"code","source":"def getModel():\n    inp = Input(shape=(None,None,1))\n    x = Lambda(lambda y:y/255.0)(inp)\n    x = Conv2D(8,(7,7), activation=\"elu\")(x)\n    x = BatchNormalization()(x)\n    x = Conv2D(16,(5,5), activation=\"elu\")(x)\n    x = BatchNormalization()(x)\n    x = Conv2D(32,(3,3), activation=\"elu\")(x)\n    x = BatchNormalization()(x)\n    x = Conv2D(64,(1,1))(x)\n    x = GlobalMaxPooling2D()(x)\n    x = Dense(16, activation=\"relu\")(x)\n    x = BatchNormalization()(x)\n    x = Dense(8, activation=\"relu\")(x)\n    x = BatchNormalization()(x)\n    x = Dense(4, activation=\"relu\")(x)\n    x = BatchNormalization()(x)\n    out = Dense(2, activation=\"softmax\")(x)\n    model = Model(inputs = inp, outputs=out)\n    model.compile(optimizer = \"sgd\", loss = \"categorical_crossentropy\",metrics=[\"accuracy\"])\n    model.summary()\n    return model\n\nmodelSavePath = os.path.join(os.getcwd(),\".model_weights_commit.hdf5\")\ncallbacks = get_callbacks(modelSavePath,8)\ngmodel = getModel()\nhistory = gmodel.fit_generator(trainGenerator,steps_per_epoch=8,epochs=40, verbose=1, callbacks=callbacks, validation_data=validGenerator, validation_steps=8, )\ngmodel = load_model(modelSavePath)\nscores = gmodel.evaluate_generator(testGenerator, steps=32)\nprint(scores)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"33e4032a1a21179639544f5bf1d70c9eb4381a63","collapsed":true},"cell_type":"code","source":"plt.plot(history.history['val_loss'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0c0279679c44b06223be30b6a801e7294d382e52","collapsed":true},"cell_type":"code","source":"plt.plot(history.history['val_acc'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"cb545ec8f020273af08f93c5d884b0d8b6256ad6"},"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}