{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.6"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":14774,"databundleVersionId":875431,"sourceType":"competition"},{"sourceId":187731,"sourceType":"datasetVersion","datasetId":80814},{"sourceId":418031,"sourceType":"datasetVersion","datasetId":131128},{"sourceId":11428818,"sourceType":"datasetVersion","datasetId":7158059}],"dockerImageVersionId":28450,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# To have reproducible results and compare them\nnr_seed = 2019\nimport numpy as np \nnp.random.seed(nr_seed)\nimport tensorflow as tf\ntf.set_random_seed(nr_seed)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:35.464694Z","iopub.execute_input":"2025-04-16T13:09:35.464996Z","iopub.status.idle":"2025-04-16T13:09:36.673941Z","shell.execute_reply.started":"2025-04-16T13:09:35.464946Z","shell.execute_reply":"2025-04-16T13:09:36.673347Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import libraries\nimport json\nimport math\nfrom tqdm import tqdm, tqdm_notebook\nimport gc\nimport warnings\nimport os\n\nimport cv2\nfrom PIL import Image\n\nimport pandas as pd\nimport scipy\nimport matplotlib.pyplot as plt\n\nfrom keras import backend as K\nfrom keras import layers\nfrom keras.applications.densenet import DenseNet121\nfrom keras.callbacks import Callback, ModelCheckpoint\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential\nfrom keras.optimizers import Adam\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import cohen_kappa_score, accuracy_score\n\nwarnings.filterwarnings(\"ignore\")\n\n%matplotlib inline","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:36.675850Z","iopub.execute_input":"2025-04-16T13:09:36.676148Z","iopub.status.idle":"2025-04-16T13:09:37.674329Z","shell.execute_reply.started":"2025-04-16T13:09:36.676094Z","shell.execute_reply":"2025-04-16T13:09:37.673447Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Image size\nim_size = 320\n# Batch size\nBATCH_SIZE = 32","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:37.676196Z","iopub.execute_input":"2025-04-16T13:09:37.676535Z","iopub.status.idle":"2025-04-16T13:09:37.681055Z","shell.execute_reply.started":"2025-04-16T13:09:37.676461Z","shell.execute_reply":"2025-04-16T13:09:37.680043Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Loading & Merging","metadata":{}},{"cell_type":"code","source":"new_train = pd.read_csv('../input/aptos2019-blindness-detection/train.csv')\nold_train = pd.read_csv('../input/diabetic-retinopathy-resized/trainLabels.csv')\nprint(new_train.shape)\nprint(old_train.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:37.682529Z","iopub.execute_input":"2025-04-16T13:09:37.682820Z","iopub.status.idle":"2025-04-16T13:09:37.797403Z","shell.execute_reply.started":"2025-04-16T13:09:37.682768Z","shell.execute_reply":"2025-04-16T13:09:37.795676Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"old_train = old_train[['image','level']]\nold_train.columns = new_train.columns\nold_train.diagnosis.value_counts()\n\n# path columns\nnew_train['id_code'] = '../input/aptos2019-blindness-detection/train_images/' + new_train['id_code'].astype(str) + '.png'\nold_train['id_code'] = '../input/diabetic-retinopathy-resized/resized_train/resized_train/' + old_train['id_code'].astype(str) + '.jpeg'\n\ntrain_df = old_train.copy()\nval_df = new_train.copy()\ntrain_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:37.805147Z","iopub.execute_input":"2025-04-16T13:09:37.805978Z","iopub.status.idle":"2025-04-16T13:09:37.966459Z","shell.execute_reply.started":"2025-04-16T13:09:37.805913Z","shell.execute_reply":"2025-04-16T13:09:37.965644Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Train - Valid split","metadata":{}},{"cell_type":"code","source":"# Not used in version 5\n#train_df, val_df = train_test_split(train_df, shuffle=True, stratify=train_df.diagnosis, test_size=0.1, random_state=2019)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:37.969865Z","iopub.execute_input":"2025-04-16T13:09:37.970096Z","iopub.status.idle":"2025-04-16T13:09:37.973169Z","shell.execute_reply.started":"2025-04-16T13:09:37.970057Z","shell.execute_reply":"2025-04-16T13:09:37.972323Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Let's shuffle the datasets\ntrain_df = train_df.sample(frac=1).reset_index(drop=True)\nval_df = val_df.sample(frac=1).reset_index(drop=True)\nprint(train_df.shape)\nprint(val_df.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:37.974449Z","iopub.execute_input":"2025-04-16T13:09:37.974759Z","iopub.status.idle":"2025-04-16T13:09:37.993606Z","shell.execute_reply.started":"2025-04-16T13:09:37.974707Z","shell.execute_reply":"2025-04-16T13:09:37.992822Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Process Images","metadata":{}},{"cell_type":"markdown","source":"Crop function: https://www.kaggle.com/ratthachat/aptos-updated-preprocessing-ben-s-cropping ","metadata":{}},{"cell_type":"code","source":"def crop_image1(img,tol=7):\n    # img is image data\n    # tol  is tolerance\n        \n    mask = img>tol\n    return img[np.ix_(mask.any(1),mask.any(0))]\n\ndef crop_image_from_gray(img,tol=7):\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            img = np.stack([img1,img2,img3],axis=-1)\n        return img\n\ndef preprocess_image(image_path, desired_size=224):\n    img = cv2.imread(image_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    img = crop_image_from_gray(img)\n    img = cv2.resize(img, (desired_size,desired_size))\n    img = cv2.addWeighted(img,4,cv2.GaussianBlur(img, (0,0), desired_size/30) ,-4 ,128)\n    \n    return img\n\ndef preprocess_image_old(image_path, desired_size=224):\n    img = cv2.imread(image_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    #img = crop_image_from_gray(img)\n    img = cv2.resize(img, (desired_size,desired_size))\n    img = cv2.addWeighted(img,4,cv2.GaussianBlur(img, (0,0), desired_size/40) ,-4 ,128)\n    \n    return img","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:37.995082Z","iopub.execute_input":"2025-04-16T13:09:37.995327Z","iopub.status.idle":"2025-04-16T13:09:38.009430Z","shell.execute_reply.started":"2025-04-16T13:09:37.995277Z","shell.execute_reply":"2025-04-16T13:09:38.008855Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def display_samples(df, columns=4, rows=3):\n    fig=plt.figure(figsize=(5*columns, 4*rows))\n\n    for i in range(columns*rows):\n        image_path = df.loc[i,'id_code']\n        image_id = df.loc[i,'diagnosis']\n        img = cv2.imread(f'{image_path}')\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        #img = crop_image_from_gray(img)\n        img = cv2.resize(img, (im_size,im_size))\n        img = cv2.addWeighted(img,4,cv2.GaussianBlur(img, (0,0), im_size/40) ,-4 ,128)\n        \n        fig.add_subplot(rows, columns, i+1)\n        plt.title(image_id)\n        plt.imshow(img)\n    \n    plt.tight_layout()\n\ndisplay_samples(train_df)","metadata":{"_kg_hide-input":true,"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:38.010791Z","iopub.execute_input":"2025-04-16T13:09:38.011062Z","iopub.status.idle":"2025-04-16T13:09:41.678301Z","shell.execute_reply.started":"2025-04-16T13:09:38.011012Z","shell.execute_reply":"2025-04-16T13:09:41.677082Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Processing Images","metadata":{}},{"cell_type":"markdown","source":"__UPDATE:__ Here we are reading just the validation set. In order to use 320x320 images, we are going to load one bucket at a time only when needed. This will let our code run without memory-related errors.","metadata":{}},{"cell_type":"code","source":"# validation set\nN = val_df.shape[0]\nx_val = np.empty((N, im_size, im_size, 3), dtype=np.uint8)\n\nfor i, image_id in enumerate(tqdm_notebook(val_df['id_code'])):\n    x_val[i, :, :, :] = preprocess_image(\n        f'{image_id}',\n        desired_size = im_size\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:09:41.679674Z","iopub.execute_input":"2025-04-16T13:09:41.679927Z","iopub.status.idle":"2025-04-16T13:21:54.979859Z","shell.execute_reply.started":"2025-04-16T13:09:41.679875Z","shell.execute_reply":"2025-04-16T13:21:54.979140Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_train = pd.get_dummies(train_df['diagnosis']).values\ny_val = pd.get_dummies(val_df['diagnosis']).values\n\nprint(y_train.shape)\nprint(x_val.shape)\nprint(y_val.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:21:54.980951Z","iopub.execute_input":"2025-04-16T13:21:54.981144Z","iopub.status.idle":"2025-04-16T13:21:54.989057Z","shell.execute_reply.started":"2025-04-16T13:21:54.981110Z","shell.execute_reply":"2025-04-16T13:21:54.988296Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Creating multilabels\n\nInstead of predicting a single label, we will change our target to be a multilabel problem; i.e., if the target is a certain class, then it encompasses all the classes before it. E.g. encoding a class 4 retinopathy would usually be `[0, 0, 0, 1]`, but in our case we will predict `[1, 1, 1, 1]`. For more details, please check out [Lex's kernel](https://www.kaggle.com/lextoumbourou/blindness-detection-resnet34-ordinal-targets).","metadata":{}},{"cell_type":"code","source":"y_train_multi = np.empty(y_train.shape, dtype=y_train.dtype)\ny_train_multi[:, 4] = y_train[:, 4]\n\nfor i in range(3, -1, -1):\n    y_train_multi[:, i] = np.logical_or(y_train[:, i], y_train_multi[:, i+1])\n\ny_val_multi = np.empty(y_val.shape, dtype=y_val.dtype)\ny_val_multi[:, 4] = y_val[:, 4]\n\nfor i in range(3, -1, -1):\n    y_val_multi[:, i] = np.logical_or(y_val[:, i], y_val_multi[:, i+1])\n\nprint(\"Y_train multi: {}\".format(y_train_multi.shape))\nprint(\"Y_val multi: {}\".format(y_val_multi.shape))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:21:54.990096Z","iopub.execute_input":"2025-04-16T13:21:54.990286Z","iopub.status.idle":"2025-04-16T13:21:55.002029Z","shell.execute_reply.started":"2025-04-16T13:21:54.990254Z","shell.execute_reply":"2025-04-16T13:21:55.001286Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_train = y_train_multi\ny_val = y_val_multi","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:21:55.003027Z","iopub.execute_input":"2025-04-16T13:21:55.003262Z","iopub.status.idle":"2025-04-16T13:21:55.011352Z","shell.execute_reply.started":"2025-04-16T13:21:55.003214Z","shell.execute_reply":"2025-04-16T13:21:55.010742Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# delete the uneeded df\ndel new_train\ndel old_train\ndel val_df\ngc.collect()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:21:55.012704Z","iopub.execute_input":"2025-04-16T13:21:55.012942Z","iopub.status.idle":"2025-04-16T13:21:55.123028Z","shell.execute_reply.started":"2025-04-16T13:21:55.012893Z","shell.execute_reply":"2025-04-16T13:21:55.122212Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Creating keras callback for QWK\n\n---\n\nI had to change this function, in order to consider the best kappa score among all the buckets.","metadata":{}},{"cell_type":"code","source":"class Metrics(Callback):\n\n    def on_epoch_end(self, epoch, logs={}):\n        X_val, y_val = self.validation_data[:2]\n        y_val = y_val.sum(axis=1) - 1\n        \n        y_pred = self.model.predict(X_val) > 0.5\n        y_pred = y_pred.astype(int).sum(axis=1) - 1\n\n        _val_kappa = cohen_kappa_score(\n            y_val,\n            y_pred, \n            weights='quadratic'\n        )\n\n        self.val_kappas.append(_val_kappa)\n\n        print(f\"val_kappa: {_val_kappa:.4f}\")\n        \n        if _val_kappa == max(self.val_kappas):\n            print(\"Validation Kappa has improved. Saving model.\")\n            self.model.save('model.h5')\n\n        return","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:21:55.124459Z","iopub.execute_input":"2025-04-16T13:21:55.124775Z","iopub.status.idle":"2025-04-16T13:21:55.136394Z","shell.execute_reply.started":"2025-04-16T13:21:55.124721Z","shell.execute_reply":"2025-04-16T13:21:55.135903Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Data Generator","metadata":{}},{"cell_type":"code","source":"def create_datagen():\n    return ImageDataGenerator(\n        featurewise_std_normalization = True,\n        horizontal_flip = True,\n        vertical_flip = True,\n        rotation_range = 360\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:21:55.137763Z","iopub.execute_input":"2025-04-16T13:21:55.138002Z","iopub.status.idle":"2025-04-16T13:21:55.151054Z","shell.execute_reply.started":"2025-04-16T13:21:55.137956Z","shell.execute_reply":"2025-04-16T13:21:55.150213Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model: DenseNet-121","metadata":{}},{"cell_type":"code","source":"densenet = DenseNet121(\n    weights='../input/densenet-keras/DenseNet-BC-121-32-no-top.h5',\n    include_top=False,\n    input_shape=(im_size,im_size,3)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:21:55.152224Z","iopub.execute_input":"2025-04-16T13:21:55.152435Z","iopub.status.idle":"2025-04-16T13:22:17.827987Z","shell.execute_reply.started":"2025-04-16T13:21:55.152399Z","shell.execute_reply":"2025-04-16T13:22:17.827360Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_model():\n    model = Sequential()\n    model.add(densenet)\n    model.add(layers.GlobalAveragePooling2D())\n    model.add(layers.Dropout(0.5))\n    model.add(layers.Dense(5, activation='sigmoid'))\n    \n    model.compile(\n        loss='binary_crossentropy',\n        optimizer=Adam(lr=0.0001,decay=1e-6),\n        metrics=['accuracy']\n    )\n    \n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:22:17.829247Z","iopub.execute_input":"2025-04-16T13:22:17.829460Z","iopub.status.idle":"2025-04-16T13:22:17.839256Z","shell.execute_reply.started":"2025-04-16T13:22:17.829423Z","shell.execute_reply":"2025-04-16T13:22:17.838265Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = build_model()\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:22:17.840451Z","iopub.execute_input":"2025-04-16T13:22:17.840746Z","iopub.status.idle":"2025-04-16T13:22:26.082348Z","shell.execute_reply.started":"2025-04-16T13:22:17.840686Z","shell.execute_reply":"2025-04-16T13:22:26.081498Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Training & Evaluation","metadata":{}},{"cell_type":"code","source":"#train_df = train_df.reset_index(drop=True)\nbucket_num = 8\ndiv = round(train_df.shape[0]/bucket_num)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:22:26.083974Z","iopub.execute_input":"2025-04-16T13:22:26.084226Z","iopub.status.idle":"2025-04-16T13:22:26.088220Z","shell.execute_reply.started":"2025-04-16T13:22:26.084175Z","shell.execute_reply":"2025-04-16T13:22:26.087476Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_init = {\n    'val_loss': [0.0],\n    'val_acc': [0.0],\n    'loss': [0.0], \n    'acc': [0.0],\n    'bucket': [0.0]\n}\nresults = pd.DataFrame(df_init)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:22:26.089640Z","iopub.execute_input":"2025-04-16T13:22:26.089927Z","iopub.status.idle":"2025-04-16T13:22:26.100801Z","shell.execute_reply.started":"2025-04-16T13:22:26.089862Z","shell.execute_reply":"2025-04-16T13:22:26.100074Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# I found that changing the nr. of epochs for each bucket helped in terms of performances\nepochs = [5,5,10,15,15,20,20,30]\nkappa_metrics = Metrics()\nkappa_metrics.val_kappas = []","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:22:26.102054Z","iopub.execute_input":"2025-04-16T13:22:26.102338Z","iopub.status.idle":"2025-04-16T13:22:26.111188Z","shell.execute_reply.started":"2025-04-16T13:22:26.102285Z","shell.execute_reply":"2025-04-16T13:22:26.110595Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i in range(0,bucket_num):\n    if i != (bucket_num-1):\n        print(\"Bucket Nr: {}\".format(i))\n        \n        N = train_df.iloc[i*div:(1+i)*div].shape[0]\n        x_train = np.empty((N, im_size, im_size, 3), dtype=np.uint8)\n        for j, image_id in enumerate(tqdm_notebook(train_df.iloc[i*div:(1+i)*div,0])):\n            x_train[j, :, :, :] = preprocess_image_old(f'{image_id}', desired_size = im_size)\n\n        data_generator = create_datagen().flow(x_train, y_train[i*div:(1+i)*div,:], batch_size=BATCH_SIZE)\n        history = model.fit_generator(\n                        data_generator,\n                        steps_per_epoch=x_train.shape[0] / BATCH_SIZE,\n                        epochs=epochs[i],\n                        validation_data=(x_val, y_val),\n                        callbacks=[kappa_metrics]\n                        )\n        \n        dic = history.history\n        df_model = pd.DataFrame(dic)\n        df_model['bucket'] = i\n    else:\n        print(\"Bucket Nr: {}\".format(i))\n        \n        N = train_df.iloc[i*div:].shape[0]\n        x_train = np.empty((N, im_size, im_size, 3), dtype=np.uint8)\n        for j, image_id in enumerate(tqdm_notebook(train_df.iloc[i*div:,0])):\n            x_train[j, :, :, :] = preprocess_image_old(f'{image_id}', desired_size = im_size)\n        data_generator = create_datagen().flow(x_train, y_train[i*div:,:], batch_size=BATCH_SIZE)\n        \n        history = model.fit_generator(\n                        data_generator,\n                        steps_per_epoch=x_train.shape[0] / BATCH_SIZE,\n                        epochs=epochs[i],\n                        validation_data=(x_val, y_val),\n                        callbacks=[kappa_metrics]\n                        )\n        \n        dic = history.history\n        df_model = pd.DataFrame(dic)\n        df_model['bucket'] = i\n\n    results = results.append(df_model)\n    \n    del data_generator\n    del x_train\n    gc.collect()\n    \n    print('-'*40)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T13:22:26.112406Z","iopub.execute_input":"2025-04-16T13:22:26.112705Z","iopub.status.idle":"2025-04-16T20:04:35.890006Z","shell.execute_reply.started":"2025-04-16T13:22:26.112651Z","shell.execute_reply":"2025-04-16T20:04:35.889182Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results = results.iloc[1:]\nresults['kappa'] = kappa_metrics.val_kappas\nresults = results.reset_index()\nresults = results.rename(index=str, columns={\"index\": \"epoch\"})\nresults","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:04:35.891686Z","iopub.execute_input":"2025-04-16T20:04:35.892089Z","iopub.status.idle":"2025-04-16T20:04:36.374786Z","shell.execute_reply.started":"2025-04-16T20:04:35.891955Z","shell.execute_reply":"2025-04-16T20:04:36.374014Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results[['loss', 'val_loss']].plot()\nresults[['acc', 'val_acc']].plot()\nresults[['kappa']].plot()\nresults.to_csv('model_results.csv',index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:04:36.375925Z","iopub.execute_input":"2025-04-16T20:04:36.376160Z","iopub.status.idle":"2025-04-16T20:04:36.856327Z","shell.execute_reply.started":"2025-04-16T20:04:36.376112Z","shell.execute_reply":"2025-04-16T20:04:36.855472Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Find best threshold","metadata":{}},{"cell_type":"code","source":"model.load_weights('model.h5')\ny_val_pred = model.predict(x_val)\n\ndef compute_score_inv(threshold):\n    y1 = y_val_pred > threshold\n    y1 = y1.astype(int).sum(axis=1) - 1\n    y2 = y_val.sum(axis=1) - 1\n    score = cohen_kappa_score(y1, y2, weights='quadratic')\n    \n    return 1 - score\n\nsimplex = scipy.optimize.minimize(\n    compute_score_inv, 0.5, method='nelder-mead'\n)\n\nbest_threshold = simplex['x'][0]\n\ny1 = y_val_pred > best_threshold\ny1 = y1.astype(int).sum(axis=1) - 1\ny2 = y_val.sum(axis=1) - 1\nscore = cohen_kappa_score(y1, y2, weights='quadratic')\nprint('Threshold: {}'.format(best_threshold))\nprint('Validation QWK score with best_threshold: {}'.format(score))\n\ny1 = y_val_pred > .5\ny1 = y1.astype(int).sum(axis=1) - 1\nscore = cohen_kappa_score(y1, y2, weights='quadratic')\nprint('Validation QWK score with .5 threshold: {}'.format(score))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:04:36.857530Z","iopub.execute_input":"2025-04-16T20:04:36.857815Z","iopub.status.idle":"2025-04-16T20:05:15.787038Z","shell.execute_reply.started":"2025-04-16T20:04:36.857765Z","shell.execute_reply":"2025-04-16T20:05:15.786343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport zipfile\n\n# Save model\nmodel.save('/kaggle/working/final_model.h5')\nprint(\"✅ Model saved as final_model.h5\")\n\n# Save results DataFrame (if not already saved)\nresults.to_csv('/kaggle/working/model_results.csv', index=False)\nprint(\"✅ Training results saved as model_results.csv\")\n\n# Zip the files\nzip_path = '/kaggle/working/results_bundle.zip'\nwith zipfile.ZipFile(zip_path, 'w') as zipf:\n    zipf.write('/kaggle/working/final_model.h5', arcname='final_model.h5')\n    zipf.write('/kaggle/working/model_results.csv', arcname='model_results.csv')\nprint(f\"✅ Zipped everything to: {zip_path}\")\n\n# Confirm files\nprint(\"📂 Files in working directory:\", os.listdir('/kaggle/working'))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:05:15.788440Z","iopub.execute_input":"2025-04-16T20:05:15.788744Z","iopub.status.idle":"2025-04-16T20:05:16.919444Z","shell.execute_reply.started":"2025-04-16T20:05:15.788696Z","shell.execute_reply":"2025-04-16T20:05:16.918741Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import json\n\nsummary = {\n    'model_name': 'DenseNet121',\n    'final_val_acc': results['val_acc'].iloc[-1],\n    'final_val_loss': results['val_loss'].iloc[-1],\n    'best_val_acc': results['val_acc'].max(),\n    'best_val_loss': results['val_loss'].min(),\n    'best_kappa': max(kappa_metrics.val_kappas),\n    'epochs': len(results),\n    'notes': 'Baseline DenseNet with multilabel targets'\n}\n\n# Save to JSON\nwith open('/kaggle/working/summary_metrics.json', 'w') as f:\n    json.dump(summary, f, indent=4)\n\nprint(\"✅ Summary saved for cross-model comparison.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:05:16.921011Z","iopub.execute_input":"2025-04-16T20:05:16.921321Z","iopub.status.idle":"2025-04-16T20:05:16.929369Z","shell.execute_reply.started":"2025-04-16T20:05:16.921264Z","shell.execute_reply":"2025-04-16T20:05:16.928699Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Install kaggle CLI if not already installed\n!pip install -q kaggle\n\n# Create kaggle folder and move API key\n!mkdir -p ~/.kaggle\n!cp /kaggle/input/kaggle-json/kaggle.json ~/.kaggle/\n!chmod 600 ~/.kaggle/kaggle.json\n\n# Create a new folder for dataset files\n!mkdir -p output_files\n!cp /kaggle/working/final_model.h5 output_files/\n!cp /kaggle/working/model_results.csv output_files/\n!cp /kaggle/working/results_bundle.zip output_files/\n\n# Initialize Kaggle Dataset metadata\n!kaggle datasets init -p output_files\n\n# Replace the default metadata with custom values\ndataset_id = \"vaisaavii/densenet-dr-results\"  # change this!\ndataset_title = \"DenseNet DR Model Results\"\ndataset_metadata = f\"\"\"\n{{\n  \"id\": \"{dataset_id}\",\n  \"title\": \"{dataset_title}\",\n  \"licenses\": [{{\"name\": \"CC0-1.0\"}}],\n  \"isPrivate\": true\n}}\n\"\"\"\n\nwith open(\"output_files/dataset-metadata.json\", \"w\") as f:\n    f.write(dataset_metadata)\n\n# Create the dataset\n!kaggle datasets create -p output_files --dir-mode zip\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:05:16.930953Z","iopub.execute_input":"2025-04-16T20:05:16.931255Z","iopub.status.idle":"2025-04-16T20:05:37.971719Z","shell.execute_reply.started":"2025-04-16T20:05:16.931200Z","shell.execute_reply":"2025-04-16T20:05:37.971029Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import roc_curve, auc\nfrom sklearn.preprocessing import label_binarize\n\n# Assuming y_val and y_val_pred are already defined and in shape (N, 5)\nfpr = dict()\ntpr = dict()\nroc_auc = dict()\nfor i in range(5):\n    fpr[i], tpr[i], _ = roc_curve(y_val[:, i], y_val_pred[:, i])\n    roc_auc[i] = auc(fpr[i], tpr[i])\n\n# Plot all ROC curves\nplt.figure(figsize=(10, 8))\nfor i in range(5):\n    plt.plot(fpr[i], tpr[i], lw=2, label='Class {} (AUC = {:.2f})'.format(i, roc_auc[i]))\nplt.plot([0, 1], [0, 1], linestyle='--', lw=2, color='r', alpha=0.8)\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('ROC Curves')\nplt.legend(loc=\"lower right\")\nplt.grid()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:05:37.973506Z","iopub.execute_input":"2025-04-16T20:05:37.973745Z","iopub.status.idle":"2025-04-16T20:05:38.308435Z","shell.execute_reply.started":"2025-04-16T20:05:37.973706Z","shell.execute_reply":"2025-04-16T20:05:38.307397Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\n# Create confusion matrix\ncm = confusion_matrix(y2, y1)\n\n# Plot it using seaborn heatmap\nplt.figure(figsize=(6, 5))\nsns.heatmap(cm, annot=True, fmt=\"d\", cmap='Blues', cbar=False)\nplt.xlabel(\"Predicted Labels\")\nplt.ylabel(\"True Labels\")\nplt.title(\"Confusion Matrix (Threshold {:.2f})\".format(best_threshold))\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:15:49.842206Z","iopub.execute_input":"2025-04-16T20:15:49.842498Z","iopub.status.idle":"2025-04-16T20:15:50.278845Z","shell.execute_reply.started":"2025-04-16T20:15:49.842442Z","shell.execute_reply":"2025-04-16T20:15:50.277694Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import classification_report\n\nprint(\"Classification Report:\\n\")\nprint(classification_report(y2, y1))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:11:46.271286Z","iopub.execute_input":"2025-04-16T20:11:46.271602Z","iopub.status.idle":"2025-04-16T20:11:46.285188Z","shell.execute_reply.started":"2025-04-16T20:11:46.271560Z","shell.execute_reply":"2025-04-16T20:11:46.284454Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results[['loss', 'val_loss']].plot()\nplt.title(\"Loss vs Val Loss\")\nplt.savefig(\"loss_vs_val_loss.png\")\n\nresults[['acc', 'val_acc']].plot()\nplt.title(\"Accuracy vs Val Accuracy\")\nplt.savefig(\"accuracy_vs_val_accuracy.png\")\n\n# Save ROC Curve separately\nplt.figure(figsize=(10, 8))\nfor i in range(5):\n    plt.plot(fpr[i], tpr[i], lw=2, label='Class {} (AUC = {:.2f})'.format(i, roc_auc[i]))\nplt.plot([0, 1], [0, 1], linestyle='--', lw=2, color='r', alpha=0.8)\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('ROC Curves')\nplt.legend(loc=\"lower right\")\nplt.grid()\nplt.savefig(\"roc_curves.png\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:11:46.651742Z","iopub.execute_input":"2025-04-16T20:11:46.652048Z","iopub.status.idle":"2025-04-16T20:11:47.893404Z","shell.execute_reply.started":"2025-04-16T20:11:46.652011Z","shell.execute_reply":"2025-04-16T20:11:47.892357Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from IPython.display import FileLink, FileLinks\nFileLinks('/kaggle/working/')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:11:56.222096Z","iopub.execute_input":"2025-04-16T20:11:56.222352Z","iopub.status.idle":"2025-04-16T20:11:56.228252Z","shell.execute_reply.started":"2025-04-16T20:11:56.222315Z","shell.execute_reply":"2025-04-16T20:11:56.227625Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Plot total training history from all buckets\nresults[['loss', 'val_loss']].plot(title=\"Loss vs. Validation Loss\", figsize=(8, 4))\nplt.grid()\nplt.show()\n\nresults[['acc', 'val_acc']].plot(title=\"Accuracy vs. Validation Accuracy\", figsize=(8, 4))\nplt.grid()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:19:18.841389Z","iopub.execute_input":"2025-04-16T20:19:18.841674Z","iopub.status.idle":"2025-04-16T20:19:19.387100Z","shell.execute_reply.started":"2025-04-16T20:19:18.841635Z","shell.execute_reply":"2025-04-16T20:19:19.386094Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, ax1 = plt.subplots(figsize=(10, 5))\n\ncolor = 'tab:blue'\nax1.set_xlabel('Epoch')\nax1.set_ylabel('Training Loss', color=color)\nax1.plot(results['loss'], label='Loss', color=color)\nax1.tick_params(axis='y', labelcolor=color)\n\nax2 = ax1.twinx()\ncolor = 'tab:green'\nax2.set_ylabel('Training Accuracy', color=color)\nax2.plot(results['acc'], label='Accuracy', color=color)\nax2.tick_params(axis='y', labelcolor=color)\n\nplt.title('Loss vs Accuracy (Train)')\nplt.grid()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:19:59.458243Z","iopub.execute_input":"2025-04-16T20:19:59.458530Z","iopub.status.idle":"2025-04-16T20:20:00.788185Z","shell.execute_reply.started":"2025-04-16T20:19:59.458478Z","shell.execute_reply":"2025-04-16T20:20:00.787100Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, ax1 = plt.subplots(figsize=(10, 5))\n\ncolor = 'tab:blue'\nax1.set_xlabel('Epoch')\nax1.set_ylabel('Validation Loss', color=color)\nax1.plot(results['val_loss'], label='Val Loss', color=color)\nax1.tick_params(axis='y', labelcolor=color)\n\nax2 = ax1.twinx()\ncolor = 'tab:red'\nax2.set_ylabel('Validation Accuracy', color=color)\nax2.plot(results['val_acc'], label='Val Accuracy', color=color)\nax2.tick_params(axis='y', labelcolor=color)\n\nplt.title('Loss vs Accuracy (Validation)')\nplt.grid()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:20:08.336357Z","iopub.execute_input":"2025-04-16T20:20:08.336636Z","iopub.status.idle":"2025-04-16T20:20:09.657213Z","shell.execute_reply.started":"2025-04-16T20:20:08.336596Z","shell.execute_reply":"2025-04-16T20:20:09.656155Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results['kappa'].plot(title=\"Cohen Kappa Score per Epoch\", figsize=(8, 4))\nplt.grid()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:20:17.233639Z","iopub.execute_input":"2025-04-16T20:20:17.233896Z","iopub.status.idle":"2025-04-16T20:20:17.456369Z","shell.execute_reply.started":"2025-04-16T20:20:17.233860Z","shell.execute_reply":"2025-04-16T20:20:17.455277Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results['acc_gain'] = results['acc'].diff()\nresults['acc_gain'].plot(title=\"Accuracy Gain per Epoch\", figsize=(8, 4))\nplt.grid()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:20:24.289856Z","iopub.execute_input":"2025-04-16T20:20:24.290130Z","iopub.status.idle":"2025-04-16T20:20:24.514596Z","shell.execute_reply.started":"2025-04-16T20:20:24.290092Z","shell.execute_reply":"2025-04-16T20:20:24.513552Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results['loss_drop'] = -results['loss'].diff()\nresults['loss_drop'].plot(title=\"Loss Drop per Epoch\", figsize=(8, 4))\nplt.grid()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:20:31.153473Z","iopub.execute_input":"2025-04-16T20:20:31.153785Z","iopub.status.idle":"2025-04-16T20:20:31.375800Z","shell.execute_reply.started":"2025-04-16T20:20:31.153745Z","shell.execute_reply":"2025-04-16T20:20:31.374746Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for metric in ['loss', 'val_loss', 'acc', 'val_acc']:\n    plt.figure()\n    results[[metric]].plot(title=f\"{metric.upper()} over Epochs\")\n    plt.grid()\n    plt.savefig(f\"/kaggle/working/{metric}_plot.png\")\n    plt.close()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:20:41.712461Z","iopub.execute_input":"2025-04-16T20:20:41.712759Z","iopub.status.idle":"2025-04-16T20:20:42.324341Z","shell.execute_reply.started":"2025-04-16T20:20:41.712718Z","shell.execute_reply":"2025-04-16T20:20:42.323396Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with open('/kaggle/working/run_notes.txt', 'w') as f:\n    f.write(\"Model: DenseNet\\n\")\n    f.write(f\"Best Val Acc: {results['val_acc'].max():.4f}\\n\")\n    f.write(\"Threshold used: 0.5\\n\")\n    f.write(\"Kappa callback enabled\\n\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-16T20:23:24.503231Z","iopub.execute_input":"2025-04-16T20:23:24.503648Z","iopub.status.idle":"2025-04-16T20:23:24.508845Z","shell.execute_reply.started":"2025-04-16T20:23:24.503451Z","shell.execute_reply":"2025-04-16T20:23:24.507988Z"}},"outputs":[],"execution_count":null}]}