{"cells":[{"metadata":{"_uuid":"4da5a3e7db32799ca0108576e469157094d23111","_cell_guid":"8a7bff8d-c95a-4cfb-8c38-14ab989f769b","trusted":false,"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 \nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport keras\nfrom keras.applications.vgg19 import VGG19\nfrom keras.models import Model\nfrom keras.layers import Dense, Dropout, Flatten\n\nimport os\nfrom tqdm import tqdm\nfrom sklearn import preprocessing\nfrom sklearn.model_selection import train_test_split\nimport cv2\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\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":"7c64ad63b95b36df5a2223b4c499c1caad9c73ee","_cell_guid":"0b8fddbc-447f-4083-88c4-9bd5f811253d"},"cell_type":"markdown","source":"First we will read in the csv's so we can see some more information on the filenames and breeds"},{"metadata":{"_uuid":"18e9091e9a3d851fb0ce796a3b537ffb7f47c874","collapsed":true,"_cell_guid":"bcbeef91-f00e-4a68-b1b8-25e206027bb2","trusted":false},"cell_type":"code","source":"df_train = pd.read_csv('../input/labels.csv')\ndf_test = pd.read_csv('../input/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0ba75a32f91650bc75440443ab3d11c35e44e1c9","_cell_guid":"6abe20dc-a411-4334-ad66-2526d99c7f63","trusted":false,"collapsed":true},"cell_type":"code","source":"df_train.head(10)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"860b860b8f98c9fe381645044628cc7492eaa6fd","_cell_guid":"31789e79-005d-4219-82f7-b757f6595adc"},"cell_type":"markdown","source":"We can see that the breed needs to be one-hot encoded for the final submission, so we will now do this."},{"metadata":{"_uuid":"7fbb53109a3d08bedb1abac074f8186bdea991ac","collapsed":true,"_cell_guid":"1ba5da72-9d82-404d-aa25-ce9739a45775","trusted":false},"cell_type":"code","source":"targets_series = pd.Series(df_train['breed'])\none_hot = pd.get_dummies(targets_series, sparse = True)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"07c3bf3155c29a76d6f42af9b2135bbbaca87c92","collapsed":true,"_cell_guid":"23fdc238-9f15-41d0-be8b-1913e6b1dd0f","trusted":false},"cell_type":"code","source":"one_hot_labels = np.asarray(one_hot)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d59fb275c2e30a410c9c8af8489f38138b1513ac","_cell_guid":"421885e6-97a5-4a43-bdf5-6b60cfc0b3d3"},"cell_type":"markdown","source":"Next we will read in all of the images for test and train, using a for loop through the values of the csv files. I have also set an im_size variable which sets the size for the image to be re-sized to,  90x90 px, you should play with this number to see how it affects accuracy."},{"metadata":{"_uuid":"7b47e6524b0fcf5ccb9a237cbdc8d444ff215dfb","collapsed":true,"_cell_guid":"0e89e3ca-7c9e-4f76-aaf8-8c5267e3a415","trusted":false},"cell_type":"code","source":"im_size = 90","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e7f00cc68bbb5b9b15ee3373361bab01287476ce","collapsed":true,"_cell_guid":"cc632b19-d7c8-4c78-b5bf-4f0313603c11","trusted":false},"cell_type":"code","source":"x_train = []\ny_train = []\nx_test = []","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1f099a6a4d6b16ed3202a91d5376b77579664d04","_cell_guid":"98aab483-199c-451b-80a9-a9c1cf3d02be","trusted":false,"collapsed":true},"cell_type":"code","source":"i = 0 \nfor f, breed in tqdm(df_train.values):\n    img = cv2.imread('../input/train/{}.jpg'.format(f))\n    label = one_hot_labels[i]\n    x_train.append(cv2.resize(img, (im_size, im_size)))\n    y_train.append(label)\n    i += 1","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bdee8455dd9f5f6232e57a83d19f06527b259611","_cell_guid":"ceaf5e6d-058d-495f-80d0-55b02870a936","trusted":false,"collapsed":true},"cell_type":"code","source":"for f in tqdm(df_test['id'].values):\n    img = cv2.imread('../input/test/{}.jpg'.format(f))\n    x_test.append(cv2.resize(img, (im_size, im_size)))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"29804cc313366d5ac155dead1c37fabbc036a4ad","collapsed":true,"_cell_guid":"d7dccd3d-9369-4b7c-b589-97f4bd299cd2","trusted":false},"cell_type":"code","source":"y_train_raw = np.array(y_train, np.uint8)\nx_train_raw = np.array(x_train, np.float32) / 255.\nx_test  = np.array(x_test, np.float32) / 255.","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0e64cd331abd85c517cf870d41b2440b200a54f1","_cell_guid":"ad4bb94f-2464-4685-9b44-32f5502e224a"},"cell_type":"markdown","source":"We check the shape of the outputs to make sure everyting went as expected."},{"metadata":{"_uuid":"a5dddeebe7556cecf31da047693710179ce29f98","_cell_guid":"b26f825e-8c02-43d9-9d1d-3e0092d69d26","trusted":false,"collapsed":true},"cell_type":"code","source":"print(x_train_raw.shape)\nprint(y_train_raw.shape)\nprint(x_test.shape)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"70495031a1e6789f8784b4a0c1c2919df4896722","_cell_guid":"3c6de3f8-d801-4cde-8877-db415b61da8e"},"cell_type":"markdown","source":"\nWe can see above that there are 120 different breeds. We can put this in a num_class variable below that can then be used when creating the CNN model."},{"metadata":{"_uuid":"00fdfb9bf52e9f7a8030d88dfab823262c0f1dc2","collapsed":true,"_cell_guid":"60707a5f-0689-4ecf-a0df-3e3e9c76e076","trusted":false},"cell_type":"code","source":"num_class = y_train_raw.shape[1]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"267bbc11b7bc95dd622bdcee0df0c1547ab419dc","_cell_guid":"c4b45b4a-de62-44c8-ace7-b81c371e9eb5"},"cell_type":"markdown","source":"It is important to create a validation set so that you can gauge the performance of your model on independent data, unseen to the model in training. We do this by splitting the current training set (x_train_raw) and the corresponding labels (y_train_raw) so that we set aside 30 % of the data at random and put these in validation sets (X_valid and Y_valid).\n\n* This split needs to be improved so that it contains images from every class, with 120 separate classes some can not be represented and so the validation score is not informative. "},{"metadata":{"_uuid":"116f3d718f6bf256eb0a2992c344e5f52f9be181","collapsed":true,"_cell_guid":"fd2dec22-e057-433b-81ba-f1d8a7580b8e","trusted":false},"cell_type":"code","source":"X_train, X_valid, Y_train, Y_valid = train_test_split(x_train_raw, y_train_raw, test_size=0.3, random_state=1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0b593bba735e6136dae235b9d02a2ff95c916f9a","_cell_guid":"ea14cf49-c458-4505-ae3c-3d487c413541"},"cell_type":"markdown","source":"Now we build the CNN architecture. Here we are using a pre-trained model VGG19 which has already been trained to identify many different dog breeds (as well as a lot of other objects from the imagenet dataset see here for more information: http://image-net.org/about-overview). Unfortunately it doesn't seem possible to downlod the weights from within this kernel so make sure you set the weights argument to 'imagenet' and not None, as it currently is below.\n\nWe then remove the final layer and instead replace it with a single dense layer with the number of nodes corresponding to the number of breed classes we have (120)."},{"metadata":{"_uuid":"0946091bb67a488a05f9e39e8dac432b485eb70a","_cell_guid":"decf1fdf-5a24-41cd-b9b3-d49825efec82","trusted":false,"collapsed":true},"cell_type":"code","source":"# Create the base pre-trained model\n# Can't download weights in the kernel\nbase_model = VGG19(#weights='imagenet',\n    weights = None, include_top=False, input_shape=(im_size, im_size, 3))\n\n# Add a new top layer\nx = base_model.output\nx = Flatten()(x)\npredictions = Dense(num_class, activation='softmax')(x)\n\n# This is the model we will train\nmodel = Model(inputs=base_model.input, outputs=predictions)\n\n# First: train only the top layers (which were randomly initialized)\nfor layer in base_model.layers:\n    layer.trainable = False\n\nmodel.compile(loss='categorical_crossentropy', \n              optimizer='adam', \n              metrics=['accuracy'])\n\ncallbacks_list = [keras.callbacks.EarlyStopping(monitor='val_acc', patience=3, verbose=1)]\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5183ff91d3f3179aeeff320d81299a3cf1f2a852","_cell_guid":"2580ad4a-8c2a-4b7c-bef1-e39293b0b02c","trusted":false,"collapsed":true},"cell_type":"code","source":"model.fit(X_train, Y_train, epochs=1, validation_data=(X_valid, Y_valid), verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"25ed4a3f9ce837128e3baa3e91bb0aee10e72ab8","_cell_guid":"9c419742-1c6a-40c6-a26a-782836ee3641"},"cell_type":"markdown","source":"Remember, accuracy is low here because we are not taking advantage of the pre-trained weights as they cannot be downloaded in the kernel. This means we are training the wights from scratch and I we have only run 1 epoch due to the hardware constraints in the kernel.\n\nNext we will make our predictions."},{"metadata":{"_uuid":"e8a63ce4e324f3e011b3de7fc459301337d1b8d0","_cell_guid":"f72763e1-68b6-4e54-9b80-ff0f4f94aa28","trusted":false,"collapsed":true},"cell_type":"code","source":"preds = model.predict(x_test, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"626b762d81d28ff77032658092d5bd9523b186b1","collapsed":true,"_cell_guid":"0457a19d-0e26-4619-a3c8-78c71e7d41e6","trusted":false},"cell_type":"code","source":"sub = pd.DataFrame(preds)\n# Set column names to those generated by the one-hot encoding earlier\ncol_names = one_hot.columns.values\nsub.columns = col_names\n# Insert the column id from the sample_submission at the start of the data frame\nsub.insert(0, 'id', df_test['id'])\nsub.head(5)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b72af806cbbdea33edd7f73d24dbe9b9cbaae805","collapsed":true,"_cell_guid":"a4ed0f81-8675-4a10-8b19-2d3ef191afe2","trusted":false},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"language_info":{"name":"python","version":"3.6.5","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"}},"nbformat":4,"nbformat_minor":1}