{"cells":[{"metadata":{},"cell_type":"markdown","source":"Import packages"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nfrom tensorflow.python.keras.applications.resnet50 import preprocess_input\nfrom tensorflow.python.keras.preprocessing.image import load_img, img_to_array\nfrom tensorflow.python.keras.applications import ResNet50\nfrom tensorflow.python.keras.models import Sequential\nfrom tensorflow.python.keras.layers import Dense, Flatten, GlobalAveragePooling2D, Dropout\nfrom tensorflow.python.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import EarlyStopping\nimport pandas as pd\nimport os\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(os.listdir(\"../input/aptos2019-blindness-detection\"))\nprint(os.listdir(\"../input/resnet50\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Create a dictionary for class weights"},{"metadata":{"trusted":true},"cell_type":"code","source":"class_weights = {0 : 1, 1 : 4.87, 2 : 1.8, 3 : 9.35, 4 : 6.12}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Read in train.csv and append the file extension to the id_code to use them as paths in the *flow_from_dataframe* generator. At the same time the class names are converted to strings beacause *flow_from_dataframe* doesn't really like integers as class names. In this step the submission file is also preprared and the paths to the test images are written to a list."},{"metadata":{"trusted":true},"cell_type":"code","source":"filenames = os.listdir(\"../input/aptos2019-blindness-detection/test_images\")\nimg_paths = [\"../input/aptos2019-blindness-detection/test_images/\" + filename for filename in filenames]\n\ntrain = pd.read_csv(\"../input/aptos2019-blindness-detection/train.csv\", sep = \",\")\nsubmission = pd.DataFrame(columns = [\"id_code\", \"diagnosis\"])\n\nfor i in range(0, len(train)):\n\tid_code = train.iloc[i, 0]\n\tid_code = id_code + \".png\"\n\ttrain.iloc[i, 0] = id_code\n\tdiagnosis = train.iloc[i, 1]\n\tdiagnosis = str(diagnosis)\n\ttrain.iloc[i, 1] = diagnosis\n\n\ti += 1\n\nprint(train.head())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Define some parameters"},{"metadata":{"trusted":true},"cell_type":"code","source":"image_size = 224\nnum_classes = 5\nbatch_size = 32\npred_batch_size = 50\nnum_epochs = 20\nsteps_per_epoch = 64","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Define and run the train and validation data generators."},{"metadata":{"trusted":true},"cell_type":"code","source":"data_generator = ImageDataGenerator(preprocessing_function = preprocess_input, validation_split = 0.3)\n\n\ntrain_generator = data_generator.flow_from_dataframe(\n\t\tdataframe = train,\n\t\tdirectory = \"../input/aptos2019-blindness-detection/train_images\",\n\t\tx_col = \"id_code\",\n\t\ty_col = \"diagnosis\",\n\t\ttarget_size = (image_size, image_size),\n\t\tbatch_size = batch_size,\n\t\tclass_mode = \"categorical\",\n\t\tsubset = \"training\")\n\nvalidation_generator = data_generator.flow_from_dataframe(\n\t\tdataframe = train,\n\t\tdirectory = \"../input/aptos2019-blindness-detection/train_images\",\n\t\tx_col = \"id_code\",\n\t\ty_col = \"diagnosis\",\n\t\ttarget_size = (image_size, image_size),\n\t\tbatch_size = batch_size,\n\t\tclass_mode = \"categorical\",\n\t\tsubset = \"validation\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Build and compile the model. After my implementation of AlexNet failed miserably I went for ResNet50. Because ResNet kinda sucks for this task with its imagenet weights on layer 0, I train it from the ground up."},{"metadata":{"trusted":true},"cell_type":"code","source":"model = Sequential()\nmodel.add(ResNet50(include_top = False, pooling = \"avg\",\n                   weights = \"../input/resnet50/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5\"))\nmodel.add(Dense(128, activation = \"relu\"))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(64, activation = \"relu\"))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(num_classes, activation = \"softmax\"))\n\nmodel.layers[0].trainable = True\n\nmodel.compile(optimizer = \"sgd\", loss = \"categorical_crossentropy\", metrics = [\"accuracy\"])\n\nprint(model.summary())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Fit the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(\n\t\ttrain_generator,\n\t\tepochs = num_epochs,\n\t\tsteps_per_epoch = steps_per_epoch,\n\t\tvalidation_data = validation_generator,\n\t\tvalidation_steps = 1,\n\t\tclass_weight = class_weights)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Plot some graphs of how the training went"},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot():\n    plt.plot(history.history[\"acc\"])\n    plt.plot(history.history[\"val_acc\"])\n    plt.title(\"model accuracy (image_size = {}, batch_size = {},\\nsteps_per_epoch = {}, num_epochs = {})\".\n             format(image_size, batch_size, steps_per_epoch, num_epochs))\n    plt.ylabel(\"accuracy\")\n    plt.xlabel(\"epoch\")\n    plt.ylim(top = 1, bottom = 0.4)\n    plt.legend([\"train\", \"test\"], loc = \"upper left\")\n    plt.show()\n    \n    plt.plot(history.history[\"loss\"])\n    plt.plot(history.history[\"val_loss\"])\n    plt.title(\"loss\")\n    plt.ylabel(\"loss\")\n    plt.xlabel(\"epoch\")\n    plt.ylim(top = 3, bottom = 0)\n    plt.legend([\"train\", \"test\"], loc = \"upper left\")\n    plt.show()\n    \nplot()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Convert the test images to numpy arrays and run preprocessing to make predictions in the next cell. This *read_and_prep_images* function is ripped straight from the deep learning kaggle course, [lesson 3](https://www.kaggle.com/dansbecker/tensorflow-programming) btw."},{"metadata":{"trusted":true},"cell_type":"code","source":"def read_and_prep_images(img_paths, image_size):\n\timgs = [load_img(img_path, target_size = (image_size, image_size)) for img_path in img_paths]\n\timg_array = np.array([img_to_array(img) for img in imgs])\n\toutput = preprocess_input(img_array)\n\n\treturn output","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Split the test images into batches of x-amount (x actually being *pred_batch_size* from the 5th cell) of images, make predictions and get the class with the highest softmax score and append it together with its image name to the submissions file. The batches of images are made because of the weird way kaggle kernels manage their memory, this way I don't run out of memory when running the kernel for the submission on the entire test set with its roughly 15k images."},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_preds(img_paths, preds):\n    img_paths = img_paths\n    print(len(img_paths))\n    submission = pd.DataFrame(columns = [\"id_code\", \"diagnosis\"])\n    for i, img_path in enumerate(img_paths):\n        pred = preds[i]\n        p0 = pred[0]\n        p1 = pred[1]\n        p2 = pred[2]\n        p3 = pred[3]\n        p4 = pred[4]\n\n        if p0 > p1 and p0 > p2 and p0 > p3 and p0 > p4:\n            p = 0\n        elif p1 > p0 and p1 > p2 and p1 > p3 and p1 > p4:\n            p = 1\n        elif p2 > p0 and p2 > p1 and p2 > p3 and p2 > p4:\n            p = 2\n        elif p3 > p0 and p3 > p1 and p3 > p2 and p3 > p4:\n            p = 3\n        elif p4 > p0 and p4 > p1 and p4 > p2 and p4 > p3:\n            p = 4\n\n        img_path = img_path[51:-4]\n        df = pd.DataFrame([[img_path, p]], columns = [\"id_code\", \"diagnosis\"])\n        submission = submission.append(df, ignore_index = True)\n    print(len(submission))\n    #print(submission)\n    return submission\n\ncomplete_submission = pd.DataFrame(columns = [\"id_code\", \"diagnosis\"])\na = int(len(img_paths) / pred_batch_size)\nfor i in range(0, a + 1):\n    img_paths_n = img_paths[i * pred_batch_size:(i + 1) * pred_batch_size]\n    test_data = read_and_prep_images(img_paths_n, image_size)\n    preds = model.predict(test_data)\n    submission = make_preds(img_paths_n, preds)\n    complete_submission = complete_submission.append(submission, ignore_index = True)\n    print(\"Images {} to {} predicted and saved.\".format(i * pred_batch_size, i * pred_batch_size + len(img_paths_n)))\n    i += 1\n\nprint(len(complete_submission))\ncomplete_submission.to_csv((\"submission.csv\"), sep = \",\", index = False)\nprint(\"All done\")","execution_count":null,"outputs":[]}],"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":1}