{"cells":[{"metadata":{},"cell_type":"markdown","source":"### Begin by importing requirements"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":false,"_kg_hide-output":true},"cell_type":"code","source":"# https://www.pyimagesearch.com/2017/NUM_CLASSES/11/image-classification-with-keras-and-deep-learning/\n# https://machinelearningmastery.com/grid-search-hyperparameters-deep-learning-models-python-keras/\n# https://machinelearningmastery.com/save-load-keras-deep-learning-models/\n#https://www.learnopencv.com/image-classification-using-convolutional-neural-networks-in-keras/\n!pip install tensorflow-gpu\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\nimport random\nimport sys\nimport cv2\nimport matplotlib\nimport tensorflow\n\nfrom subprocess import check_output\nfrom datetime import datetime\n#tensorflow.keras.something\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Dropout, Flatten, Embedding\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img\nfrom tensorflow.keras.optimizers import Adam\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras.utils import to_categorical\n\n# Image Cropping Imports\nfrom PIL import ImageFile \nImageFile.LOAD_TRUNCATED_IMAGES = True\nfrom skimage import io\nfrom skimage.transform import resize\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#list the files in the input directory\n#classes : 0 - No DR, 1 - Mild, 2 - Moderate, 3 - Severe, 4 - Proliferative DR\n\n# print(os.listdir(\"../input\"))\n# print(check_output([\"ls\", \"../input\"]).decode(\"utf8\")) #trainLabels.csv\n# print(check_output([\"pwd\", \"\"]).decode(\"utf8\")) # /kaggle/working/\n","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"_kg_hide-output":true},"cell_type":"markdown","source":"### Allow for conversion of labels to categorical variables, pre-processing the size of images in the data-set and the epochs and batch size of the model."},{"metadata":{"trusted":true},"cell_type":"code","source":"def classes_to_int(label):\n    # label = classes.index(dir)\n    label = label.strip()\n    if label == \"No DR\":  return 0\n    if label == \"Mild\":  return 1\n    if label == \"Moderate\":  return 2\n    if label == \"Severe\":  return 3\n    if label == \"Proliferative DR\":  return 4\n    print(\"Invalid Label\", label)\n    return 5\n\ndef int_to_classes(i):\n    if i == 0: return \"No DR\"\n    elif i == 1: return \"Mild\"\n    elif i == 2: return \"Moderate\"\n    elif i == 3: return \"Severe\"\n    elif i == 4: return \"Proliferative DR\"\n    print(\"Invalid class \", i)\n    return \"Invalid Class\"\n\n\nNUM_CLASSES = 5\n\n# we resize images\nWIDTH = 128\nHEIGHT = 128\nDEPTH = 3\ninputShape = (HEIGHT, WIDTH, DEPTH)\n\n# initialize number of epochs to train for, initial learning rate and batch size\nEPOCHS = 15\nINIT_LR = 1e-3\nBS = 32\n\n#global variables\nImageNameDataHash = {}\nuniquePatientIDList = []","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Pre-process the images "},{"metadata":{"trusted":true},"cell_type":"code","source":"def readTrainData(trainDir):\n    global ImageNameDataHash\n    # loop over the input images\n    images = os.listdir(trainDir)\n    print(\"Number of files in \" + trainDir + \" is \" + str(len(images)))\n    for imageFileName in images:\n        if (imageFileName == \"trainLabels.csv\"):\n            continue\n        # load the image, pre-process it, and store it in the data list\n        imageFullPath = os.path.join(os.path.sep, trainDir, imageFileName)\n        #print(imageFullPath)\n        img = load_img(imageFullPath)\n        arr = img_to_array(img)  # Numpy array with shape (233,233,3)\n        dim1 = arr.shape[0]\n        dim2 = arr.shape[1]\n        dim3 = arr.shape[2]\n        if (dim1 < HEIGHT or dim2 < WIDTH or dim3 < DEPTH):\n            print(\"Error image dimensions are less than expected \"+str(arr.shape))\n        arr = cv2.resize(arr, (HEIGHT,WIDTH)) #Numpy array with shape (HEIGHT, WIDTH,3)\n        #print(arr.shape) # 128,128,3\n        dim1 = arr.shape[0]\n        dim2 = arr.shape[1]\n        dim3 = arr.shape[2]\n        if (dim1 != HEIGHT or dim2 != WIDTH or dim3 != DEPTH):\n            print(\"Error after resize, image dimensions are not equal to expected \"+str(arr.shape))\n        #print(type(arr))\n        # scale the raw pixel intensities to the range [0, 1] - TBD TEST\n        arr = np.array(arr, dtype=\"float\") / 255.0\n        imageFileName = imageFileName.replace('.jpeg','')\n        ImageNameDataHash[str(imageFileName)] = np.array(arr) \n    return","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from datetime import datetime\nprint(\"Loading images at...\"+ str(datetime.now()))\nsys.stdout.flush()\nreadTrainData(\"/kaggle/working/../input/\")\nprint(\"Loaded \" + str(len(ImageNameDataHash)) + \" images at...\"+ str(datetime.now())) # 1000","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Further look into the data..."},{"metadata":{"trusted":true},"cell_type":"code","source":"#csv contains image\tlevel\n#10_left 0\n#10_right 0\nimport csv\ndef readTrainCsv():\n    raw_df = pd.read_csv('/kaggle/working/../input/trainLabels.csv', sep=',')\n    print(type(raw_df)) #<class 'pandas.core.frame.DataFrame'>\n    row_count=raw_df.shape[0] #gives number of row count row_count=35126 \n    col_count=raw_df.shape[1] #gives number of col count col count=2\n    print(\"row_count=\"+str(row_count)+\" col count=\"+str(col_count))\n    raw_df[\"PatientID\"] = ''\n    header_list = list(raw_df.columns)\n    print(header_list) # ['image', 'level', 'PatientID']\n    # double check if level of left and right are same or not\n    ImageLevelHash = {}\n    patientIDList = []\n    for index, row in raw_df.iterrows():\n        # 0 is image, 1 is level, 2 is PatientID, 3 is data\n        key = row[0] + ''\n        patientID = row[0] + ''\n        patientID = patientID.replace('_right','')\n        patientID = patientID.replace('_left','')\n        #print(\"Adding patient ID\"+ patientID)\n        raw_df.at[index, 'PatientID'] = patientID\n        patientIDList.append(patientID)\n        ImageLevelHash[key] = str(row[1]) # level\n                \n    global uniquePatientIDList\n    uniquePatientIDList = sorted(set(patientIDList))\n    count=0;\n    for patientID in uniquePatientIDList:\n        left_level = ImageLevelHash[str(patientID+'_left')]\n        right_level = ImageLevelHash[str(patientID+'_right')]\n        #right_exists = str(patientID+'_right') in raw_df.values\n        if (left_level != right_level):\n            count = count+1\n            #print(\"Warning for patient=\"+ str(patientID) + \" left_level=\" + left_level+ \" right_level=\" +right_level)\n    print(\"count of images with both left and right eye level not matching=\"+str(count)) # 2240\n    print(\"number of unique patients=\"+str(len(uniquePatientIDList))) # 17563\n    return raw_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"random.seed(10)\nprint(\"Reading trainLabels.csv...\")\ndf = readTrainCsv()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# df has 3 columns ['image', 'level', 'PatientID']\nkeepImages =  list(ImageNameDataHash.keys())\ndf = df[df['image'].isin(keepImages)]\nprint(len(df)) # 1000","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#convert hash to dataframe\nimageNameArr = []\ndataArr = []\nfor index, row in df.iterrows():\n    key = str(row[0])\n    if key in ImageNameDataHash:\n        imageNameArr.append(key)\n        dataArr.append(np.array(ImageNameDataHash[key])) # np.array\n\ndf2 = pd.DataFrame({'image': imageNameArr, 'data': dataArr})\ndf2_header_list = list(df2.columns) \nprint(df2_header_list) # ['image', 'data']\nprint(len(df2)) # 1000\n#print(df2.describe(include='all'))\n#print(df2.sample(3)) # 3 rows x 2 columns","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"if len(df) != len(df2):\n    print(\"Error length of df != df2\")\n    \nfor idx in range(0,len(df)):\n    if (df.loc[df.index[idx], 'image'] != df2.loc[df2.index[idx], 'image']):\n        print(\"Error \" + df.loc[df.index[idx], 'image'] +\"==\" + df2.loc[df2.index[idx], 'image'])\n        \nprint(df2.dtypes)\nprint(df.dtypes)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.merge(df2, df, left_on='image', right_on='image', how='outer')\ndf_header_list = list(df.columns) \nprint(df_header_list) # 'image', 'data', level', 'PatientID'\nprint(len(df)) # 1000\nprint(df.sample())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_directory(directory):\n    '''\n    Creates a new folder in the specified directory if the folder doesn't exist.\n    INPUT\n        directory: Folder to be created, called as \"folder/\".\n    OUTPUT\n        New folder in the current directory.\n    '''\n    if not os.path.exists(directory):\n        os.makedirs(directory)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def crop_and_resize_images(path, new_path, cropx, cropy, img_size=256):\n    '''\n    Crops, resizes, and stores all images from a directory in a new directory.\n    INPUT\n        path: Path where the current, unscaled images are contained.\n        new_path: Path to save the resized images.\n        img_size: New size for the rescaled images.\n    OUTPUT\n        All images cropped, resized, and saved from the old folder to the new folder.\n    '''\n    create_directory(new_path)\n    dirs = [l for l in os.listdir(path) if l != '.DS_Store']\n    total = 0\n\n    for item in dirs:\n        img = io.imread(path+item)\n        y,x,channel = img.shape\n        startx = x//2-(cropx//2)\n        starty = y//2-(cropy//2)\n        img = img[starty:starty+cropy,startx:startx+cropx]\n        img = resize(img, (256,256))\n        io.imsave(str(new_path + item), img)\n        total += 1\n        print(\"Saving: \", item, total)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Print a sample image from the dataset and look at the sape of the "},{"metadata":{"trusted":true},"cell_type":"code","source":"# sample0 = df.loc[df.index[0], 'data']\n# print(sample0)\n# print(type(sample0)) # <class 'numpy.ndarray'>\n# print(sample0.shape) # 128,128,3\n# from matplotlib import pyplot as plt\n# plt.imshow(sample0, interpolation='nearest')\n# plt.show()\n# print(\"Sample Image\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Scale the raw pixel intensities to the range [0, 1] then convert labels to vectors"},{"metadata":{"trusted":true},"cell_type":"code","source":"X = df['data']\nY = df['level']\n\n#print(type(X)) # 'pandas.core.series.Series'\n#X = np.array(X, dtype=\"float\") / 255.0 -- TBD moved to top\nY = np.array(Y)\n\nY =  to_categorical(Y, num_classes=NUM_CLASSES)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Split data into training and testing using 75% training and 25% for validation... refer to https://www.kaggle.com/kmader/tf-data-tutorial-with-retina-and-keras\n\n### Then reset index for new dataframes"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Parttition data into 75:25...\")\nsys.stdout.flush()\nprint(\"Unique patients in dataframe df=\" + str(df.PatientID.nunique())) # 500\nunique_ids = df.PatientID.unique()\nprint('unique_ids shape='+ str(len(unique_ids))) #500\n\ntrain_ids, valid_ids = train_test_split(unique_ids, test_size = 0.25, random_state = 10) #stratify = rr_df['level'])\ntrainid_list = train_ids.tolist()\nprint('trainid_list shape=', str(len(trainid_list))) # 375\n\ntraindf = df[df.PatientID.isin(trainid_list)]\nvalSet = df[~df.PatientID.isin(trainid_list)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"traindf = traindf.reset_index(drop=True)\nvalSet = valSet.reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trainX = traindf['data']\ntrainY = traindf['level']\n\nvalX = valSet['data']\nvalY = valSet['level']\n\n#(trainX, valX, trainY, valY) = train_test_split(X,Y,test_size=0.25, random_state=10)\nprint('trainX shape=', trainX.shape[0], 'valX shape=', valX.shape[0]) # 750, 250\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trainY =  to_categorical(trainY, num_classes=NUM_CLASSES)\nvalY =  to_categorical(valY, num_classes=NUM_CLASSES)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Begin Data Augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"#construct the image generator for data augmentation\nprint(\"Generating images...\")\nsys.stdout.flush()\naug = ImageDataGenerator(rotation_range=30, width_shift_range=0.1, \\\n    height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,\\\n    horizontal_flip=True, fill_mode=\"nearest\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### The function below builds the model, we will be using 4 layers?? "},{"metadata":{"trusted":true},"cell_type":"code","source":"def createModel():\n    print (\"num classes\", NUM_CLASSES)\n    model = Sequential()\n    # first set of CONV => RELU => MAX POOL layers\n    model.add(Conv2D(32, (3, 3), padding='same', activation='relu', input_shape=inputShape))\n    model.add(Conv2D(32, (3, 3), activation='relu'))\n    model.add(MaxPooling2D(pool_size=(2, 2)))\n    model.add(Dropout(0.25))\n    \n    model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))\n    model.add(Conv2D(64, (3, 3), activation='relu'))\n    model.add(MaxPooling2D(pool_size=(2, 2)))\n    model.add(Dropout(0.25))\n    \n    model.add(Conv2D(64, (3, 3), padding='same', activation='relu'))\n    model.add(Conv2D(64, (3, 3), activation='relu'))\n    model.add(MaxPooling2D(pool_size=(2, 2)))\n    model.add(Dropout(0.25))\n    \n    model.add(Flatten())\n    model.add(Dense(512, activation='relu'))\n    model.add(Dropout(0.5))\n    \n    # Output layer\n    model.add(Embedding(output_dim=NUM_CLASSES, activation='softmax'))\n#     keras.layers.Embedding(output_dim=NUM_CLASSES)\n    # returns our fully constructed deep learning + Keras image classifier \n    opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)\n    # use binary_crossentropy if there are two classes\n    model.compile(loss=\"categorical_crossentropy\", optimizer=opt, metrics=[\"accuracy\"])\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Reshaping trainX at...\"+ str(datetime.now()))\n#print(trainX.sample()) \nprint(type(trainX)) # <class 'pandas.core.series.Series'>\nprint(trainX.shape) # (750,)\nfrom numpy import zeros\nXtrain = np.zeros([trainX.shape[0],HEIGHT, WIDTH, DEPTH])\nfor i in range(trainX.shape[0]): # 0 to traindf Size -1\n    Xtrain[i] = trainX[i]\nprint(Xtrain.shape) # (750,128,128,3)\nprint(\"Reshaped trainX at...\"+ str(datetime.now()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Reshaping valX at...\"+ str(datetime.now()))\nprint(type(valX)) # <class 'pandas.core.series.Series'>\nprint(valX.shape) # (250,)\nfrom numpy import zeros\nXval = np.zeros([valX.shape[0],HEIGHT, WIDTH, DEPTH])\nfor i in range(valX.shape[0]): # 0 to traindf Size -1\n    Xval[i] = valX[i]\nprint(Xval.shape) # (250,128,128,3)\nprint(\"Reshaped valX at...\"+ str(datetime.now()))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Initialise Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# initialize the model\nprint(\"compiling model...\")\nsys.stdout.flush()\nmodel = createModel()\n\n# print the summary of model\nfrom tensorflow.keras.utils import print_summary\nprint_summary(model, line_length=None, positions=None, print_fn=None)\n\n# add some visualization\nfrom IPython.display import SVG\nfrom tensorflow.keras.utils.vis_utils import model_to_dot\nSVG(model_to_dot(model).create(prog='dot', format='svg'))","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}