{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Imports\n\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom glob import glob # finds all the pathnames matching a specified pattern according to the rules used by the Unix shell\nimport cv2 # computer vision library for reading images\nfrom IPython.display import Image\nimport os, warnings\nimport matplotlib.pyplot as plt\nfrom matplotlib import gridspec\n\n# Tensorflow\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers.experimental import preprocessing\n\n#Keras\nfrom keras import applications\nfrom keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau\nfrom keras.applications import InceptionResNetV2\nfrom tensorflow.keras.applications.inception_resnet_v2 import preprocess_input\nfrom tensorflow.keras.preprocessing import image\n\nfrom sklearn.model_selection import train_test_split\n\n# Reproducability\ndef set_seed(seed=31415):\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    os.environ['TF_DETERMINISTIC_OPS'] = '1'\nset_seed()\n\n# Set Matplotlib defaults\nplt.rc('figure', autolayout=True)\nplt.rc('axes', labelweight='bold', labelsize='large',\n       titleweight='bold', titlesize=18, titlepad=10)\nplt.rc('image', cmap='magma')\nwarnings.filterwarnings(\"ignore\") # to clean up output cells","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-06-16T10:25:34.250596Z","iopub.execute_input":"2021-06-16T10:25:34.250892Z","iopub.status.idle":"2021-06-16T10:25:41.101032Z","shell.execute_reply.started":"2021-06-16T10:25:34.250822Z","shell.execute_reply":"2021-06-16T10:25:41.100165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Path to the data\nPATH = \"../input/dog-breed-identification\"\nTRAIN_PATH = os.path.join(PATH, 'train/*')\nTEST_PATH = os.path.join(PATH, 'test/*')\nLABELS_PATH = os.path.join(PATH, 'labels.csv')\nDOG_IMAGES_PATH = os.path.join('../input/dog-images/*')\n\n# Set the parameters for the Keras model\nSIZE = 299\nNUM_CLASSES = 120\nBATCH_SIZE = 128\nEPOCHS = 50","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:25:44.923017Z","iopub.execute_input":"2021-06-16T10:25:44.923365Z","iopub.status.idle":"2021-06-16T10:25:44.928755Z","shell.execute_reply.started":"2021-06-16T10:25:44.923334Z","shell.execute_reply":"2021-06-16T10:25:44.927723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_model():\n    '''\n    Builds a pretrained model on the imagenet dataset\n    Model InceptionRestNetV2 with freezed weights\n    Sets the input shape to (SIZE, SIZE, 3)\n    Sets the output shape to 120 classes\n    '''\n    base_model = InceptionResNetV2(\n    include_top=False,\n    weights=\"imagenet\",\n    input_tensor=None,\n    input_shape=(SIZE, SIZE, 3),\n    pooling=None)\n    base_model.trainable = False\n\n    model = keras.models.Sequential([\n        base_model,\n        keras.layers.GlobalAveragePooling2D(),\n        keras.layers.Dropout(0.2),\n        keras.layers.Dense(120, activation='softmax')\n    ])\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:25:46.687397Z","iopub.execute_input":"2021-06-16T10:25:46.687715Z","iopub.status.idle":"2021-06-16T10:25:46.693998Z","shell.execute_reply.started":"2021-06-16T10:25:46.687686Z","shell.execute_reply":"2021-06-16T10:25:46.692902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_image(path):\n    '''\n    Read the image.\n    Resize the image.\n    Transform the image in an array.\n    Preprocessing\n    '''\n    img = image.load_img(path, target_size=(SIZE, SIZE))\n    img = image.img_to_array(img)\n    img = preprocess_input(img)\n    # Return 3D image array\n    return img\n\n\ndef parse_data(x, y):\n    x = x.decode()\n    num_class = NUM_CLASSES\n    image = read_image(x)\n    label = [0] * num_class\n    label[y] = 1\n    label = np.array(label)\n    label = label.astype(np.int32)\n    return image, label\n\ndef tf_parse(x, y):\n    x, y = tf.numpy_function(parse_data, [x, y], [tf.float32, tf.int32])\n    x.set_shape((SIZE, SIZE, 3))\n    y.set_shape((NUM_CLASSES))\n    return x, y\n\ndef tf_dataset(x, y):\n    dataset = tf.data.Dataset.from_tensor_slices((x, y))\n    dataset = dataset.map(tf_parse)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.repeat()\n    return dataset","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:25:48.687665Z","iopub.execute_input":"2021-06-16T10:25:48.688006Z","iopub.status.idle":"2021-06-16T10:25:48.696008Z","shell.execute_reply.started":"2021-06-16T10:25:48.687974Z","shell.execute_reply":"2021-06-16T10:25:48.695005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get the number of breeds\nlabels_df = pd.read_csv(LABELS_PATH)\nbreed = labels_df['breed'].unique()\nprint('Number of breeds: ', len(breed))","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:25:51.501671Z","iopub.execute_input":"2021-06-16T10:25:51.502002Z","iopub.status.idle":"2021-06-16T10:25:51.545824Z","shell.execute_reply.started":"2021-06-16T10:25:51.501971Z","shell.execute_reply":"2021-06-16T10:25:51.544827Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Set a unique id for each breed\nbreed_to_id = {name: i for i, name in enumerate(breed)}\nid_to_breed = {i: name for i, name in enumerate(breed)}","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:25:53.563354Z","iopub.execute_input":"2021-06-16T10:25:53.563681Z","iopub.status.idle":"2021-06-16T10:25:53.567630Z","shell.execute_reply.started":"2021-06-16T10:25:53.563654Z","shell.execute_reply":"2021-06-16T10:25:53.566815Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a list of labels ids from each image\nids = glob(TRAIN_PATH)\nlabels = []\n\nfor image_id in ids:\n    image_id = image_id.split('/')[-1].split('.')[0]\n    breed_name = list(labels_df[labels_df.id == image_id]['breed'])[0]\n    breed_idx = breed_to_id[breed_name]\n    labels.append(breed_idx)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:25:55.795029Z","iopub.execute_input":"2021-06-16T10:25:55.795373Z","iopub.status.idle":"2021-06-16T10:26:14.693483Z","shell.execute_reply.started":"2021-06-16T10:25:55.795344Z","shell.execute_reply":"2021-06-16T10:26:14.692581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Split the dataset\nx_train, x_valid, y_train, y_valid = train_test_split(ids, labels, test_size=0.2, random_state=42)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:26:14.694851Z","iopub.execute_input":"2021-06-16T10:26:14.695194Z","iopub.status.idle":"2021-06-16T10:26:14.706562Z","shell.execute_reply.started":"2021-06-16T10:26:14.695160Z","shell.execute_reply":"2021-06-16T10:26:14.705791Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create the datasets\ntrain_dataset = tf_dataset(x_train, y_train)\nvalid_dataset = tf_dataset(x_valid, y_valid)","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:26:14.708301Z","iopub.execute_input":"2021-06-16T10:26:14.708767Z","iopub.status.idle":"2021-06-16T10:26:17.144605Z","shell.execute_reply.started":"2021-06-16T10:26:14.708727Z","shell.execute_reply":"2021-06-16T10:26:17.143793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Instanciate the model\nmodel = build_model()\nmodel.compile(loss='categorical_crossentropy', optimizer='Adam', metrics=['acc'])\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:26:17.146112Z","iopub.execute_input":"2021-06-16T10:26:17.146443Z","iopub.status.idle":"2021-06-16T10:26:29.033768Z","shell.execute_reply.started":"2021-06-16T10:26:17.146410Z","shell.execute_reply":"2021-06-16T10:26:29.032884Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Set callbacks\ncallbacks = [\n    EarlyStopping(\n    patience=5,\n    min_delta=0.001,\n    restore_best_weights=True,\n    ),\n    ModelCheckpoint('model.h5', verbose=1, save_best_only=True),\n    ReduceLROnPlateau(factor=0.1, patience=5, min_lr=1e-6)\n]\ntrain_steps = (len(x_train)//BATCH_SIZE) + 1\nvalid_steps = (len(x_valid)//BATCH_SIZE) + 1\n\n# Training\nhistory = model.fit(train_dataset,\n          steps_per_epoch=train_steps,\n          validation_steps=valid_steps,\n          validation_data=(valid_dataset),\n          epochs=EPOCHS,\n          callbacks=callbacks\n         )","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:26:29.035190Z","iopub.execute_input":"2021-06-16T10:26:29.035599Z","iopub.status.idle":"2021-06-16T10:37:23.510875Z","shell.execute_reply.started":"2021-06-16T10:26:29.035552Z","shell.execute_reply":"2021-06-16T10:37:23.509888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history_frame = pd.DataFrame(history.history)\nhistory_frame.loc[:, ['loss', 'val_loss']].plot()\nhistory_frame.loc[:, ['acc', 'val_acc']].plot();","metadata":{"execution":{"iopub.status.busy":"2021-06-16T10:37:23.512285Z","iopub.execute_input":"2021-06-16T10:37:23.512793Z","iopub.status.idle":"2021-06-16T10:37:23.961615Z","shell.execute_reply.started":"2021-06-16T10:37:23.512750Z","shell.execute_reply":"2021-06-16T10:37:23.960644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def decode_predictions(preds, top=5, class_list_path=None):\n    results = []\n    top_indices = (-preds).argsort()[0]\n    for i in range(top):\n        breed = id_to_breed.get(top_indices[i])\n        prob = preds[0][top_indices[i]]\n        results.append((breed, prob))\n    return results","metadata":{"execution":{"iopub.status.busy":"2021-06-16T11:14:33.662995Z","iopub.execute_input":"2021-06-16T11:14:33.663511Z","iopub.status.idle":"2021-06-16T11:14:33.670744Z","shell.execute_reply.started":"2021-06-16T11:14:33.663473Z","shell.execute_reply":"2021-06-16T11:14:33.669975Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Testing with friends and family dogs","metadata":{}},{"cell_type":"code","source":"images = glob(DOG_IMAGES_PATH)\n\nfor i in range(len(images)):\n    img_path = images[i]\n    display(Image(filename=img_path, width=SIZE, height=SIZE))\n    x = read_image(img_path)\n    x = np.expand_dims(x, axis=0)\n\n    preds = model.predict(x)\n    print('Predicted:', decode_predictions(preds, top=3))","metadata":{"execution":{"iopub.status.busy":"2021-06-16T11:14:35.540904Z","iopub.execute_input":"2021-06-16T11:14:35.541232Z","iopub.status.idle":"2021-06-16T11:14:39.812593Z","shell.execute_reply.started":"2021-06-16T11:14:35.541201Z","shell.execute_reply":"2021-06-16T11:14:39.811746Z"},"trusted":true},"execution_count":null,"outputs":[]}]}