{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":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":{},"cell_type":"markdown","source":"# References:\n\nhttps://www.kaggle.com/myltykritik/simple-lgbm-image-features\n\nhttps://stackoverflow.com/questions/47200146/keras-load-images-batch-wise-for-large-dataset\n\nhttps://towardsdatascience.com/building-a-convolutional-neural-network-cnn-in-keras-329fbbadc5f5\n\nhttps://keras.io/models/model/\n\nhttps://www.pyimagesearch.com/2018/12/24/how-to-use-keras-fit-and-fit_generator-a-hands-on-tutorial/\n\nhttps://keras.io/layers/pooling/\n\nhttps://towardsdatascience.com/transfer-learning-and-image-classification-using-keras-on-kaggle-kernels-c76d3b030649"},{"metadata":{},"cell_type":"markdown","source":"# Imports"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"# time\nimport time\n# import OpenCV\nimport cv2\n# random\nimport random\nrandom.seed(1331)\n# viz\nimport matplotlib.pyplot as plt\n%matplotlib inline\n# Keras\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Conv2D, Flatten, Dropout, MaxPooling2D, GlobalAveragePooling2D\nfrom keras.utils import to_categorical\nfrom keras.applications import DenseNet121\nfrom keras import backend as K\nfrom keras.optimizers import Adam","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# View Image Shapes"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(cv2.imread('../input/aptos2019-blindness-detection/train_images/000c1434d8d7.png').shape)\nprint(cv2.imread('../input/aptos2019-blindness-detection/train_images/4289af3afbd2.png').shape)\nprint(cv2.imread('../input/aptos2019-blindness-detection/train_images/810ed108f5b7.png').shape)\nprint(cv2.imread('../input/aptos2019-blindness-detection/train_images/be521870a0ea.png').shape)\nprint(cv2.imread('../input/aptos2019-blindness-detection/train_images/001639a390f0.png').shape)\nprint(cv2.imread('../input/aptos2019-blindness-detection/train_images/4294a14c656a.png').shape)\nprint(cv2.imread('../input/aptos2019-blindness-detection/train_images/8114d6a160df.png').shape)\nprint(cv2.imread('../input/aptos2019-blindness-detection/train_images/be68322c7223.png').shape)\nprint(cv2.imread('../input/aptos2019-blindness-detection/train_images/0024cdab0c1e.png').shape)\nprint(cv2.imread('../input/aptos2019-blindness-detection/train_images/42985aa2e32f.png').shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# View an Image"},{"metadata":{"trusted":true},"cell_type":"code","source":"# read in image\nimg = cv2.imread('../input/aptos2019-blindness-detection/train_images/f549294e12e1.png')\n#img = cv2.imread('../input/aptos2019-blindness-detection/train_images/000c1434d8d7.png')\nimg = cv2.resize(img, (224,224))\n# show image\nplt.imshow(img)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.max(img)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Set Up ID & Target Lookup Table"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('../input/aptos2019-blindness-detection/train.csv')\nids_and_target = train_df[['id_code','diagnosis']]\nonehottarget = pd.get_dummies(ids_and_target['diagnosis'])\nids_and_target = ids_and_target.join(onehottarget)\nids_and_target.iloc[:,5] = np.where(ids_and_target.iloc[:,6]>ids_and_target.iloc[:,5], ids_and_target.iloc[:,6], ids_and_target.iloc[:,5])\nids_and_target.iloc[:,4] = np.where(ids_and_target.iloc[:,5]>ids_and_target.iloc[:,4], ids_and_target.iloc[:,5], ids_and_target.iloc[:,4])\nids_and_target.iloc[:,3] = np.where(ids_and_target.iloc[:,4]>ids_and_target.iloc[:,3], ids_and_target.iloc[:,4], ids_and_target.iloc[:,3])\nids_and_target.iloc[:,2] = np.where(ids_and_target.iloc[:,3]>ids_and_target.iloc[:,2], ids_and_target.iloc[:,3], ids_and_target.iloc[:,2])\nprint(ids_and_target.head())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test out diagnosis extraction code\ngetrow = ids_and_target.loc[ids_and_target['id_code'] == 'f549294e12e1']\nprint(getrow)\nprint(np.asarray(getrow[[0,1,2,3,4]].values[0], dtype=np.float32))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"to_categorical(ids_and_target['diagnosis'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# My Data Augmentation Function"},{"metadata":{"trusted":true},"cell_type":"code","source":"def MyAug(fiximg, shape):\n    auglist = [fiximg]\n    \n    # we can only fit so much into memory\n    # so every round we will randomly select an augmentation to apply for training\n    augshuf = random.randint(1,101)\n    \n    if augshuf in range(1,11):\n    \n        # Augmentation 1\n\n        # blur image using 25x25 kernel\n        blurred = cv2.blur(fiximg, ksize=(25,25))\n        # write out image\n        auglist.append(blurred)\n    \n    elif augshuf in range(11,21):\n    \n        # Augmentation 2\n\n        # covert to HSV\n        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)\n        # We're going to equalize the value channel\n        hsv[:,:,2] = cv2.equalizeHist(hsv[:,:,2])\n        # convert back to RGB\n        eq_color_img = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)\n        # write out image\n        auglist.append(eq_color_img)\n    \n    elif augshuf in range(21,31):\n    \n        # Augmentation 3\n\n        y_offsetp1 = int(fiximg.shape[0]*0.25)\n        y_offsetp2 = int(fiximg.shape[0]*0.75)\n        x_offsetp1 = int(fiximg.shape[1]*0.25)\n        x_offsetp2 = int(fiximg.shape[1]*0.75)\n        # crop\n        cropped_img = fiximg[y_offsetp1:y_offsetp2,x_offsetp1:x_offsetp2]\n        cropped_img = cv2.resize(cropped_img, shape)\n        # write out image\n        auglist.append(cropped_img)\n    \n    elif augshuf in range(31,41):\n    \n        # Augmentation 4\n\n        y_offsetp1 = int(fiximg.shape[0]*0)\n        y_offsetp2 = int(fiximg.shape[0]*0.6)\n        x_offsetp1 = int(fiximg.shape[1]*0)\n        x_offsetp2 = int(fiximg.shape[1]*0.6)\n        # crop\n        cropped_img = fiximg[y_offsetp1:y_offsetp2,x_offsetp1:x_offsetp2]\n        cropped_img = cv2.resize(cropped_img, shape)\n        # write out image\n        auglist.append(cropped_img)\n\n    elif augshuf in range(41,51):\n        \n        # Augmentation 5\n\n        y_offsetp1 = int(fiximg.shape[0]*0)\n        y_offsetp2 = int(fiximg.shape[0]*0.6)\n        x_offsetp1 = int(fiximg.shape[1]*0.4)\n        x_offsetp2 = int(fiximg.shape[1]*1)\n        # crop\n        cropped_img = fiximg[y_offsetp1:y_offsetp2,x_offsetp1:x_offsetp2]\n        cropped_img = cv2.resize(cropped_img, shape)\n        # write out image\n        auglist.append(cropped_img)\n    \n    elif augshuf in range(51,61):\n    \n        # Augmentation 6\n\n        y_offsetp1 = int(fiximg.shape[0]*0)\n        y_offsetp2 = int(fiximg.shape[0]*0.6)\n        x_offsetp1 = int(fiximg.shape[1]*0.4)\n        x_offsetp2 = int(fiximg.shape[1]*1)\n        # crop\n        cropped_img = fiximg[y_offsetp1:y_offsetp2,x_offsetp1:x_offsetp2]\n        cropped_img = cv2.resize(cropped_img, shape)\n        # write out image\n        auglist.append(cropped_img)\n    \n    elif augshuf in range(61,71):\n    \n        # Augmentation 7\n    \n        y_offsetp1 = int(fiximg.shape[0]*0.4)\n        y_offsetp2 = int(fiximg.shape[0]*1)\n        x_offsetp1 = int(fiximg.shape[1]*0.4)\n        x_offsetp2 = int(fiximg.shape[1]*1)\n        # crop\n        cropped_img = fiximg[y_offsetp1:y_offsetp2,x_offsetp1:x_offsetp2]\n        cropped_img = cv2.resize(cropped_img, shape)\n        # write out image\n        auglist.append(cropped_img)\n    \n    elif augshuf in range(71,81):\n    \n    # Augmentations 8-12\n        # Augmentation 8\n    \n    #for i in range(8, 13):\n        # generate random percentages\n        xp1 = min(.15,random.randint(1,100)/100)\n        xp2 = max(.85,random.randint(1,100)/100)\n        yp1 = min(.15,random.randint(1,100)/100)\n        yp2 = max(.85,random.randint(1,100)/100)\n        # create points\n        y_offsetp1 = int(fiximg.shape[0]*yp1)\n        y_offsetp2 = int(fiximg.shape[0]*yp2)\n        x_offsetp1 = int(fiximg.shape[1]*xp1)\n        x_offsetp2 = int(fiximg.shape[1]*xp2)\n        # crop\n        cropped_img = fiximg[y_offsetp1:y_offsetp2,x_offsetp1:x_offsetp2]\n        cropped_img = cv2.resize(cropped_img, shape)\n        # write out image\n        auglist.append(cropped_img)\n        \n    elif augshuf in range(81,91):\n    # Augmentations 13-18\n    \n    #i = 13\n    #for rot in [-40, -30, -20, 20, 30, 40]:\n        rot = random.choice(np.arange(-180,179,1))\n        if rot ==0:\n            rot = 179\n        rows,cols,_ = fiximg.shape\n        M = cv2.getRotationMatrix2D((cols/2,rows/2),rot,1)\n        dst = cv2.warpAffine(fiximg,M,(cols,rows))\n        auglist.append(dst)\n        #i += 1\n        \n    elif augshuf in range(91,101):\n        \n        # Augmentation 19\n\n        rows,cols,ch = fiximg.shape\n        pts1 = np.float32([[50,50],[200,50],[50,200]])\n        pts2 = np.float32([[10,100],[200,50],[100,250]])\n        M = cv2.getAffineTransform(pts1,pts2)\n        dst = cv2.warpAffine(fiximg,M,(cols,rows))\n        # write out image\n        auglist.append(dst)\n    \n    return auglist","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Function to Load Images"},{"metadata":{"trusted":true},"cell_type":"code","source":"def LoadImagesAndTarget_Train(files, lookup_table, shape):\n    i = 0\n    w = shape[0]\n    h = shape[1]\n    batch_images = np.zeros(((len(files) * 2),w,h,3))\n    targetvals = np.zeros(((len(files) * 2),5))\n    for file in files:\n        # read in image\n        img = cv2.imread('../input/aptos2019-blindness-detection/train_images/' + file)\n        # resize\n        img = cv2.resize(img, shape)\n        #print(\"Starting image augmentation ...\")\n        newimages = MyAug(img, shape)\n        # normalize\n        newimages = np.array(newimages) / 255.0\n        #print(\"Loading batch images ...\")\n        for img in newimages:\n            # preprocessing for training, adds 'samples' dim\n            #fiximg = preprocess_input(img)\n            # add image to training set\n            batch_images[i] = img\n            # get the filename without extension\n            filename = os.path.splitext(file)[0]\n            # only keep the row from the lookup table that matches our id\n            getrow = lookup_table.loc[lookup_table['id_code'] == filename]\n            # change the format to one-hot encoded, and save to target dataset\n            targetvals[i] = np.asmatrix(getrow[[0,1,2,3,4]].values[0], dtype=np.float32)\n            # get target based on filename\n            i += 1\n    #print(\"returning batches ...\")\n    return batch_images, targetvals","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def LoadImagesAndTarget_Test(files, lookup_table, shape):\n    i = 0\n    w = shape[0]\n    h = shape[1]\n    batch_images = np.zeros(((len(files)),w,h,3))\n    targetvals = np.zeros(((len(files)),5))\n    for file in files:\n        # read in image\n        img = cv2.imread('../input/aptos2019-blindness-detection/train_images/' + file)\n        # resize\n        img = cv2.resize(img, shape)\n        #print(\"Starting image augmentation ...\")\n        # Note: No augmentation on test data\n        # normalize\n        img = np.array(img) / 255.0\n        batch_images[i] = img\n        # get the filename without extension\n        filename = os.path.splitext(file)[0]\n        # only keep the row from the lookup table that matches our id\n        getrow = lookup_table.loc[lookup_table['id_code'] == filename]\n        # change the format to one-hot encoded, and save to target dataset\n        targetvals[i] = np.asmatrix(getrow[[0,1,2,3,4]].values[0], dtype=np.float32)\n        # get target based on filename\n        i += 1\n    #print(\"returning batches ...\")\n    return batch_images, targetvals","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Create Image Loader"},{"metadata":{"trusted":true},"cell_type":"code","source":"def KerasModelTrainer(files, batch_size, lookup_table, epochs, test_size, shape):\n    \n    # initialize\n    L = len(files)\n    rnds = L // batch_size\n    training_loss_history_e = []\n    test_loss_history_e = []\n    training_acc_history_e = []\n    test_acc_history_e = []\n    #this line is just to make the generator infinite, keras needs that    \n    #while True:\n\n    for epoch in range(1,epochs + 1):\n        \n        # initialize\n        batch_start = 0\n        batch_end = batch_size\n        test_cases = int(batch_size * test_size)\n        training_loss_history = []\n        test_loss_history = []\n        training_acc_history = []\n        test_acc_history = []\n        mycnt = 0\n        start = time.time()\n        \n        print(\"Epoch {}/{}\".format(epoch,epochs))\n        \n        while batch_start < L:\n            \n            # initialize\n            mycnt += 1\n            pct = int((mycnt / rnds) * 100)\n            limit = min(batch_end, L)\n\n            Xtrain, Ytrain = LoadImagesAndTarget_Train(files[batch_start:(limit - test_cases)], lookup_table, shape)\n            Xtest, Ytest = LoadImagesAndTarget_Test(files[((limit - test_cases)):limit], lookup_table, shape)    \n\n            # train\n            # calculate learning rate\n            #current_learning_rate = 0.001 * (10**(-mycnt))\n            # train model:\n            #K.set_value(model.optimizer.lr, current_learning_rate)  # set new lr\n            model.train_on_batch(Xtrain,Ytrain)\n\n            # test on train\n            training_metrics = model.test_on_batch(Xtrain,Ytrain)\n            training_loss = training_metrics[0]\n            training_acc = training_metrics[1]\n            #print(training_acc)\n            \n            training_loss_history.append(training_loss)\n            training_acc_history.append(training_acc)\n            #print(training_acc_history)\n            #print(np.mean(training_acc_history))\n            \n            # test on test\n            test_metrics = model.test_on_batch(Xtest,Ytest)\n            test_loss = test_metrics[0]\n            test_acc = test_metrics[1]\n            \n            test_loss_history.append(test_loss)\n            test_acc_history.append(test_acc)\n            \n            batch_start += batch_size   \n            batch_end += batch_size\n            \n            if np.isnan(np.mean(training_acc_history)) == False:\n                train_acc_mean = np.mean(training_acc_history)\n            if np.isnan(np.mean(test_acc_history)) == False:\n                test_acc_mean = np.mean(test_acc_history)\n            \n            print(\"Training {}% [\".format(pct), \n                  \"#\" * int(pct/5), \n                  \".\" * (20 - int(pct/5)), \"]\", \n                  \" Train Acc: {0:.3f} | \".format(train_acc_mean), \n                  \" Test Acc: {0:.3f}\".format(test_acc_mean), end='\\r')\n        \n        end = time.time()\n        print(\"\")\n        print(\"Processing Time: {0:.2f} min\".format((end - start) / 60))\n        \n        test_loss_history_e.append(np.mean(test_loss_history))\n        test_acc_history_e.append(np.mean(test_acc_history))\n        training_loss_history_e.append(np.mean(training_loss_history))\n        training_acc_history_e.append(np.mean(training_acc_history))\n    \n    return model, training_loss_history_e, test_loss_history_e, training_acc_history_e, test_acc_history_e","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Define Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"densenet = DenseNet121(\n    weights='../input/densenetkeras/DenseNet-BC-121-32-no-top.h5',\n    include_top=False,\n    input_shape=(224,224,3)\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#create model\nmodel = Sequential()\n#add model layers\nmodel.add(densenet)\nmodel.add(Conv2D(60, kernel_size=2, activation='tanh', padding='same'))\nmodel.add(Dropout(0.2))\nmodel.add(Conv2D(60, kernel_size=2, activation='tanh', padding='same'))\nmodel.add(Dropout(0.2))\nmodel.add(GlobalAveragePooling2D())\nmodel.add(Dropout(0.5))\nmodel.add(Dense(5, activation='sigmoid'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#densenet.trainable = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#compile model using accuracy to measure model performance\nmodel.compile(optimizer=Adam(lr=0.00005), loss='binary_crossentropy', metrics=['accuracy'])\nprint(model.summary())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Run Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"#files = os.listdir('../input/aptos2019-blindness-detection/train_images') \n#files = random.sample(files, 2000)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"files = os.listdir('../input/aptos2019-blindness-detection/train_images') ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = 12\nmodel, train_loss_hist, test_loss_hist, train_acc_hist, test_acc_hist = KerasModelTrainer(files=files,\n                                                                                          batch_size=32,\n                                                                                          lookup_table=ids_and_target, \n                                                                                          epochs=epochs, \n                                                                                          test_size=0.15, \n                                                                                          shape=(224,224))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(np.arange(1, epochs+1, 1), test_loss_hist)\nplt.plot(np.arange(1, epochs+1, 1), train_loss_hist)\nplt.xlabel('Rounds / Batches')\nplt.ylabel('Loss')\nplt.title('Train / Test Loss History')\nplt.legend(['test', 'train'], loc='upper left')\nplt.grid(True)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(np.arange(1, epochs+1, 1), test_acc_hist)\nplt.plot(np.arange(1, epochs+1, 1), train_acc_hist)\nplt.xlabel('Rounds / Batches')\nplt.ylabel('Accuracy')\nplt.title('Train / Test Acc History')\nplt.legend(['test', 'train'], loc='upper left')\nplt.grid(True)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Score Images"},{"metadata":{"trusted":true},"cell_type":"code","source":"files = os.listdir('../input/aptos2019-blindness-detection/test_images')\ni = 0\nfor file in files:\n    batch_images = np.zeros((1,224,224,3))\n    # read in image\n    img = cv2.imread('../input/aptos2019-blindness-detection/test_images/' + file)\n    # resize\n    img = cv2.resize(img, (224,224))\n    # normalize\n    img = np.array(img) / 255.0\n    #get filename\n    filename = os.path.splitext(file)[0]\n    # reformat img\n    batch_images[0] = img\n    # score image\n    pred = model.predict(batch_images, verbose=0)\n    if i == 0:\n        # add prediction and id to a dataframe\n        d = {'pred': [pred], 'id_code': [filename]}\n        df = pd.DataFrame(data=d)\n        i += 1\n    else:\n        # add prediction and id to a dataframe\n        d = {'pred': [pred], 'id_code': [filename]}\n        tmp = pd.DataFrame(data=d)\n        df = df.append(tmp, ignore_index=True)\n        i += 1\n        print(\"Number of images completed: {}\".format(i), end='\\r')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df[\"diagnosis\"] = df[\"pred\"].apply(lambda x: sum(sum((x>0.5).astype(int)))-1)\nsubmission = df[['id_code','diagnosis']]\nsubmission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df[\"diagnosis\"].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.to_csv('submission.csv',index=False)","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}