{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceType":"competition","sourceId":14774,"databundleVersionId":875431}],"dockerImageVersionId":31287,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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":"2026-04-22T13:50:10.303573Z","iopub.execute_input":"2026-04-22T13:50:10.303843Z","iopub.status.idle":"2026-04-22T13:50:43.736842Z","shell.execute_reply.started":"2026-04-22T13:50:10.303811Z","shell.execute_reply":"2026-04-22T13:50:43.736017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport tensorflow as tf\n\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import MobileNetV2\nfrom tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Dropout\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.regularizers import l2\n\nfrom sklearn.utils.class_weight import compute_class_weight","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-22T13:50:43.738659Z","iopub.execute_input":"2026-04-22T13:50:43.739086Z","iopub.status.idle":"2026-04-22T13:51:09.365394Z","shell.execute_reply.started":"2026-04-22T13:50:43.739060Z","shell.execute_reply":"2026-04-22T13:51:09.364775Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = pd.read_csv(\"/kaggle/input/competitions/aptos2019-blindness-detection/train.csv\")\n\ntrain_df[\"id_code\"] = train_df[\"id_code\"] + \".png\"\ntrain_df[\"diagnosis\"] = train_df[\"diagnosis\"].astype(str)\n\ntrain_path = \"/kaggle/input/competitions/aptos2019-blindness-detection/train_images\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-22T13:51:09.366230Z","iopub.execute_input":"2026-04-22T13:51:09.366731Z","iopub.status.idle":"2026-04-22T13:51:09.460331Z","shell.execute_reply.started":"2026-04-22T13:51:09.366706Z","shell.execute_reply":"2026-04-22T13:51:09.459463Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"datagen = ImageDataGenerator(\n    rescale=1./255,\n    validation_split=0.2,\n\n    rotation_range=15,\n    zoom_range=0.15,\n    width_shift_range=0.08,\n    height_shift_range=0.08,\n\n    shear_range=0.1,\n    brightness_range=[0.8,1.2],\n\n    horizontal_flip=True,\n    fill_mode='nearest'\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-22T13:51:09.461249Z","iopub.execute_input":"2026-04-22T13:51:09.461660Z","iopub.status.idle":"2026-04-22T13:51:09.465912Z","shell.execute_reply.started":"2026-04-22T13:51:09.461636Z","shell.execute_reply":"2026-04-22T13:51:09.465079Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data = datagen.flow_from_dataframe(\n    dataframe=train_df,\n    directory=train_path,\n    x_col=\"id_code\",\n    y_col=\"diagnosis\",\n    target_size=(224,224),\n    batch_size=16,\n    class_mode=\"categorical\",\n    subset=\"training\",\n    shuffle=True\n)\n\nval_data = datagen.flow_from_dataframe(\n    dataframe=train_df,\n    directory=train_path,\n    x_col=\"id_code\",\n    y_col=\"diagnosis\",\n    target_size=(224,224),\n    batch_size=16,\n    class_mode=\"categorical\",\n    subset=\"validation\",\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-22T13:51:09.467021Z","iopub.execute_input":"2026-04-22T13:51:09.467676Z","iopub.status.idle":"2026-04-22T13:51:53.193576Z","shell.execute_reply.started":"2026-04-22T13:51:09.467653Z","shell.execute_reply":"2026-04-22T13:51:53.192692Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"classes = np.unique(train_data.classes)\n\nweights = compute_class_weight(\n    class_weight='balanced',\n    classes=classes,\n    y=train_data.classes\n)\n\nclass_weights = dict(zip(classes, weights))\n\nprint(\"Class Weights:\", class_weights)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-22T13:51:53.194619Z","iopub.execute_input":"2026-04-22T13:51:53.194940Z","iopub.status.idle":"2026-04-22T13:51:53.228179Z","shell.execute_reply.started":"2026-04-22T13:51:53.194915Z","shell.execute_reply":"2026-04-22T13:51:53.227342Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_model = MobileNetV2(\n    weights=\"imagenet\",\n    include_top=False,\n    input_shape=(224,224,3)\n)\n\n# Fine-tuning\nfor layer in base_model.layers[:-50]:\n    layer.trainable = False\n\nfor layer in base_model.layers[-50:]:\n    layer.trainable = True\n\n# Head\nx = base_model.output\nx = GlobalAveragePooling2D()(x)\n\nx = Dense(256, activation=\"relu\", kernel_regularizer=l2(0.001))(x)\nx = Dropout(0.6)(x)\n\npredictions = Dense(5, activation=\"softmax\")(x)\n\nmodel = Model(inputs=base_model.input, outputs=predictions)\n\nmodel.summary()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-22T13:51:53.230217Z","iopub.execute_input":"2026-04-22T13:51:53.230800Z","iopub.status.idle":"2026-04-22T13:51:56.298148Z","shell.execute_reply.started":"2026-04-22T13:51:53.230778Z","shell.execute_reply":"2026-04-22T13:51:56.297457Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=0.00005),\n    loss=\"categorical_crossentropy\",\n    metrics=[\"accuracy\"]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-22T13:51:56.299065Z","iopub.execute_input":"2026-04-22T13:51:56.299367Z","iopub.status.idle":"2026-04-22T13:51:56.312622Z","shell.execute_reply.started":"2026-04-22T13:51:56.299346Z","shell.execute_reply":"2026-04-22T13:51:56.311830Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau\n\nearly_stop = EarlyStopping(\n    monitor='val_loss',\n    patience=5,\n    restore_best_weights=True\n)\n\nlr_reduce = ReduceLROnPlateau(\n    monitor='val_loss',\n    factor=0.3,\n    patience=2,\n    min_lr=1e-6\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = model.fit(\n    train_data,\n    validation_data=val_data,\n    epochs=40,\n    callbacks=[early_stop, lr_reduce],\n    class_weight=class_weights\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-22T13:51:56.320208Z","iopub.execute_input":"2026-04-22T13:51:56.320509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.figure(figsize=(16,6))\n\n# Accuracy\nplt.subplot(1,2,1)\n\nplt.plot(history.history['accuracy'], marker='o', label='Train Accuracy')\nplt.plot(history.history['val_accuracy'], marker='o', label='Valid Accuracy')\n\nplt.title('Model Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\n\nplt.legend(loc='lower right')\nplt.grid(True)\n\n# Loss\nplt.subplot(1,2,2)\n\nplt.plot(history.history['loss'], marker='o', label='Train Loss')\nplt.plot(history.history['val_loss'], marker='o', label='Valid Loss')\n\nplt.title('Model Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\n\nplt.legend(loc='upper right')\nplt.grid(True)\n\nplt.tight_layout()\nplt.show()\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nfrom sklearn.metrics import confusion_matrix, classification_report\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\n\nval_data.reset()\n\ny_pred = model.predict(val_data)\ny_pred_classes = np.argmax(y_pred, axis=1)\n\ny_true = val_data.classes\n\n\ncm = confusion_matrix(y_true, y_pred_classes)\n\n\nlabels = ['Normal', 'Mild', 'Moderate', 'Severe', 'Proliferative']\n\n\nplt.figure(figsize=(8,6))\n\nsns.heatmap(cm,\n            annot=True,\n            fmt='d',\n            cmap='Blues',           # 🔵 تدرج أزرق\n            linewidths=1,\n            linecolor='black',\n            xticklabels=labels,\n            yticklabels=labels,\n            annot_kws={\"size\":12, \"weight\":\"bold\"})\n\nplt.title('Confusion Matrix', fontsize=16)\nplt.xlabel('Predicted Label', fontsize=12)\nplt.ylabel('Actual Label', fontsize=12)\n\nplt.xticks(rotation=30)\nplt.yticks(rotation=0)\n\nplt.tight_layout()\nplt.show()\n\nprint(\"\\n--- Classification Report ---\\n\")\nprint(classification_report(y_true, y_pred_classes, target_names=labels))","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}