{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":14774,"databundleVersionId":875431,"isSourceIdPinned":false,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"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\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 read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:02:39.806783Z","iopub.execute_input":"2025-06-24T09:02:39.807448Z","iopub.status.idle":"2025-06-24T09:02:48.024697Z","shell.execute_reply.started":"2025-06-24T09:02:39.807421Z","shell.execute_reply":"2025-06-24T09:02:48.024009Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom keras import Sequential, layers\nfrom tensorflow.keras.models import Model\nfrom keras.layers import Input, Conv2D, MaxPooling2D, GlobalAveragePooling2D, Dense, Flatten, Activation, Dropout, BatchNormalization\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom sklearn.model_selection import train_test_split\n%matplotlib ipympl\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:25.204754Z","iopub.execute_input":"2025-06-24T09:03:25.204974Z","iopub.status.idle":"2025-06-24T09:03:25.221726Z","shell.execute_reply.started":"2025-06-24T09:03:25.204958Z","shell.execute_reply":"2025-06-24T09:03:25.221025Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\n\ngpus = tf.config.experimental.list_physical_devices('GPU')\nif gpus:\n    try:\n        tf.config.experimental.set_visible_devices(gpus[0], 'GPU')\n        tf.config.experimental.set_memory_growth(gpus[0], True)\n        print(\"GPU setup completed.\")\n    except RuntimeError as e:\n        print(f\"RuntimeError: {e}\")\nelse:\n    print(\"No GPU devices found.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:22.706942Z","iopub.execute_input":"2025-06-24T09:03:22.707399Z","iopub.status.idle":"2025-06-24T09:03:25.161671Z","shell.execute_reply.started":"2025-06-24T09:03:22.70738Z","shell.execute_reply":"2025-06-24T09:03:25.160999Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"folder_path = '/kaggle/input/aptos2019-blindness-detection/train_images'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:25.162388Z","iopub.execute_input":"2025-06-24T09:03:25.162758Z","iopub.status.idle":"2025-06-24T09:03:25.203515Z","shell.execute_reply.started":"2025-06-24T09:03:25.162729Z","shell.execute_reply":"2025-06-24T09:03:25.203007Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = pd.read_csv('/kaggle/input/aptos2019-blindness-detection/train.csv')\ntest_df = pd.read_csv('/kaggle/input/aptos2019-blindness-detection/test.csv')\n\ntrain_df['id_code'] = train_df['id_code'] + '.png'\ntrain_df['diagnosis'] = train_df['diagnosis'].astype(str)\ntrain_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:35.147603Z","iopub.execute_input":"2025-06-24T09:03:35.148167Z","iopub.status.idle":"2025-06-24T09:03:35.201492Z","shell.execute_reply.started":"2025-06-24T09:03:35.14814Z","shell.execute_reply":"2025-06-24T09:03:35.200931Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df_shuffled = train_df.sample(frac=1, random_state=42).reset_index(drop=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:36.047199Z","iopub.execute_input":"2025-06-24T09:03:36.047462Z","iopub.status.idle":"2025-06-24T09:03:36.063475Z","shell.execute_reply.started":"2025-06-24T09:03:36.047441Z","shell.execute_reply":"2025-06-24T09:03:36.062764Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"final_train_df, test_df = train_test_split(train_df_shuffled, test_size=0.2, stratify=train_df_shuffled['diagnosis'], random_state=42)\nfinal_val_df, final_test_df = train_test_split(test_df, test_size=0.2, stratify=test_df['diagnosis'], random_state=42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:37.887014Z","iopub.execute_input":"2025-06-24T09:03:37.887331Z","iopub.status.idle":"2025-06-24T09:03:37.90064Z","shell.execute_reply.started":"2025-06-24T09:03:37.887288Z","shell.execute_reply":"2025-06-24T09:03:37.900132Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Data Augmentation","metadata":{}},{"cell_type":"code","source":"train_datagen = ImageDataGenerator(rescale = 1 / 255.,\n                                   rotation_range = 20,\n                                   width_shift_range = 0.2,\n                                   height_shift_range = 0.2,\n                                   shear_range = 0.2,\n                                   zoom_range = 0.2,\n                                   brightness_range = [0.8, 1.2],\n                                   horizontal_flip = True)\n\nval_datagen = ImageDataGenerator(rescale = 1 / 255.)\ntest_datagen = ImageDataGenerator(rescale = 1 / 255.)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:38.337578Z","iopub.execute_input":"2025-06-24T09:03:38.337802Z","iopub.status.idle":"2025-06-24T09:03:38.341985Z","shell.execute_reply.started":"2025-06-24T09:03:38.337786Z","shell.execute_reply":"2025-06-24T09:03:38.341237Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_generator = train_datagen.flow_from_dataframe(final_train_df,\n                                                    directory = folder_path,\n                                                    x_col = 'id_code',\n                                                    y_col = 'diagnosis',\n                                                    target_size = (224, 224),\n                                                    batch_size = 32,\n                                                    class_mode = 'categorical')\nvalidation_generator = val_datagen.flow_from_dataframe(final_val_df,\n                                                  directory = folder_path,\n                                                  x_col = 'id_code',\n                                                  y_col = 'diagnosis',\n                                                  target_size = (224, 224),\n                                                  batch_size = 32,\n                                                  class_mode = 'categorical')\n\ntest_generator = test_datagen.flow_from_dataframe(final_test_df,\n                                                  directory = folder_path,\n                                                  x_col = 'id_code',\n                                                  y_col = 'diagnosis',\n                                                  target_size = (224, 224),\n                                                  batch_size = 32,\n                                                  class_mode = 'categorical')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:38.646808Z","iopub.execute_input":"2025-06-24T09:03:38.647636Z","iopub.status.idle":"2025-06-24T09:03:43.823293Z","shell.execute_reply.started":"2025-06-24T09:03:38.647606Z","shell.execute_reply":"2025-06-24T09:03:43.822175Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Callbacks","metadata":{}},{"cell_type":"code","source":"def categorical_focal_loss(gamma = 2.0, alpha = 0.25):\n    def loss_fn(y_true, y_pred):\n        y_pred = tf.clip_by_value(y_pred, 1e-7, 1.0 - 1e-7)\n        cross_entropy = -y_true * tf.math.log(y_pred)\n        focal_factor = alpha * tf.pow(1 - y_pred, gamma)\n        loss = focal_factor * cross_entropy\n        return tf.reduce_sum(loss, axis=1)\n    return loss_fn","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:43.824967Z","iopub.execute_input":"2025-06-24T09:03:43.825896Z","iopub.status.idle":"2025-06-24T09:03:43.832042Z","shell.execute_reply.started":"2025-06-24T09:03:43.825863Z","shell.execute_reply":"2025-06-24T09:03:43.831477Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau\n\nclass LearningRateLogger(tf.keras.callbacks.Callback):\n    def on_epoch_end(self, epoch, logs=None):\n        logs = logs or {}\n        lr = self.model.optimizer.learning_rate\n        logs['learning_rate'] = tf.keras.backend.get_value(lr)\n\n\nlr_scheduler = ReduceLROnPlateau(\n    monitor ='val_loss', factor = 0.5, patience = 4, verbose = 1, min_lr = 1e-6\n)\n\nearly_stop = EarlyStopping(\n    monitor = 'val_loss',\n    patience = 10,\n    restore_best_weights = True,\n    verbose = 1\n)\n\ncallback = [early_stop, lr_scheduler, LearningRateLogger()]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:43.832901Z","iopub.execute_input":"2025-06-24T09:03:43.833133Z","iopub.status.idle":"2025-06-24T09:03:43.941894Z","shell.execute_reply.started":"2025-06-24T09:03:43.833107Z","shell.execute_reply":"2025-06-24T09:03:43.941254Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Custom Model Making","metadata":{}},{"cell_type":"code","source":"def depthwise_separable_conv(inputs, filters, strides = 1, use_se = False):\n    \n    x = layers.DepthwiseConv2D(kernel_size = 3, strides = strides, padding = 'same')(inputs)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n\n    x = layers.Conv2D(filters, kernel_size = 1, strides = 1, padding = 'same')(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n\n    if use_se:\n        x = squeeze_excitation_block(x)\n\n    return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:43.94386Z","iopub.execute_input":"2025-06-24T09:03:43.944504Z","iopub.status.idle":"2025-06-24T09:03:43.970079Z","shell.execute_reply.started":"2025-06-24T09:03:43.944485Z","shell.execute_reply":"2025-06-24T09:03:43.96956Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def squeeze_excitation_block(inputs, ratio = 16):\n    \n    filters = inputs.shape[-1]\n    x = layers.GlobalAveragePooling2D()(inputs)\n    x = layers.Dense(filters // ratio, activation = 'relu')(x)\n    x = layers.Dense(filters, activation = 'sigmoid')(x)\n    x = layers.Reshape((1, 1, filters))(x)\n    return layers.Multiply()([inputs, x])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:43.970752Z","iopub.execute_input":"2025-06-24T09:03:43.971028Z","iopub.status.idle":"2025-06-24T09:03:43.987995Z","shell.execute_reply.started":"2025-06-24T09:03:43.971008Z","shell.execute_reply":"2025-06-24T09:03:43.987431Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_model():\n    inputs = layers.Input(shape = (224, 224, 3))\n\n    # First Conv2D layer with tunable filters\n    x = layers.Conv2D(32, kernel_size = 3, strides = 2, padding = 'same')(inputs)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n\n    # Depthwise Separable Convolutional Blocks with hp.Choice filters\n    x = depthwise_separable_conv(x, 64, strides = 1, use_se = True)\n    x = depthwise_separable_conv(x, 256, strides = 2, use_se = True)\n    x = depthwise_separable_conv(x, 256, strides = 1, use_se = True)\n    x = depthwise_separable_conv(x, 512, strides = 2, use_se = True)\n    x = depthwise_separable_conv(x, 256, strides = 1, use_se = True)\n    x = depthwise_separable_conv(x, 1024, strides = 2, use_se = True)\n    x = depthwise_separable_conv(x, 512, strides = 1, use_se = True)\n\n    # Global Average Pooling and Dense layers\n    x = layers.GlobalAveragePooling2D()(x)\n    x = layers.Dense(128, activation = 'relu')(x)\n    x = layers.Dropout(0.5)(x)\n    outputs = layers.Dense(5, activation = 'softmax')(x)\n\n    model = keras.Model(inputs, outputs)\n\n    model.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])\n\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:43.988625Z","iopub.execute_input":"2025-06-24T09:03:43.988822Z","iopub.status.idle":"2025-06-24T09:03:44.005458Z","shell.execute_reply.started":"2025-06-24T09:03:43.988808Z","shell.execute_reply":"2025-06-24T09:03:44.004989Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model1 = build_model()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:44.00602Z","iopub.execute_input":"2025-06-24T09:03:44.006534Z","iopub.status.idle":"2025-06-24T09:03:46.350693Z","shell.execute_reply.started":"2025-06-24T09:03:44.006512Z","shell.execute_reply":"2025-06-24T09:03:46.349937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import time \nnow = time.time()\n\nhistory = model1.fit(\n    train_generator,\n    epochs = 45,\n    validation_data = validation_generator,\n    callbacks = callback\n)\n\nprint(f\"Total Training time: {(time.time() - now) / 3600: .4f}hrs\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T09:03:46.351505Z","iopub.execute_input":"2025-06-24T09:03:46.351789Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model1.save('/kaggle/working/vary1_batchsize_nonlinear3.h5')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from IPython.display import FileLink\nFileLink('/kaggle/working/vary1_batchsize_nonlinear3.h5')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%matplotlib inline\nimport matplotlib.pyplot as plt\n\n# Plot Loss (linear scale)\nplt.figure(figsize=(10, 5))\nplt.plot(history.history['loss'], label='Train Loss', linewidth=2)\nplt.plot(history.history['val_loss'], label='Validation Loss', linewidth=2)\nplt.title('Model Training vs. Validation Loss', fontsize=14)\nplt.xlabel('Epoch', fontsize=12)\nplt.ylabel('Loss', fontsize=12)\nplt.legend()\nplt.grid(True)\nplt.tight_layout()\nplt.show()\n\n# Plot Accuracy\nplt.figure(figsize=(10, 5))\nplt.plot(history.history['accuracy'], label='Train Accuracy', linewidth=2)\nplt.plot(history.history['val_accuracy'], label='Validation Accuracy', linewidth=2)\nplt.title('Model Training vs. Validation Accuracy', fontsize=14)\nplt.xlabel('Epoch', fontsize=12)\nplt.ylabel('Accuracy', fontsize=12)\nplt.ylim(0, 1)\nplt.legend()\nplt.grid(True)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def evaluate_model_from_generator(model, generator, loss_fn):\n    total_loss = 0.0\n    total_correct = 0\n    total_samples = 0\n\n    for batch_images, batch_labels in generator:\n        batch_size = batch_images.shape[0]\n\n        predictions = model(batch_images, training=False)\n        loss = tf.reduce_sum(loss_fn(batch_labels, predictions)).numpy()  # sum, not mean\n\n        total_loss += loss\n\n        # Accuracy: convert one-hot to class indices\n        true_classes = np.argmax(batch_labels, axis=1)\n        pred_classes = np.argmax(predictions, axis=1)\n        correct = np.sum(true_classes == pred_classes)\n\n        total_correct += correct\n        total_samples += batch_size\n\n        if total_samples >= generator.samples:\n            break\n\n    avg_loss = total_loss / total_samples\n    avg_acc = total_correct / total_samples\n    return avg_loss, avg_acc","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"t = time.time()\n\nloss_fn = tf.keras.losses.CategoricalCrossentropy()\n\ntrain_loss, train_acc = evaluate_model_from_generator(model1, train_generator, loss_fn)\nprint(f\"Train Accuracy: {train_acc * 100:.2f}%\")\n\nval_loss, val_acc = evaluate_model_from_generator(model1, validation_generator, loss_fn)\nprint(f\"Validation Accuracy: {val_acc * 100:.2f}%\")\n\ntest_loss, test_acc = evaluate_model_from_generator(model1, test_generator, loss_fn)\nprint(f\"Test Accuracy: {test_acc * 100:.2f}%\")\n\nprint(f\"Total Evaluation time: {(time.time() - t) / 60: .2f} mins\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import classification_report, confusion_matrix\n\nclass_names = ['NO DR', 'MILD', 'MODERATE', 'SEVERE', 'PROLIFERATE']\n\ny_true = []\ny_pred = []\n\nfor batch_images, batch_labels in validation_generator:\n    predictions = model1(batch_images, training=False)  \n\n    # If labels are one-hot encoded, convert to integer class labels\n    if batch_labels.shape[-1] == len(class_names):  # one-hot\n        true_classes = tf.argmax(batch_labels, axis=1)\n    else:  # already integer labels\n        true_classes = tf.cast(batch_labels, tf.int64)\n\n    predicted_classes = tf.argmax(predictions, axis=1)\n\n    # Add to overall list\n    y_true.extend(true_classes.numpy())\n    y_pred.extend(predicted_classes.numpy())\n\n    # Optional: break after all samples if generator loops infinitely\n    if len(y_true) >= validation_generator.samples:\n        break\n\n# Evaluate\nprint(classification_report(y_true, y_pred, target_names=class_names))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import cohen_kappa_score\n\n# Assuming y_true and y_pred contain integer labels\nkappa_score = cohen_kappa_score(y_true, y_pred)\nprint(f\"Cohen's Kappa Score: {kappa_score:.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import cohen_kappa_score\n\nqwk_score = cohen_kappa_score(y_true, y_pred, weights='quadratic')\nprint(f\"Quadratic Weighted Kappa (QWK): {qwk_score:.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport seaborn as sns\n%matplotlib inline\nimport matplotlib.pyplot as plt\n\n# Confusion matrix\nconf_matrix = confusion_matrix(y_true, y_pred)\n\nclass_names = [\"No DR\", \"Mild\", \"Moderate\", \"Severe\", \"Proliferate DR\"]\n\nplt.figure(figsize=(8, 6))\nsns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues',\n            xticklabels=class_names,\n            yticklabels=class_names)\n\nplt.xlabel('Predicted Labels')\nplt.ylabel('True Labels')\nplt.title('Confusion Matrix Heatmap')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import classification_report, confusion_matrix\n\nclass_names = ['NO DR', 'MILD', 'MODERATE', 'SEVERE', 'PROLIFERATE']\n\ny_true = []\ny_pred = []\n\nfor batch_images, batch_labels in test_generator:\n    predictions = model1(batch_images, training=False)  \n\n    # If labels are one-hot encoded, convert to integer class labels\n    if batch_labels.shape[-1] == len(class_names):  # one-hot\n        true_classes = tf.argmax(batch_labels, axis=1)\n    else:  # already integer labels\n        true_classes = tf.cast(batch_labels, tf.int64)\n\n    predicted_classes = tf.argmax(predictions, axis=1)\n\n    # Add to overall list\n    y_true.extend(true_classes.numpy())\n    y_pred.extend(predicted_classes.numpy())\n\n    # Optional: break after all samples if generator loops infinitely\n    if len(y_true) >= test_generator.samples:\n        break\n\n# Evaluate\nprint(classification_report(y_true, y_pred, target_names=class_names))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import cohen_kappa_score\n\n# Assuming y_true and y_pred contain integer labels\nkappa_score = cohen_kappa_score(y_true, y_pred)\nprint(f\"Cohen's Kappa Score: {kappa_score:.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import cohen_kappa_score\n\nqwk_score = cohen_kappa_score(y_true, y_pred, weights='quadratic')\nprint(f\"Quadratic Weighted Kappa (QWK): {qwk_score:.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport seaborn as sns\n%matplotlib inline\nimport matplotlib.pyplot as plt\n\n# Confusion matrix\nconf_matrix = confusion_matrix(y_true, y_pred)\n\nclass_names = [\"No DR\", \"Mild\", \"Moderate\", \"Severe\", \"Proliferate DR\"]\n\nplt.figure(figsize=(8, 6))\nsns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues',\n            xticklabels=class_names,\n            yticklabels=class_names)\n\nplt.xlabel('Predicted Labels')\nplt.ylabel('True Labels')\nplt.title('Confusion Matrix Heatmap')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ninitial_lr = 1e-3\nfactor = 0.5\npatience = 4\nmin_lr = 1e-6\ntotal_epochs = len(history.history['loss'])\n\nlrs = []\nlr = initial_lr\nwait = 0\n\nprevious_loss = history.history['val_loss'][0]\n\nfor epoch in range(total_epochs):\n    current_loss = history.history['val_loss'][epoch]\n    \n    if current_loss < previous_loss: \n        wait = 0\n        previous_loss = current_loss\n    else:\n        wait += 1\n        if wait >= patience:\n            new_lr = max(lr * factor, min_lr)\n            if new_lr < lr:\n                lr = new_lr\n            wait = 0\n\n    lrs.append(lr)\n\n# Plot\nplt.figure(figsize=(10, 4))\nplt.plot(lrs, label='Estimated LR', color='green', marker='o')\nplt.title('Learning Rate per Epoch (ReduceLROnPlateau)')\nplt.xlabel('Epoch')\nplt.ylabel('Learning Rate')\nplt.grid(True)\nplt.legend()\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport random\nimport numpy as np\n\nlabel_mapping = {\n    0: \"No DR\",\n    1: \"Mild\",\n    2: \"Moderate\",\n    3: \"Severe\",\n    4: \"Proliferate DR\"\n}\n\nplt.figure(figsize=(15, 10))\n\n# Total samples\nnum_samples = len(test_generator.filenames)\n\nindices = random.sample(range(num_samples), 20)\n\nfor i, idx in enumerate(indices):\n    image_path = test_generator.filepaths[idx]\n    image = tf.keras.utils.load_img(image_path, target_size=(224, 224))\n    image_array = tf.keras.utils.img_to_array(image) / 255.0  # normalize\n    image_input = np.expand_dims(image_array, axis=0)\n\n    # Actual label\n    actual_label = test_generator.classes[idx]\n\n    # Prediction\n    prediction = model1.predict(image_input, verbose=0)\n    pred_label = np.argmax(prediction)\n\n    # Plotting\n    plt.subplot(4, 5, i + 1)\n    plt.imshow(image)\n    plt.axis('off')\n    plt.title(f\"Actual: {label_mapping[actual_label]}\\nPred: {label_mapping[pred_label]}\", fontsize=9)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pickle\n\n# Save the history object\nwith open('vary1_batchsize_nonlinear3_history.pkl', 'wb') as f:\n    pickle.dump(history.history, f)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Change Batchsize to 8","metadata":{}},{"cell_type":"code","source":"train_generator = train_datagen.flow_from_dataframe(final_train_df,\n                                                    directory = folder_path,\n                                                    x_col = 'id_code',\n                                                    y_col = 'diagnosis',\n                                                    target_size = (224, 224),\n                                                    batch_size = 8,\n                                                    class_mode = 'categorical')\nvalidation_generator = val_datagen.flow_from_dataframe(final_val_df,\n                                                  directory = folder_path,\n                                                  x_col = 'id_code',\n                                                  y_col = 'diagnosis',\n                                                  target_size = (224, 224),\n                                                  batch_size = 8,\n                                                  class_mode = 'categorical')\n\ntest_generator = test_datagen.flow_from_dataframe(final_test_df,\n                                                  directory = folder_path,\n                                                  x_col = 'id_code',\n                                                  y_col = 'diagnosis',\n                                                  target_size = (224, 224),\n                                                  batch_size = 8,\n                                                  class_mode = 'categorical')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model2 = build_model()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import time \nnow = time.time()\n\nhistory = model2.fit(\n    train_generator,\n    epochs = 40,\n    validation_data = validation_generator,\n    callbacks = callback\n)\n\nprint(f\"Total Training time: {(time.time() - now) / 3600: .4f}hrs\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model2.save('/kaggle/working/vary2_batchsize_nonlinear3.h5')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from IPython.display import FileLink\nFileLink('/kaggle/working/vary2_batchsize_nonlinear3.h5')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%matplotlib inline\nimport matplotlib.pyplot as plt\n\n# Plot Loss (linear scale)\nplt.figure(figsize=(10, 5))\nplt.plot(history.history['loss'], label='Train Loss', linewidth=2)\nplt.plot(history.history['val_loss'], label='Validation Loss', linewidth=2)\nplt.title('Model Training vs. Validation Loss', fontsize=14)\nplt.xlabel('Epoch', fontsize=12)\nplt.ylabel('Loss', fontsize=12)\nplt.legend()\nplt.grid(True)\nplt.tight_layout()\nplt.show()\n\n# Plot Accuracy\nplt.figure(figsize=(10, 5))\nplt.plot(history.history['accuracy'], label='Train Accuracy', linewidth=2)\nplt.plot(history.history['val_accuracy'], label='Validation Accuracy', linewidth=2)\nplt.title('Model Training vs. Validation Accuracy', fontsize=14)\nplt.xlabel('Epoch', fontsize=12)\nplt.ylabel('Accuracy', fontsize=12)\nplt.ylim(0, 1)\nplt.legend()\nplt.grid(True)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def evaluate_model_from_generator(model, generator, loss_fn):\n    total_loss = 0.0\n    total_correct = 0\n    total_samples = 0\n\n    for batch_images, batch_labels in generator:\n        batch_size = batch_images.shape[0]\n\n        predictions = model(batch_images, training=False)\n        loss = tf.reduce_sum(loss_fn(batch_labels, predictions)).numpy()  # sum, not mean\n\n        total_loss += loss\n\n        # Accuracy: convert one-hot to class indices\n        true_classes = np.argmax(batch_labels, axis=1)\n        pred_classes = np.argmax(predictions, axis=1)\n        correct = np.sum(true_classes == pred_classes)\n\n        total_correct += correct\n        total_samples += batch_size\n\n        if total_samples >= generator.samples:\n            break\n\n    avg_loss = total_loss / total_samples\n    avg_acc = total_correct / total_samples\n    return avg_loss, avg_acc","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"t = time.time()\n\nloss_fn = tf.keras.losses.CategoricalCrossentropy()\n\ntrain_loss, train_acc = evaluate_model_from_generator(model2, train_generator, loss_fn)\nprint(f\"Train Accuracy: {train_acc * 100:.2f}%\")\n\nval_loss, val_acc = evaluate_model_from_generator(model2, validation_generator, loss_fn)\nprint(f\"Validation Accuracy: {val_acc * 100:.2f}%\")\n\ntest_loss, test_acc = evaluate_model_from_generator(model2, test_generator, loss_fn)\nprint(f\"Test Accuracy: {test_acc * 100:.2f}%\")\n\nprint(f\"Total Evaluation time: {(time.time() - t) / 60: .2f} mins\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import classification_report, confusion_matrix\n\nclass_names = ['NO DR', 'MILD', 'MODERATE', 'SEVERE', 'PROLIFERATE']\n\ny_true = []\ny_pred = []\n\nfor batch_images, batch_labels in validation_generator:\n    predictions = model2(batch_images, training=False)  \n\n    # If labels are one-hot encoded, convert to integer class labels\n    if batch_labels.shape[-1] == len(class_names):  # one-hot\n        true_classes = tf.argmax(batch_labels, axis=1)\n    else:  # already integer labels\n        true_classes = tf.cast(batch_labels, tf.int64)\n\n    predicted_classes = tf.argmax(predictions, axis=1)\n\n    # Add to overall list\n    y_true.extend(true_classes.numpy())\n    y_pred.extend(predicted_classes.numpy())\n\n    # Optional: break after all samples if generator loops infinitely\n    if len(y_true) >= validation_generator.samples:\n        break\n\n# Evaluate\nprint(classification_report(y_true, y_pred, target_names=class_names))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import cohen_kappa_score\n\n# Assuming y_true and y_pred contain integer labels\nkappa_score = cohen_kappa_score(y_true, y_pred)\nprint(f\"Cohen's Kappa Score: {kappa_score:.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import cohen_kappa_score\n\nqwk_score = cohen_kappa_score(y_true, y_pred, weights='quadratic')\nprint(f\"Quadratic Weighted Kappa (QWK): {qwk_score:.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport seaborn as sns\n%matplotlib inline\nimport matplotlib.pyplot as plt\n\n# Confusion matrix\nconf_matrix = confusion_matrix(y_true, y_pred)\n\nclass_names = [\"No DR\", \"Mild\", \"Moderate\", \"Severe\", \"Proliferate DR\"]\n\nplt.figure(figsize=(8, 6))\nsns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues',\n            xticklabels=class_names,\n            yticklabels=class_names)\n\nplt.xlabel('Predicted Labels')\nplt.ylabel('True Labels')\nplt.title('Confusion Matrix Heatmap')\nplt.tight_layout()\nplt.show()from sklearn.metrics import confusion_matrix\nimport seaborn as sns\n%matplotlib inline\nimport matplotlib.pyplot as plt\n\n# Confusion matrix\nconf_matrix = confusion_matrix(y_true, y_pred)\n\nclass_names = [\"No DR\", \"Mild\", \"Moderate\", \"Severe\", \"Proliferate DR\"]\n\nplt.figure(figsize=(8, 6))\nsns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues',\n            xticklabels=class_names,\n            yticklabels=class_names)\n\nplt.xlabel('Predicted Labels')\nplt.ylabel('True Labels')\nplt.title('Confusion Matrix Heatmap')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import classification_report, confusion_matrix\n\nclass_names = ['NO DR', 'MILD', 'MODERATE', 'SEVERE', 'PROLIFERATE']\n\ny_true = []\ny_pred = []\n\nfor batch_images, batch_labels in test_generator:\n    predictions = model2(batch_images, training=False)  \n\n    # If labels are one-hot encoded, convert to integer class labels\n    if batch_labels.shape[-1] == len(class_names):  # one-hot\n        true_classes = tf.argmax(batch_labels, axis=1)\n    else:  # already integer labels\n        true_classes = tf.cast(batch_labels, tf.int64)\n\n    predicted_classes = tf.argmax(predictions, axis=1)\n\n    # Add to overall list\n    y_true.extend(true_classes.numpy())\n    y_pred.extend(predicted_classes.numpy())\n\n    # Optional: break after all samples if generator loops infinitely\n    if len(y_true) >= test_generator.samples:\n        break\n\n# Evaluate\nprint(classification_report(y_true, y_pred, target_names=class_names))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import cohen_kappa_score\n\n# Assuming y_true and y_pred contain integer labels\nkappa_score = cohen_kappa_score(y_true, y_pred)\nprint(f\"Cohen's Kappa Score: {kappa_score:.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import cohen_kappa_score\n\nqwk_score = cohen_kappa_score(y_true, y_pred, weights='quadratic')\nprint(f\"Quadratic Weighted Kappa (QWK): {qwk_score:.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport seaborn as sns\n%matplotlib inline\nimport matplotlib.pyplot as plt\n\n# Confusion matrix\nconf_matrix = confusion_matrix(y_true, y_pred)\n\nclass_names = [\"No DR\", \"Mild\", \"Moderate\", \"Severe\", \"Proliferate DR\"]\n\nplt.figure(figsize=(8, 6))\nsns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues',\n            xticklabels=class_names,\n            yticklabels=class_names)\n\nplt.xlabel('Predicted Labels')\nplt.ylabel('True Labels')\nplt.title('Confusion Matrix Heatmap')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ninitial_lr = 1e-3\nfactor = 0.5\npatience = 4\nmin_lr = 1e-6\ntotal_epochs = len(history.history['loss'])\n\nlrs = []\nlr = initial_lr\nwait = 0\n\nprevious_loss = history.history['val_loss'][0]\n\nfor epoch in range(total_epochs):\n    current_loss = history.history['val_loss'][epoch]\n    \n    if current_loss < previous_loss: \n        wait = 0\n        previous_loss = current_loss\n    else:\n        wait += 1\n        if wait >= patience:\n            new_lr = max(lr * factor, min_lr)\n            if new_lr < lr:\n                lr = new_lr\n            wait = 0\n\n    lrs.append(lr)\n\n# Plot\nplt.figure(figsize=(10, 4))\nplt.plot(lrs, label='Estimated LR', color='green', marker='o')\nplt.title('Learning Rate per Epoch (ReduceLROnPlateau)')\nplt.xlabel('Epoch')\nplt.ylabel('Learning Rate')\nplt.grid(True)\nplt.legend()\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport random\nimport numpy as np\n\nlabel_mapping = {\n    0: \"No DR\",\n    1: \"Mild\",\n    2: \"Moderate\",\n    3: \"Severe\",\n    4: \"Proliferate DR\"\n}\n\nplt.figure(figsize=(15, 10))\n\n# Total samples\nnum_samples = len(test_generator.filenames)\n\nindices = random.sample(range(num_samples), 20)\n\nfor i, idx in enumerate(indices):\n    image_path = test_generator.filepaths[idx]\n    image = tf.keras.utils.load_img(image_path, target_size=(224, 224))\n    image_array = tf.keras.utils.img_to_array(image) / 255.0  # normalize\n    image_input = np.expand_dims(image_array, axis=0)\n\n    # Actual label\n    actual_label = test_generator.classes[idx]\n\n    # Prediction\n    prediction = model2.predict(image_input, verbose=0)\n    pred_label = np.argmax(prediction)\n\n    # Plotting\n    plt.subplot(4, 5, i + 1)\n    plt.imshow(image)\n    plt.axis('off')\n    plt.title(f\"Actual: {label_mapping[actual_label]}\\nPred: {label_mapping[pred_label]}\", fontsize=9)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pickle\n\n# Save the history object\nwith open('vary2_batchsize_nonlinear3_history.pkl', 'wb') as f:\n    pickle.dump(history.history, f)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}