{"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":"import os\nimport random\nimport csv\nimport shutil\nimport cv2\nimport pandas as pd\nimport tensorflow as tf\nimport numpy as np\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom matplotlib import pyplot as plt\nfrom scipy.linalg import fractional_matrix_power\nfrom scipy.signal import wiener\nfrom PIL import Image","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:03:12.857915Z","iopub.execute_input":"2023-07-24T08:03:12.858286Z","iopub.status.idle":"2023-07-24T08:03:21.758901Z","shell.execute_reply.started":"2023-07-24T08:03:12.858253Z","shell.execute_reply":"2023-07-24T08:03:21.757977Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Image preprocessing","metadata":{}},{"cell_type":"code","source":"# CLAHE on green channel of RGB image \n\ndef enhance_contrast(image): \n    image = np.uint8(image)\n    r, g, b = cv2.split(image)\n    clahe = cv2.createCLAHE(clipLimit=2, tileGridSize=(8,8))\n    g = wiener(g, 2, 0.01) # weiner \n    g = np.uint8(g)\n    g_enhanced = clahe.apply(g)\n    image =  np.stack([r,g_enhanced,b],axis=-1)\n    image = cv2.resize(image, (224, 224))\n    return image\n    '''\n    # Split the image into RGB channels\n    red_channel, green_channel, blue_channel = cv2.split(image)\n    # Apply CLAHE to the green channel only\n    clahe = cv2.createCLAHE(clipLimit=2, tileGridSize=(8,8))\n    green_channel = wiener(green_channel, 2, 0.01) # weiner filter\n    green_enhanced = clahe.apply(green_channel)\n\n    # Merge the enhanced green channel with the original red and blue channels\n    enhanced_image = cv2.merge([red_channel, green_enhanced, blue_channel])\n    #enhanced_image = cv2.blur(image, (3,3)) # median filter\n    return enhanced_image\n    '''\n# crop image \ndef crop_image_from_gray(img,tol=7):\n    if img.ndim ==1:\n        return img\n    if img.ndim ==2:\n        mask = img>tol\n        return img[np.ix_(mask.any(1),mask.any(0))]\n    elif img.ndim==3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img>tol\n        \n        check_shape = img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]\n        if (check_shape == 0): # image is too dark so that we crop out everything,\n            return img # return original image\n        else:\n            img1=img[:,:,0][np.ix_(mask.any(1),mask.any(0))]\n            img2=img[:,:,1][np.ix_(mask.any(1),mask.any(0))]\n            img3=img[:,:,2][np.ix_(mask.any(1),mask.any(0))]\n    #         print(img1.shape,img2.shape,img3.shape)\n            img = np.stack([img1,img2,img3],axis=-1)\n    #         print(img.shape)\n        return img\n    \ndef preprocess_image(image):\n    image = crop_image_from_gray(image)\n    image = enhance_contrast(image)\n\n    #image = adjust_brightness(image)\n    return image\n# check cropping\nax = plt.subplot(1,2,1)\nimg = '/kaggle/input/diabetic-retinopathy-resized/resized_train/resized_train/10003_left.jpeg'\nimg = cv2.imread(img)\nimage = img[:,:,1]\nplt.imshow(image, cmap ='gray')\nimg = preprocess_image(img)\nax = plt.subplot(1,2,2)\nplt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:41:52.065644Z","iopub.execute_input":"2023-07-24T08:41:52.066009Z","iopub.status.idle":"2023-07-24T08:41:52.744394Z","shell.execute_reply.started":"2023-07-24T08:41:52.065979Z","shell.execute_reply":"2023-07-24T08:41:52.743486Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# brightness adjustment\ndef image_agcwd(img, a=0.25):\n    h,w = img.shape[:2]\n    hist,bins = np.histogram(img.flatten(),256,[0,256])\n    cdf = hist.cumsum()\n    cdf_normalized = cdf / cdf.max()\n    prob_normalized = hist / hist.sum()\n\n    unique_intensity = np.unique(img)\n    intensity_max = unique_intensity.max()\n    intensity_min = unique_intensity.min()\n    prob_min = prob_normalized.min()\n    prob_max = prob_normalized.max()\n    \n    pn_temp = (prob_normalized - prob_min) / (prob_max - prob_min)\n    pn_temp[pn_temp>0] = prob_max * (pn_temp[pn_temp>0]**a)\n    pn_temp[pn_temp<0] = prob_max * (-((-pn_temp[pn_temp<0])**a))\n    prob_normalized_wd = pn_temp / pn_temp.sum() # normalize to [0,1]\n    cdf_prob_normalized_wd = prob_normalized_wd.cumsum()\n    inverse_cdf = 1 - cdf_prob_normalized_wd\n    \n    img_new = img.copy()\n    for i in unique_intensity:\n        img_new[img==i] = np.round(255 * (i / 255)**inverse_cdf[i])\n   \n#   print (\"%f %f\"%(prob_min, prob_max))\n    #plt.plot(inverse_cdf, color = 'b')\n#     plt.plot(inverse_cdf, color = 'r')\n#     plt.ylim([0,0.15])\n    #plt.show()\n    \n    return img_new\n\ndef image_agcwd_truncated(img, a=0.75):\n    h,w = img.shape[:2]\n    hist,bins = np.histogram(img.flatten(),256,[0,256])\n    cdf = hist.cumsum()\n    cdf_normalized = cdf / cdf.max()\n    prob_normalized = hist / hist.sum()\n\n    unique_intensity = np.unique(img)\n    intensity_max = unique_intensity.max()\n    intensity_min = unique_intensity.min()\n    prob_min = prob_normalized.min()\n    prob_max = prob_normalized.max()\n    \n    pn_temp = (prob_normalized - prob_min) / (prob_max - prob_min)\n    pn_temp[pn_temp>0] = prob_max * (pn_temp[pn_temp>0]**a)\n    pn_temp[pn_temp<0] = prob_max * (-((-pn_temp[pn_temp<0])**a))\n    prob_normalized_wd = pn_temp / pn_temp.sum() # normalize to [0,1]\n    cdf_prob_normalized_wd = prob_normalized_wd.cumsum()\n    inverse_cdf = np.maximum(0.5,1 - cdf_prob_normalized_wd)\n    \n    img_new = img.copy()\n    for i in unique_intensity:\n        img_new[img==i] = np.round(255 * (i / 255)**inverse_cdf[i])\n   \n#     print (\"%f %f\"%(prob_min, prob_max))\n#     print (cdf_prob_normalized_wd.min(),cdf_prob_normalized_wd.max())\n#     print(hist.sum(),h*w)\n    #plt.plot(prob_normalized_wd, color = 'b')\n#     plt.plot(inverse_cdf, color = 'r')\n    #plt.ylim([0,0.2])\n    #plt.show()\n    \n    return img_new\n\n\ndef process_bright(img):\n    img_negative = 255 - img\n#     plt.imshow(img_negative, cmap='gray')\n#     plt.title('Negative Image')\n#     plt.show()\n    \n    agcwd = image_agcwd(img_negative)\n    reversed = 255 - agcwd\n    return reversed\n\ndef process_dimmed(img):\n    agcwd = image_agcwd_truncated(img)\n    return agcwd\n\n\ndef adjust_brightness(image):\n    rgb = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)\n    YCrCb = cv2.cvtColor(image, cv2.COLOR_BGR2YCrCb)\n    Y = YCrCb[:,:,0]\n\n    # Determine whether image is bright or dimmed\n    threshold = 0.3\n    T_t = 112 # Global average brightness \n    M,N = image.shape[:2]\n    m_I = np.sum(Y/(M*N)) \n    t = (m_I - T_t)/ T_t\n\n    img_output = None\n    if t < -threshold:\n        #print (\"Dimmed Image\")\n        result = process_dimmed(Y)\n        YCrCb[:,:,0] = result\n        img_output = cv2.cvtColor(YCrCb,cv2.COLOR_YCrCb2RGB)\n    elif t > threshold:\n        #print (\"Bright Image\")\n        result = process_bright(Y)\n        YCrCb[:,:,0] = result\n        img_output = cv2.cvtColor(YCrCb,cv2.COLOR_YCrCb2RGB)\n    return img_output\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-07-24T08:42:08.635497Z","iopub.execute_input":"2023-07-24T08:42:08.635881Z","iopub.status.idle":"2023-07-24T08:42:08.654975Z","shell.execute_reply.started":"2023-07-24T08:42:08.635852Z","shell.execute_reply":"2023-07-24T08:42:08.653713Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Select images and split into training, validation and test directory\n","metadata":{}},{"cell_type":"code","source":"labels = ['label0', 'label1', 'label2', 'label3', 'label4']\n\nimg_dir = '/kaggle/input/diabeticretinopathycropped/diabetic retinopathy/diabetic retinopathy cropped'\nlabel_csv = '/kaggle/input/diabeticretinopathycropped/diabetic retinopathy/trainLabels.csv'\n\ntrain_dir = 'train'\nvalid_dir = 'tmp_valid'\ntest_dir = 'tmp_test'\n\n# clear and create new directory\nif os.path.isdir(train_dir):\n    shutil.rmtree(train_dir)\nif os.path.isdir(valid_dir):\n    shutil.rmtree(valid_dir)\nif os.path.isdir(test_dir):\n    shutil.rmtree(test_dir)\n    \nos.makedirs(train_dir)\nos.makedirs(valid_dir)\nos.makedirs(test_dir)\n\nfor label in labels:\n    sub_dir = os.path.join(train_dir, label)\n    if not os.path.exists(sub_dir):\n        os.makedirs(sub_dir)\n    sub_dir = os.path.join(valid_dir, label)\n    if not os.path.exists(sub_dir):\n        os.makedirs(sub_dir)\n    sub_dir = os.path.join(test_dir, label)\n    if not os.path.exists(sub_dir):\n        os.makedirs(sub_dir)\n\n# open csv file and read to dict img - label\nimg_labels = {}\nwith open(label_csv, 'r') as f:\n    reader = csv.reader(f)\n    next(reader) # skip header row\n    for row in reader:\n        img_name = row[0] + '.jpeg'\n        label = int(row[1])\n        img_labels[img_name] = label\n\n# randomly select one fifth of the images and write their rows to a new CSV file\nimg_number = int(len(list(img_labels.keys()))/2)################# change to /3, /2 or /1 for bigger dataset \n\nselected_imgs = random.sample(list(img_labels.keys()), img_number)\nrandom.shuffle(selected_imgs)\n# split the selected imgs to train, test and validation\ntrain_ratio = 0.7 \nvalid_ratio = 0.2 \ntest_ratio = 0.1\n\ntrain_split = int(len(selected_imgs) * train_ratio)\nvalid_split = int(len(selected_imgs) * valid_ratio)\n\n# Split the images into train and test sets\ntrain_imgs = selected_imgs[:train_split]\nvalid_imgs = selected_imgs[train_split:train_split+valid_split]\ntest_imgs = selected_imgs[train_split+valid_split:]\n\nfor img_name in train_imgs:\n    label = img_labels[img_name]\n    src_path = os.path.join(img_dir, img_name)\n    dst_path = os.path.join(train_dir, labels[label], img_name)\n    shutil.copy(src_path, dst_path)\nfor img_name in valid_imgs:\n    label = img_labels[img_name]\n    src_path = os.path.join(img_dir, img_name)\n    dst_path = os.path.join(valid_dir, labels[label], img_name)\n    shutil.copy(src_path, dst_path)\nfor img_name in test_imgs:\n    label = img_labels[img_name]\n    src_path = os.path.join(img_dir, img_name)\n    dst_path = os.path.join(test_dir, labels[label], img_name)\n    shutil.copy(src_path, dst_path)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:42:14.306793Z","iopub.execute_input":"2023-07-24T08:42:14.307164Z","iopub.status.idle":"2023-07-24T08:44:23.775649Z","shell.execute_reply.started":"2023-07-24T08:42:14.307132Z","shell.execute_reply":"2023-07-24T08:44:23.774470Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport matplotlib.pyplot as plt\ndir = train_dir\nimages = []\nnum = 4\n\nfor label in labels:\n    img_dir = os.path.join(dir, label)\n    image_paths = os.listdir(img_dir)\n    image_paths = list(map(lambda img: os.path.join(img_dir, img), image_paths))\n    images.extend(random.sample(image_paths, num))\nplt.figure(figsize=(20, 20))\nimage = cv2.imread(images[0])\nprint(images[0])\nfor i in range(5 * num):\n    image = plt.imread(images[i])\n    image = preprocess_image(image)\n    ax = plt.subplot(5, num, i + 1)\n    plt.imshow(image)\n    plt.title(os.path.basename(images[i]))\n    plt.axis(\"off\")\n'''\nimg_dir = os.path.join(dir, labels[2])\nimage_paths = os.listdir(img_dir)\nimages = random.sample(list(map(lambda img: os.path.join(img_dir, img), image_paths)), 2)\nplt.figure(figsize=(20, 20))\nfor i in range(2):\n    image = plt.imread(images[i])\n    image = preprocess_image(image)\n    ax = plt.subplot(1, num, i + 1)\n    height, width, channel = image.shape\n    plt.imshow(image)\n    plt.title(os.path.basename(images[i]) + ' ' + str(height) + '*' + str(width))\n    plt.axis(\"off\")\n'''","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:44:23.777930Z","iopub.execute_input":"2023-07-24T08:44:23.778934Z","iopub.status.idle":"2023-07-24T08:44:27.847429Z","shell.execute_reply.started":"2023-07-24T08:44:23.778896Z","shell.execute_reply":"2023-07-24T08:44:27.846580Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\ni = random.randint(0, 10)\n# Reading an image in default mode\nimage = cv2.imread(images[0])\nimage = crop_image_from_gray(image)\nB, G, R = cv2.split(image)\nclahe = cv2.createCLAHE(clipLimit=4, tileGridSize=(8,8))\nG_enhanced = clahe.apply(G)\nG_wiener = wiener(G, 2, 0.01)\nG_wiener = clahe.apply(np.uint8(G_wiener))\n# Display the individual channels using plt.imshow()\nplt.figure(figsize=(20, 20))\nax = plt.subplot(3, 2, 1)\nplt.imshow(G_enhanced, cmap='gray')\nplt.title('G_enhanced Channel')\nax = plt.subplot(3, 2, 2)\nplt.hist(G_enhanced.flatten(),256,[0,256],color='r')\n\nax = plt.subplot(3, 2, 3)\nplt.imshow(G_wiener, cmap='gray')\nplt.title('G_enhanced wiener Channel')\nax = plt.subplot(3, 2, 4)\nplt.hist(G_wiener.flatten(),256,[0,256],color='r')\n\nax = plt.subplot(3, 2, 5)\nplt.imshow(G, cmap='gray')\nplt.title('Green Channel')\nax = plt.subplot(3, 2, 6)\nplt.hist(G.flatten(),256,[0,256],color='r')","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:44:27.848872Z","iopub.execute_input":"2023-07-24T08:44:27.849580Z","iopub.status.idle":"2023-07-24T08:45:14.382997Z","shell.execute_reply.started":"2023-07-24T08:44:27.849545Z","shell.execute_reply":"2023-07-24T08:45:14.381952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Apply preprocessing and augmentation on the dataset\n","metadata":{}},{"cell_type":"code","source":"# apply augmentation and CLAHE on training set -> move to augmentation set\n\n\n# Specify the paths to the train folder and the augmented output folder\ntrain_dir = 'train'\naug_dir = 'aug'\n\nif os.path.isdir(aug_dir):\n    shutil.rmtree(aug_dir)\n\nos.makedirs(aug_dir)\n\nfor label in labels:\n    os.makedirs(os.path.join(aug_dir, label))\n    \n# create data frame\ntrain_paths = []\nlabel_image = []\nfor label in labels:\n    for image_path in [os.path.join(train_dir, label, image) for image in os.listdir(os.path.join(train_dir, label))]:\n        train_paths.append(image_path)\n        label_image.append(label)\n        \nFseries=pd.Series(train_paths, name='filepaths')\nLseries=pd.Series(label_image, name='labels')\ntrain_df = pd.concat([Fseries, Lseries], axis = 1)\nprint(train_df.head())\nprint('Total number of images before undersampling: {num}'.format(num = len(train_df)))\nprint(train_df['labels'].value_counts())\n\n# undersampling by dividing to the average of 5 images\nmax_value = 0\nfor value in train_df['labels'].value_counts():\n    max_value += value\nmax_value = int(max_value/5)\n\n# limit the number of image to max_value\nsample_list = []\ngroups=train_df.groupby('labels')\nfor label in train_df['labels'].unique():                 \n    group=groups.get_group(label)\n    sample_count=len(group)    \n    if sample_count > max_value:\n        samples=group.sample(max_value, replace=False, weights=None, random_state=123, axis=0).reset_index(drop=True)\n    else:\n        samples=group.sample(frac=1.0, replace=False, random_state=123, axis=0).reset_index(drop=True)\n    sample_list.append(samples)\ntrain_df=pd.concat(sample_list, axis=0).reset_index(drop=True)\nprint('Total number of images after undersampling: {num}'.format(num = len(train_df)))\nprint(train_df['labels'].value_counts())    \n\n# create aug images to balance after undersampling\ntarget = max_value\ngen = ImageDataGenerator(horizontal_flip=True, vertical_flip=True, rotation_range=20, preprocessing_function=preprocess_image)\ngroups = train_df.groupby('labels') # group by class\n\nfor label in train_df['labels'].unique():  # for every class               \n    group = groups.get_group(label)  # a dataframe holding only rows with the specified label \n    sample_count = len(group)   # determine how many samples there are in this class  \n    if sample_count < target: # if the class has less than target number of images\n        aug_img_count = 0\n        delta = target - sample_count  # number of augmented images to create\n        target_dir = os.path.join(aug_dir, label)  # define where to write the images    \n        aug_gen = gen.flow_from_dataframe(group,  x_col='filepaths', y_col=None, target_size=(224, 224), class_mode=None, batch_size=1,\n                                         shuffle=False, save_to_dir=target_dir, save_prefix='aug',save_format='jpeg')\n        while aug_img_count<delta:\n            images=next(aug_gen)   \n            aug_img_count += len(images)\n            \n# copy image (with CLAHE only)\ngen = ImageDataGenerator(preprocessing_function=preprocess_image)\nfor label in train_df['labels'].unique():\n    group = groups.get_group(label)\n    target_dir=os.path.join(aug_dir, label)\n    aug_gen=gen.flow_from_dataframe(group,  x_col='filepaths', y_col=None, target_size=(224, 224), class_mode=None, batch_size=1,\n                                    shuffle=False, save_to_dir=target_dir, save_prefix='aug',save_format='jpeg')\n    num_images = len(group)\n    for _ in range(num_images):\n        images = next(aug_gen)\n\nprint('Number of images in each label after augmentation: ')\nfor label in labels:\n    path = os.path.join(aug_dir, label)\n    print(label + ': {}'.format(len(os.listdir(path))) + ' images')","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:45:14.401870Z","iopub.execute_input":"2023-07-24T08:45:14.402428Z","iopub.status.idle":"2023-07-24T08:51:45.764152Z","shell.execute_reply.started":"2023-07-24T08:45:14.402393Z","shell.execute_reply":"2023-07-24T08:51:45.763200Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# apply CLAHE on validation and test dataset\ngen = ImageDataGenerator(preprocessing_function=preprocess_image)\n\nnew_val_dir = 'valid'\nnew_test_dir = 'test'\n\nif os.path.isdir(new_val_dir):\n    shutil.rmtree(new_val_dir)\nif os.path.isdir(new_test_dir):\n    shutil.rmtree(new_test_dir)\nos.makedirs(new_val_dir)\nos.makedirs(new_test_dir)\n\nfor label in labels:\n    os.makedirs(os.path.join(new_val_dir, label))\n    os.makedirs(os.path.join(new_test_dir, label))\n\n# create df from folder to apply aug + clahe\nvalid_paths = []\nlabel_image = []\nfor label in labels:\n    for image_path in [os.path.join(valid_dir, label, image) for image in os.listdir(os.path.join(valid_dir, label))]:\n        valid_paths.append(image_path)\n        label_image.append(label)\n        \nFseries=pd.Series(valid_paths, name='filepaths')\nLseries=pd.Series(label_image, name='labels')\nvalid_df = pd.concat([Fseries, Lseries], axis = 1)\n\ntest_paths = []\nlabel_image = []\nfor label in labels:\n    for image_path in [os.path.join(test_dir, label, image) for image in os.listdir(os.path.join(test_dir, label))]:\n        test_paths.append(image_path)\n        label_image.append(label)\n        \nFseries=pd.Series(test_paths, name='filepaths')\nLseries=pd.Series(label_image, name='labels')\ntest_df = pd.concat([Fseries, Lseries], axis = 1)\n\n\ngroups = valid_df.groupby('labels')\nfor label in valid_df['labels'].unique():\n    group = groups.get_group(label)\n    target_dir=os.path.join(new_val_dir, label)\n    aug_gen=gen.flow_from_dataframe(group,  x_col='filepaths', y_col=None, target_size=(224, 224), class_mode=None, batch_size=1,\n                                    shuffle=False, save_to_dir=target_dir, save_prefix='aug',save_format='jpeg')\n    num_images = len(group)\n    print(len(group))\n    for _ in range(num_images):\n        images = next(aug_gen)\n\ngroups = test_df.groupby('labels')\nfor label in test_df['labels'].unique():\n    group = groups.get_group(label)\n    target_dir=os.path.join(new_test_dir, label)\n    aug_gen=gen.flow_from_dataframe(group,  x_col='filepaths', y_col=None, target_size=(224, 224), class_mode=None, batch_size=1,\n                                    shuffle=False, save_to_dir=target_dir, save_prefix='aug',save_format='jpeg')\n    num_images = len(group)\n    for _ in range(num_images):\n        images = next(aug_gen)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-07-24T08:54:01.006129Z","iopub.execute_input":"2023-07-24T08:54:01.006500Z","iopub.status.idle":"2023-07-24T08:56:18.151093Z","shell.execute_reply.started":"2023-07-24T08:54:01.006464Z","shell.execute_reply":"2023-07-24T08:56:18.150098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport PIL\nimport PIL.Image\nimport tensorflow as tf\nimport pathlib\naug_dir = pathlib.Path('aug').with_suffix('')\ntrain_dir = pathlib.Path('train').with_suffix('')\nnew_test_dir = pathlib.Path('test').with_suffix('')\nnew_val_dir = pathlib.Path('valid').with_suffix('')\n\nbatch_size = 32 ################\nimg_height = 224 ################\nimg_width = 224 ################\nnum_classes = 5\n\ntrain_ds = tf.keras.utils.image_dataset_from_directory(\n  aug_dir,\n  shuffle=True,\n  image_size=(img_height, img_width),\n  batch_size=batch_size)\n\n\nvalidation_ds = tf.keras.utils.image_dataset_from_directory(\n  new_val_dir,\n  shuffle=False,\n  image_size=(img_height, img_width),\n  batch_size=batch_size)\n\ntest_ds = tf.keras.utils.image_dataset_from_directory(\n    new_test_dir,\n    shuffle=False,\n    image_size=(img_height, img_width),\n    batch_size=batch_size)\n","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:56:18.152618Z","iopub.execute_input":"2023-07-24T08:56:18.152969Z","iopub.status.idle":"2023-07-24T08:56:19.580466Z","shell.execute_reply.started":"2023-07-24T08:56:18.152935Z","shell.execute_reply":"2023-07-24T08:56:19.579560Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# improve performance\nAUTOTUNE = tf.data.AUTOTUNE\n\ntrain_ds = train_ds.prefetch(buffer_size=AUTOTUNE)\nvalidation_ds = validation_ds.prefetch(buffer_size=AUTOTUNE)\ntest_ds = test_ds.prefetch(buffer_size=AUTOTUNE)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:56:19.581789Z","iopub.execute_input":"2023-07-24T08:56:19.582118Z","iopub.status.idle":"2023-07-24T08:56:19.588583Z","shell.execute_reply.started":"2023-07-24T08:56:19.582086Z","shell.execute_reply":"2023-07-24T08:56:19.587692Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"# Convolutional Block Attention Module (CBAM)","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.layers import GlobalAveragePooling2D, GlobalMaxPooling2D, Reshape, Dense, Input\nfrom tensorflow.keras.layers import Activation, Concatenate, Conv2D, Multiply\n\n\ndef channel_attention_module(x, ratio=8):\n    batch, _, _, channel = x.shape\n\n    ## Shared layers\n    l1 = Dense(channel//ratio, activation=\"relu\", use_bias=False)\n    l2 = Dense(channel, use_bias=False)\n\n    ## Global Average Pooling\n    x1 = GlobalAveragePooling2D()(x)\n    x1 = l1(x1)\n    x1 = l2(x1)\n\n    ## Global Max Pooling\n    x2 = GlobalMaxPooling2D()(x)\n    x2 = l1(x2)\n    x2 = l2(x2)\n\n    ## Add both the features and pass through sigmoid\n    feats = x1 + x2\n    feats = Activation(\"sigmoid\")(feats)\n    feats = Multiply()([x, feats])\n\n    return feats\n\ndef spatial_attention_module(x):\n    ## Average Pooling\n    x1 = tf.reduce_mean(x, axis=-1)\n    x1 = tf.expand_dims(x1, axis=-1)\n\n    ## Max Pooling\n    x2 = tf.reduce_max(x, axis=-1)\n    x2 = tf.expand_dims(x2, axis=-1)\n\n    ## Concatenat both the features\n    feats = Concatenate()([x1, x2])\n    ## Conv layer\n    feats = Conv2D(1, kernel_size=7, padding=\"same\", activation=\"sigmoid\")(feats)\n    feats = Multiply()([x, feats])\n\n    return feats\n\ndef cbam(x):\n    x = channel_attention_module(x)\n    x = spatial_attention_module(x)\n    return x\n\nif __name__ == \"__main__\":\n    inputs = Input(shape=(128, 128, 32))\n    y = cbam(inputs)\n    print(y.shape)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:56:19.589791Z","iopub.execute_input":"2023-07-24T08:56:19.590501Z","iopub.status.idle":"2023-07-24T08:56:19.670975Z","shell.execute_reply.started":"2023-07-24T08:56:19.590468Z","shell.execute_reply":"2023-07-24T08:56:19.670018Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# transfer learning\nimg_shape = (img_height, img_width, 3,)\n#preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input\n#base_model = tf.keras.applications.MobileNetV2(input_shape=img_shape,\n                                               #include_top=False,\n                                               #weights='imagenet')\nbase_model = tf.keras.applications.EfficientNetB0(include_top=False, weights='imagenet', input_shape = img_shape, pooling = max)###############\nbase_model.trainable = False\nglobal_max_layer = tf.keras.layers.GlobalMaxPooling2D()\nprediction_layer = tf.keras.models.Sequential()\nprediction_layer.add(tf.keras.layers.Dense(1280, activation='relu'))\nprediction_layer.add(tf.keras.layers.Dense(5, activation='softmax'))\n\n#prediction_layer = tf.keras.layers.Dense(num_classes, activation='softmax')\n\n# build\ninputs = tf.keras.Input(shape=img_shape)\nx = base_model(inputs, training=False)\nx = cbam(x)\nx = global_max_layer(x)\nx = tf.keras.layers.Dropout(0.5)(x)\n\noutputs = prediction_layer(x)\n#outputs = tf.keras.layers.Dense(5, activation='softmax')(x)\nmodel = tf.keras.Model(inputs, outputs)\n# compile\n\nbase_learning_rate = 0.0001 ###################\nmodel.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=base_learning_rate), loss = 'sparse_categorical_crossentropy', metrics=['accuracy'])\n\n","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:56:19.674341Z","iopub.execute_input":"2023-07-24T08:56:19.674684Z","iopub.status.idle":"2023-07-24T08:56:22.535554Z","shell.execute_reply.started":"2023-07-24T08:56:19.674660Z","shell.execute_reply":"2023-07-24T08:56:22.534576Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:56:22.537062Z","iopub.execute_input":"2023-07-24T08:56:22.537425Z","iopub.status.idle":"2023-07-24T08:56:22.611597Z","shell.execute_reply.started":"2023-07-24T08:56:22.537391Z","shell.execute_reply":"2023-07-24T08:56:22.610875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.callbacks import EarlyStopping\n\n# Define the EarlyStopping callback\nearly_stopping = EarlyStopping(monitor='val_loss', patience=5, mode='min', verbose=1)\n\ninitial_epochs = 20\nhistory = model.fit(train_ds,\n                    epochs=initial_epochs,\n                    validation_data=validation_ds, callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:56:22.612591Z","iopub.execute_input":"2023-07-24T08:56:22.613004Z","iopub.status.idle":"2023-07-24T09:02:07.311724Z","shell.execute_reply.started":"2023-07-24T08:56:22.612979Z","shell.execute_reply":"2023-07-24T09:02:07.310782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Evaluate the model on the test dataset\nloss, accuracy = model.evaluate(test_ds)\n\n# Print the evaluation results\nprint('Test Loss:', loss)\nprint('Test Accuracy:', accuracy)","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:07:46.372900Z","iopub.execute_input":"2023-07-24T09:07:46.373280Z","iopub.status.idle":"2023-07-24T09:07:49.419622Z","shell.execute_reply.started":"2023-07-24T09:07:46.373249Z","shell.execute_reply":"2023-07-24T09:07:49.418573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_model.trainable = True\nmodel.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=base_learning_rate/5), loss = 'sparse_categorical_crossentropy', metrics=['accuracy'])\n\n\n# Fine-tune from this layer onwards\nfine_tune_at = 50\n\n# Freeze all the layers before the `fine_tune_at` layer\nfor layer in base_model.layers[:fine_tune_at]:\n    layer.trainable = False\n\nfine_tune_epochs = 20\ntotal_epochs =  initial_epochs + fine_tune_epochs\n\nhistory_fine = model.fit(train_ds,\n                         epochs=total_epochs,\n                         initial_epoch=history.epoch[-1],\n                         validation_data=validation_ds, callbacks=[early_stopping])\n","metadata":{"execution":{"iopub.status.busy":"2023-07-24T09:08:21.176180Z","iopub.execute_input":"2023-07-24T09:08:21.176755Z","iopub.status.idle":"2023-07-24T09:16:52.209284Z","shell.execute_reply.started":"2023-07-24T09:08:21.176722Z","shell.execute_reply":"2023-07-24T09:16:52.208365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Confusion matrix, f1-score","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import f1_score, precision_score, recall_score, confusion_matrix, classification_report\n\n# Evaluate the model on the test dataset\nloss, accuracy = model.evaluate(test_ds)\n\n# Print the evaluation results\nprint('Test Loss:', loss)\nprint('Test Accuracy:', accuracy)\n\ny_pred = model.predict(test_ds)\ny_pred = np.argmax(y_pred, axis=1)\ny_test = tf.concat([y for x, y in test_ds], axis=0).numpy()\nprint(y_test)\nprint(y_pred)\n# Print f1, precision, and recall scores\nprint('overall precision, recall and f1:')\nprint(precision_score(y_test, y_pred , average=\"macro\"))\nprint(recall_score(y_test, y_pred , average=\"macro\"))\nprint(f1_score(y_test, y_pred , average=\"macro\"))\nprint('report f1 on each class: ')\nprint(classification_report(y_test, y_pred))\n","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:40:52.219736Z","iopub.status.idle":"2023-07-24T08:40:52.220249Z","shell.execute_reply.started":"2023-07-24T08:40:52.219984Z","shell.execute_reply":"2023-07-24T08:40:52.220010Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Accuracy, Loss Graph\n","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nacc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nplt.figure(figsize=(8, 8))\nplt.subplot(2, 1, 1)\nplt.plot(acc, label='Training Accuracy')\nplt.plot(val_acc, label='Validation Accuracy')\nplt.legend(loc='lower right')\nplt.ylabel('Accuracy')\nplt.ylim([min(plt.ylim()),1])\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(2, 1, 2)\nplt.plot(loss, label='Training Loss')\nplt.plot(val_loss, label='Validation Loss')\nplt.legend(loc='upper right')\nplt.ylabel('Cross Entropy')\nplt.ylim([0,4])\nplt.title('Training and Validation Loss')\nplt.xlabel('epoch')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-24T08:40:52.221950Z","iopub.status.idle":"2023-07-24T08:40:52.222438Z","shell.execute_reply.started":"2023-07-24T08:40:52.222203Z","shell.execute_reply":"2023-07-24T08:40:52.222226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Other dataset (apply preprocessing + move to test ds)","metadata":{}},{"cell_type":"code","source":"#aptos2019 dataset\ndir = '/kaggle/input/aptos2019-blindness-detection/train_images'\nout_dir = '/kaggle/working/test'\n\nif os.path.isdir(out_dir):\n    shutil.rmtree(out_dir)\nos.makedirs(out_dir)\n\nfor label in labels:\n    sub_dir = os.path.join(out_dir, label)\n    if not os.path.exists(sub_dir):\n        os.makedirs(sub_dir)\n        \ncsv_file = '/kaggle/input/aptos2019-blindness-detection/train.csv' # Change this to the path of your CSV file\n'''\ndata = {}\nwith open(label_csv, 'r') as csv_file:\n    reader = csv.reader(csv_file)\n    next(reader) # Skip the header row\n    for row in reader:\n        filename = row[0] + '.png'\n        label = int(row[1])\n        data[filename] = label\nimg_names = list(data.keys())\nfor img_name in img_names:\n    label = data[img_name]\n    src_path = os.path.join(dir, img_name)\n    dst_path = os.path.join(out_dir, labels[label], img_name)\n    shutil.copy(src_path, dst_path)\n'''\ndf = pd.read_csv(csv_file, usecols=[0,1])\ndf.columns = ['filepaths', 'labels']\ndf['filepaths'] = dir + '/' + df['filepaths'] + '.png'\nprint(df.head(10))\nprint(len(df))\ngen = ImageDataGenerator(preprocessing_function=preprocess_image)\ngroups = df.groupby('labels')\nfor label in df['labels'].unique():\n    group = groups.get_group(label)\n    target_dir=os.path.join(out_dir, labels[int(label)])\n    aug_gen=gen.flow_from_dataframe(group,  x_col='filepaths', y_col=None, target_size=(224, 224), class_mode=None, batch_size=1,\n                                    shuffle=False, save_to_dir=target_dir)\n    num_images = len(group)\n    for _ in range(num_images):\n        images = next(aug_gen)\n\n# -------------------------------------\ntest_ds = tf.keras.utils.image_dataset_from_directory(\n    out_dir,\n    shuffle=False,\n    image_size=(img_height, img_width),\n    batch_size=batch_size)\n\n# Evaluate the model on the test dataset\nloss, accuracy = model.evaluate(test_ds)\n\n# Print the evaluation results\nprint('Test Loss:', loss)\nprint('Test Accuracy:', accuracy)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#messidor dataset\ndir = '/kaggle/input/messifor2/messidor2/IMAGES'\ncsv_file = '/kaggle/input/messidor2-dr-grades/messidor_data.csv'\nout_dir = '/kaggle/working/test'\n\nif os.path.isdir(out_dir):\n    shutil.rmtree(out_dir)\nos.makedirs(out_dir)\n\nfor label in labels:\n    sub_dir = os.path.join(out_dir, label)\n    if not os.path.exists(sub_dir):\n        os.makedirs(sub_dir)\n\nprint(df['labels'].unique())\ndf = pd.read_csv(csv_file, usecols=[0,1])\ndf.columns = ['filepaths', 'labels']\ndf['filepaths'] = dir + '/' + df['filepaths']\nprint(df.head(10))\nprint(len(df))\ngen = ImageDataGenerator(preprocessing_function=preprocess_image)\ngroups = df.groupby('labels')\nfor label in df['labels'].unique()[:-1]:\n    group = groups.get_group(label)\n    target_dir=os.path.join(out_dir, labels[int(label)])\n    aug_gen=gen.flow_from_dataframe(group,  x_col='filepaths', y_col=None, target_size=(224, 224), class_mode=None, batch_size=1,\n                                    shuffle=False, save_to_dir=target_dir)\n    num_images = len(group)\n    for _ in range(num_images):\n        images = next(aug_gen)\n# -------------------------------------\ntest_ds = tf.keras.utils.image_dataset_from_directory(\n    out_dir,\n    shuffle=False,\n    image_size=(img_height, img_width),\n    batch_size=batch_size)\n\n# Evaluate the model on the test dataset\nloss, accuracy = model.evaluate(test_ds)\n\n# Print the evaluation results\nprint('Test Loss:', loss)\nprint('Test Accuracy:', accuracy)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# idrid dataset -> apply preprocess and move to test dir\nimport os\nimport pandas as pd\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\ntrain_dir = '/kaggle/input/idrid-dataset/a. Training Set'\ntest_dir = '/kaggle/input/idrid-dataset/b. Testing Set'\ntrain_csv = '/kaggle/input/idrid-dataset/training.csv'\ntest_csv = '/kaggle/input/idrid-dataset/testing.csv'\nout_dir = '/kaggle/working/test'\n\nif os.path.isdir(out_dir):\n    shutil.rmtree(out_dir)\nos.makedirs(out_dir)\n\nfor label in labels:\n    sub_dir = os.path.join(out_dir, label)\n    if not os.path.exists(sub_dir):\n        os.makedirs(sub_dir)\n# Read CSV files\ntrain_df = pd.read_csv(train_csv, usecols=[0,1])\ntrain_df.columns = ['filepaths', 'labels']\ntrain_df['filepaths'] = train_dir + '/' + train_df['filepaths'] + '.jpg'\n\ntest_df = pd.read_csv(test_csv, usecols=[0,1])\ntest_df.columns = ['filepaths', 'labels']\ntest_df['filepaths'] = test_dir + '/' + test_df['filepaths'] + '.jpg'\n\ndf = pd.concat([train_df, test_df])\nprint(df.head(10))\ngen = ImageDataGenerator(preprocessing_function=preprocess_image)\ngroups = df.groupby('labels')\nfor label in df['labels'].unique():\n    group = groups.get_group(label)\n    target_dir=os.path.join(out_dir, labels[label])\n    aug_gen=gen.flow_from_dataframe(group,  x_col='filepaths', y_col=None, target_size=(224, 224), class_mode=None, batch_size=1,\n                                    shuffle=False, save_to_dir=target_dir,save_format='jpg')\n    num_images = len(group)\n    for _ in range(num_images):\n        images = next(aug_gen)\n\n# -------------------------------------\ntest_ds = tf.keras.utils.image_dataset_from_directory(\n    out_dir,\n    shuffle=False,\n    image_size=(img_height, img_width),\n    batch_size=batch_size)\n# Evaluate the model on the test dataset\nloss, accuracy = model.evaluate(test_ds)\n\n# Print the evaluation results\nprint('Test Loss:', loss)\nprint('Test Accuracy:', accuracy)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n","metadata":{},"execution_count":null,"outputs":[]}]}