{"cells":[{"metadata":{"_uuid":"8fccad9a2816a1c1431b0af0094104acd3d254ea","_cell_guid":"05d85d2f-ddd6-43ee-858c-246a1fe44dad"},"cell_type":"markdown","source":"**This kernel is created to show the standard step-by-step process in handling image data. However, given the time limit of an hour, the kernel can only reach a low validation accuracy. Another way  of trainning the model from scratch is to run the script on a very powerful computer or using cloud computing. If you want to save time and computational power, you can also pre-process the data in the same manner and use [ImageNet pre-trained models](https://www.pyimagesearch.com/2017/03/20/imagenet-vggnet-resnet-inception-xception-keras/). Now let's begin and hope you enjoy it. **"},{"metadata":{"_uuid":"2ad8d85f26d4a02c565d28d68f58400b5cdf83e7","_cell_guid":"19baf75a-c1a2-4924-9b2f-af687b54ac30"},"cell_type":"markdown","source":"**Libraries that you need for image data preprocessing**"},{"metadata":{"trusted":true,"_uuid":"75e215471dd0bae253a64668d70b202332a026d0","_cell_guid":"75bda4b4-bd1f-4342-a115-1479c792e3da"},"cell_type":"code","source":"import os\nimport cv2 # image handling\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom tqdm import tqdm\n\nimport seaborn as sns\nimport matplotlib.pyplot as plt \n\nimport sklearn\nfrom sklearn.cross_validation import train_test_split\n\nfrom subprocess import check_output\nprint(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3170b8afe1370d71da40c44f3bb7376fcc87bbeb","_cell_guid":"b2b53fb3-d209-43b6-a77e-4840138b6847"},"cell_type":"markdown","source":"**Examine the breeds, and we found out there are 120 breeds in total**"},{"metadata":{"scrolled":false,"trusted":true,"_uuid":"c24fafd4ae44aa95256bb7cb74272164f6480dcf","_cell_guid":"1ba819a6-516b-4261-bb8c-7b45c53b816a"},"cell_type":"code","source":"lables = pd.read_csv('../input/dog-breed-identification/labels.csv')\nprint (lables.head(5))\nbreed_count = lables['breed'].value_counts()\nprint (breed_count.head())\nprint (breed_count.shape)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1f91be1efa0db570dc30cb97534831191b73202b","_cell_guid":"b9953982-bb18-439d-8a58-457117fe0085"},"cell_type":"markdown","source":"**One hot encoding the lables**"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"3528072a152a9d350b2017d74087cbb6ffa7aefb","_cell_guid":"037d97ee-3c15-49ff-bbee-0797b9291dca"},"cell_type":"code","source":"targets = pd.Series(lables['breed'])\none_hot = pd.get_dummies(targets, sparse = True)\none_hot_labels = np.asarray(one_hot)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7696ed4e81168d77c9ab344b32b8edcc3c822b8e","_cell_guid":"981d8e7c-87a4-4e92-8cce-78c1ece1f3e5"},"cell_type":"markdown","source":"**Set image parameters to be used later, I'm using grayscale here so the number of channel is 1**"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"d5b49d6b594c84fc40b21e29e3bcab9b443ef222","_cell_guid":"1bf91366-611b-4a0f-8d91-af4a4481c391"},"cell_type":"code","source":"img_rows=128\nimg_cols=128\nnum_channel=1# 3 colour channes","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dc698da2c9eaa9ce0aed8c012063fb3d24e48813","_cell_guid":"aeaf8832-2b75-4912-b511-c71a5d5e4b89"},"cell_type":"markdown","source":"**Testing on a single image, first read in the image file in graysalce, then resize it**"},{"metadata":{"trusted":true,"_uuid":"33cf55a5ce494887f1f91a08cc91a86df205743b","_cell_guid":"41fe73b0-200f-41b9-84ec-a352d1be08e0"},"cell_type":"code","source":"img_1 = cv2.imread('../input/dog-breed-identification/train/000bec180eb18c7604dcecc8fe0dba07.jpg', 0)\nplt.title('Original Image')\nplt.imshow(img_1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"32c1940369176d028f727bf6c030dd37a023acf3","_cell_guid":"ff7e4be3-29b9-4961-a966-83bd72645ab5"},"cell_type":"code","source":"img_1_resize= cv2.resize(img_1, (img_rows, img_cols)) \nprint (img_1_resize.shape)\nplt.title('Resized Image')\nplt.imshow(img_1_resize)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"878c4bd62ee87f7975036457161b4a073e368d15","_cell_guid":"2b777b91-214c-4907-9df6-d6e1e13a828a"},"cell_type":"markdown","source":"**Now loop the proceedure through the train folder, and keep adding each new image data onto the existing data frame (x_feature) **"},{"metadata":{"scrolled":true,"trusted":true,"_uuid":"54547affe95fa119c96a78a424d02e424e235be0","_cell_guid":"fabf10c5-4fad-47ca-aa13-13bab1c394ce"},"cell_type":"code","source":"x_feature = []\ny_feature = []\n\ni = 0 # initialisation\nfor f, img in tqdm(lables.values): # f for format ,jpg\n    train_img = cv2.imread('../input/dog-breed-identification/train/{}.jpg'.format(f),0)\n    label = one_hot_labels[i]\n    train_img_resize = cv2.resize(train_img, (img_rows, img_cols)) \n    x_feature.append(train_img_resize)\n    y_feature.append(label)\n    i += 1","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"41ee575079f710453722c8174d02218f8301b516","_cell_guid":"24e6622c-223d-41d3-9a0a-66872c701d50"},"cell_type":"markdown","source":"**The data frames need to be the form of arrays and normolised. Becuase I'm dealing with grayscale here, I needed to add the dimension at the end of the array else it keras would raise an exception**"},{"metadata":{"trusted":true,"_uuid":"ef8369be2afc9c9a1de9729f05e65f6389685be6","_cell_guid":"e6789b54-55b3-4051-9af4-e7d69c6842e2"},"cell_type":"code","source":"x_train_data = np.array(x_feature, np.float32) / 255.   # /= 255 for normolisation\nprint (x_train_data.shape)\nx_train_data = np.expand_dims(x_train_data, axis = 3)\nprint (x_train_data.shape)","execution_count":null,"outputs":[]},{"metadata":{"scrolled":false,"trusted":true,"_uuid":"dade950fac2a31dc8fd0c7b93338bbf8e1025663","_cell_guid":"4cbaae72-3658-4149-83a2-72d7e6c12977"},"cell_type":"code","source":"y_train_data = np.array(y_feature, np.uint8)\nprint (y_train_data.shape)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d10aaf85da38cd25b1a1d7f57b0a3a1795e233ad","_cell_guid":"9ba935f0-c18f-44c2-89f4-e7d6cbfedf2c"},"cell_type":"markdown","source":"**Spliting the training and validation sets**"},{"metadata":{"trusted":true,"_uuid":"b3303aa47962785f429e80671e8ef1d2d6fc0f2e","_cell_guid":"5f655643-e314-48f7-bbe3-306dbcdd372c"},"cell_type":"code","source":"x_train, x_val, y_train, y_val = train_test_split(x_train_data, y_train_data, test_size=0.2, random_state=2)\nprint (x_train.shape)\nprint (x_val.shape)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3ee3ae0af69b78a2f0af37ee398e6f5468b94a52","_cell_guid":"5323afd8-78ec-40f9-b5ff-922e59ded8de"},"cell_type":"markdown","source":"**After we have done the trainning data, now we are doing the test data, do the same thing to prepare the test data**"},{"metadata":{"scrolled":false,"trusted":true,"_uuid":"856ebd1877a822bdc2017492f17b69d4ca66c0b7","_cell_guid":"28420709-f882-462e-a8af-c9ef640c5521"},"cell_type":"code","source":"submission = pd.read_csv('../input/dog-breed-identification/sample_submission.csv')\ntest_img = submission['id']\nprint (test_img.head(5))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"82a23a7102f9bbe148192d79b67c14e531e6e001","_cell_guid":"c76c30ba-4c38-47b5-8180-026ceef3727f"},"cell_type":"code","source":"x_test_feature = []\n\ni = 0 # initialisation\nfor f in tqdm(test_img.values): # f for format ,jpg\n    img = cv2.imread('../input/dog-breed-identification/test/{}.jpg'.format(f), 0)\n    img_resize = cv2.resize(img, (img_rows, img_cols)) \n    x_test_feature.append(img_resize)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"18127092a5609a482256358131b54c9704bf86ce","_cell_guid":"8e6a4226-c49d-4755-a407-f0cbccedd30c"},"cell_type":"code","source":"x_test_data = np.array(x_test_feature, np.float32) / 255. \nprint (x_test_data.shape)\nx_test_data = np.expand_dims(x_test_data, axis = 3)\nprint (x_test_data.shape)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"71b34432222e8233693dedd44114aa97d2fd79de","_cell_guid":"27125f4b-a478-462a-bca9-7645622ca97a"},"cell_type":"markdown","source":"**Now we have prepared: x_train, y_train, x_val, y_val and x_test. Time to build our CNN model. First import keras**"},{"metadata":{"trusted":true,"_uuid":"b01e6760c402bc10aa5de5738593683c2e7bff5f","_cell_guid":"34e2626d-472e-4ce1-9109-ae3c6c3341f7"},"cell_type":"code","source":"from keras.models import Sequential  # initial NN\nfrom keras.layers import Dense, Dropout # construct each layer\nfrom keras.layers import Convolution2D # swipe across the image by 1\nfrom keras.layers import MaxPooling2D # swipe across by pool size\nfrom keras.layers import Flatten","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"725b5357f545f6a315e9c4eae770e3bd7716089a","_cell_guid":"72871f2b-4643-4412-b9a5-9fe796f0d409"},"cell_type":"markdown","source":"**Initialising model**"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"42812300fd536e5c3de2065ffed8260538418893","_cell_guid":"0ea10339-a7bd-452f-9946-f8620e286a61"},"cell_type":"code","source":"model = Sequential()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"aceca5f45fc45ca7eb198efb570ed2a2e8f35f67","_cell_guid":"b85f6a55-de28-403d-a60e-04335a3ce614"},"cell_type":"markdown","source":"**I have a rather simple CNN here**\n1. Convetional layer (detect features in image matrix)\n2. Pooling layer (recongise features in different angle and/or size)\n3. Convetional layer\n4. Pooling laye\n5. Flattening layer (flatten layers in array of imput)\n6. Full connected layer (full connected ANN)\n7. Output layer"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"3d78ad2805cbcf247afcaf05381145160200fdfe","_cell_guid":"8431953e-e024-46b5-8719-66f78be04ab9"},"cell_type":"code","source":"# retifier ensure the non-linearity in the processing \nmodel.add(Convolution2D (filters = 64, kernel_size = (4,4),padding = 'Same', \n                         activation ='relu', input_shape = (img_rows, img_cols, num_channel))) \nmodel.add(MaxPooling2D(pool_size=(2,2)))\nmodel.add(Convolution2D (filters = 64, kernel_size = (4,4),padding = 'Same', \n                         activation ='relu')) \nmodel.add(MaxPooling2D(pool_size=(2,2)))\n\nmodel.add(Flatten()) \n# fully connected ANN \nmodel.add(Dense(units = 120, activation = 'relu')) \n# output layer\nmodel.add(Dense(units = 120, activation = 'softmax')) ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b360873a9d9cd53612599b431102a129a4aa4eb9","_cell_guid":"68390aff-16cb-449b-90fc-c8da99f22c8b"},"cell_type":"markdown","source":"**Compile the model**"},{"metadata":{"trusted":true,"_uuid":"ee4771f73431ccac7ccd0b6da15668f316d82ab6","_cell_guid":"dcf1725b-72c8-4c1b-84d3-459f280b9011"},"cell_type":"code","source":"model.compile(optimizer = 'adam' , loss = \"categorical_crossentropy\", metrics=[\"accuracy\"]) \nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3cc88ff10ad6cb9b4d7441b65d7c87b8c436dae9","_cell_guid":"736f952f-8ebc-4d90-b95e-792fe22421a9"},"cell_type":"markdown","source":"**Fit the model into data**"},{"metadata":{"scrolled":false,"trusted":true,"_uuid":"c229267d5319802bb34056b30062891099ff59d6","_cell_guid":"b5ddd483-2408-4504-b2fa-ff8728d49b47"},"cell_type":"code","source":"batch_size = 128 \nnb_epochs = 2\nhistory = model.fit(x_train, y_train,\n                    batch_size=batch_size,\n                    epochs=nb_epochs,\n                    verbose=2, \n                    validation_data=(x_val, y_val),\n                    initial_epoch=0)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2c8606c27d8e317a8f6f3d93c9fa69a2c9dfacda","_cell_guid":"aaafd4af-0855-4c31-b89d-c14ed5dc607f"},"cell_type":"markdown","source":"**Plot the loss and accuracy curves for training and validation**"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"88efc2a0c591c6d1d638bc9c875e3ec91d0420b2","_cell_guid":"34830861-bf30-46ff-8190-025efd3b51ee"},"cell_type":"code","source":"fig, ax = plt.subplots(2,1)\nax[0].plot(history.history['loss'], color='b', label=\"Training loss\")\nax[0].plot(history.history['val_loss'], color='r', label=\"validation loss\",axes =ax[0])\nlegend = ax[0].legend(loc='best', shadow=True)\n\nax[1].plot(history.history['acc'], color='b', label=\"Training accuracy\")\nax[1].plot(history.history['val_acc'], color='r',label=\"Validation accuracy\")\nlegend = ax[1].legend(loc='best', shadow=True)","execution_count":null,"outputs":[]},{"metadata":{"collapsed":true,"_uuid":"147e963dafe05e8105029d704afa05b304353434","_cell_guid":"78f32811-6cdb-4bff-ac5c-1a3ed57ac4fd"},"cell_type":"markdown","source":"**Predict results**"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"1d725a8e99273c3188ceeec24dfc226c242e30f1","_cell_guid":"58fe101f-b520-494f-8c9f-b1dc4f37eea1"},"cell_type":"code","source":"results = model.predict(x_test_data)\nprediction = pd.DataFrame(results)\n\n# Set column names to those generated by the one-hot encoding earlier\ncol_names = one_hot.columns.values\nprediction.columns = col_names\n# Insert the column id from the sample_submission at the start of the data frame\nprediction.insert(0, 'id', submission['id'])\n\nsubmission = prediction\nsubmission.to_csv('new_submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"collapsed":true,"_uuid":"1da0eea1b70e54b747cdfc0678069523eed05578","_cell_guid":"d7c6dc8c-a468-45a0-95e6-a4a72370c984"},"cell_type":"markdown","source":"**Thank you for reading**"}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}