{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":14774,"databundleVersionId":875431,"sourceType":"competition"}],"dockerImageVersionId":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.applications import ResNet50, VGG16\nfrom tensorflow.keras.applications import resnet, vgg16 # For preprocessing\n\nimport pandas as pd\nimport numpy as np\nimport os\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import f1_score, precision_score, recall_score, accuracy_score\n\n# --- Define Constants ---\nDATA_DIR = \"/kaggle/input/aptos2019-blindness-detection/\"\nTRAIN_CSV_PATH = os.path.join(DATA_DIR, \"train.csv\")\nTRAIN_IMG_DIR = os.path.join(DATA_DIR, \"train_images\")\n\n# Model constants\nIMG_SIZE = 224 # As required by the models\nIMG_SHAPE = (IMG_SIZE, IMG_SIZE, 3)\nBATCH_SIZE = 32\nNUM_CLASSES = 5","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-01T09:32:36.536516Z","iopub.execute_input":"2025-11-01T09:32:36.537255Z","iopub.status.idle":"2025-11-01T09:32:36.542392Z","shell.execute_reply.started":"2025-11-01T09:32:36.537219Z","shell.execute_reply":"2025-11-01T09:32:36.541524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. Load the CSV file\ndf = pd.read_csv(TRAIN_CSV_PATH)\n\n# 2. Create the full image path\n#    Example: 'id_code_123' -> '/kaggle/input/.../train_images/id_code_123.png'\ndf['image_path'] = df['id_code'].apply(lambda x: os.path.join(TRAIN_IMG_DIR, f\"{x}.png\"))\n\n# 3. Get labels as integers\n#    The 'diagnosis' column is already our label (0, 1, 2, 3, 4)\ndf['label'] = df['diagnosis']\n\n# 4. Split the data into training and validation sets\n#    We use stratify=df['label'] to ensure both sets have a similar\n#    distribution of classes, which is crucial for imbalanced datasets.\ntrain_df, val_df = train_test_split(\n    df,\n    test_size=0.2, # 20% for validation\n    random_state=42,\n    stratify=df['label']\n)\n\nprint(f\"Training samples: {len(train_df)}\")\nprint(f\"Validation samples: {len(val_df)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-01T09:32:36.543417Z","iopub.execute_input":"2025-11-01T09:32:36.543661Z","iopub.status.idle":"2025-11-01T09:32:36.575386Z","shell.execute_reply.started":"2025-11-01T09:32:36.543636Z","shell.execute_reply":"2025-11-01T09:32:36.574768Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. Define the image loading and resizing function\ndef load_image(image_path, label):\n    img = tf.io.read_file(image_path)\n    img = tf.io.decode_png(img, channels=3)\n    img = tf.image.resize(img, [IMG_SIZE, IMG_SIZE])\n    return img, label\n\n# 2. Define the model-specific preprocessing functions\n#    Each pre-trained model has its own way of normalizing pixels\ndef preprocess_vgg16(image, label):\n    image = vgg16.preprocess_input(image) # Uses VGG16's specific normalization\n    return image, label\n\ndef preprocess_resnet50(image, label):\n    image = resnet.preprocess_input(image) # Uses ResNet's specific normalization\n    return image, label\n\ndef preprocess_alexnet(image, label):\n    image = image / 255.0 # Scale to [0, 1]\n    # Normalize using ImageNet mean and std dev\n    image = (image - [0.485, 0.456, 0.406]) / [0.229, 0.224, 0.225]\n    return image, label\n\n# 3. Create a helper function to build the full dataset\ndef create_dataset(df, preprocess_fn):\n    # Create a dataset from the dataframe slices\n    dataset = tf.data.Dataset.from_tensor_slices((\n        df['image_path'].values,\n        df['label'].values\n    ))\n    \n    # Load and resize images\n    dataset = dataset.map(load_image, num_parallel_calls=tf.data.AUTOTUNE)\n    \n    # Apply model-specific preprocessing\n    dataset = dataset.map(preprocess_fn, num_parallel_calls=tf.data.AUTOTUNE)\n    \n    # Batch, shuffle, and prefetch for performance\n    # For the validation set, we don't need to shuffle\n    if 'train' in df.iloc[0]['image_path']:\n        dataset = dataset.shuffle(buffer_size=len(df))\n        \n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(buffer_size=tf.data.AUTOTUNE)\n    \n    return dataset\n\n# 4. Create the three distinct datasets\n#    (We'll do this just before training each model)\n#\n#    Example:\n#    train_ds_vgg16 = create_dataset(train_df, preprocess_vgg16)\n#    val_ds_vgg16 = create_dataset(val_df, preprocess_vgg16)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-01T09:32:36.576385Z","iopub.execute_input":"2025-11-01T09:32:36.576551Z","iopub.status.idle":"2025-11-01T09:32:36.584091Z","shell.execute_reply.started":"2025-11-01T09:32:36.576539Z","shell.execute_reply":"2025-11-01T09:32:36.583401Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =============================================================================\n# Model 1: VGG-16 (From Keras Applications)\n# =============================================================================\ndef create_vgg16_baseline():\n    base_model = VGG16(input_shape=IMG_SHAPE,\n                       include_top=False,\n                       weights='imagenet')\n    base_model.trainable = False # FREEZE\n    \n    inputs = layers.Input(shape=IMG_SHAPE)\n    x = base_model(inputs, training=False)\n    x = layers.GlobalAveragePooling2D()(x)\n    outputs = layers.Dense(NUM_CLASSES, activation='softmax')(x)\n    \n    model = models.Model(inputs, outputs)\n    return model\n\n# =============================================================================\n# Model 2: ResNet-50 (From Keras Applications)\n# =============================================================================\ndef create_resnet50_baseline():\n    base_model = ResNet50(input_shape=IMG_SHAPE,\n                          include_top=False,\n                          weights='imagenet')\n    base_model.trainable = False # FREEZE\n    \n    inputs = layers.Input(shape=IMG_SHAPE)\n    x = base_model(inputs, training=False)\n    x = layers.GlobalAveragePooling2D()(x)\n    outputs = layers.Dense(NUM_CLASSES, activation='softmax')(x)\n    \n    model = models.Model(inputs, outputs)\n    return model\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-01T09:32:36.584766Z","iopub.execute_input":"2025-11-01T09:32:36.585048Z","iopub.status.idle":"2025-11-01T09:32:36.599990Z","shell.execute_reply.started":"2025-11-01T09:32:36.585029Z","shell.execute_reply":"2025-11-01T09:32:36.599420Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =============================================================================\n# Model 3: AlexNet (Manually Implemented) - CORRECTED\n# =============================================================================\ndef create_alexnet_baseline():\n    \n    # 1. Define the entire AlexNet model + our new head in one stack\n    model = models.Sequential([\n        layers.Input(shape=IMG_SHAPE),\n        layers.Resizing(227, 227), # AlexNet uses 227x227\n        \n        # --- Start of \"base_model\" layers ---\n        layers.Conv2D(filters=96, kernel_size=(11,11), strides=(4,4), activation='relu'),\n        layers.BatchNormalization(),\n        layers.MaxPooling2D(pool_size=(3,3), strides=(2,2)),\n        \n        layers.Conv2D(filters=256, kernel_size=(5,5), padding='same', activation='relu'),\n        layers.BatchNormalization(),\n        layers.MaxPooling2D(pool_size=(3,3), strides=(2,2)),\n        \n        layers.Conv2D(filters=384, kernel_size=(3,3), padding='same', activation='relu'),\n        layers.Conv2D(filters=384, kernel_size=(3,3), padding='same', activation='relu'),\n        layers.Conv2D(filters=256, kernel_size=(3,3), padding='same', activation='relu'),\n        layers.MaxPooling2D(pool_size=(3,3), strides=(2,2)),\n        \n        layers.Flatten(),\n        layers.Dense(4096, activation='relu'),\n        layers.Dropout(0.5),\n        layers.Dense(4096, activation='relu'),\n        layers.Dropout(0.5),\n        # --- End of \"base_model\" layers ---\n        \n        # --- Our new classification head ---\n        layers.Dense(NUM_CLASSES, activation='softmax', name='predictions')\n    \n    ], name=\"alexnet_model\")\n    \n    # 2. FREEZE all layers *except* the last one\n    #    This follows the rule \"train only the new classification head\"\n    for layer in model.layers[:-1]:\n        layer.trainable = False\n        \n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-01T09:32:36.601301Z","iopub.execute_input":"2025-11-01T09:32:36.601538Z","iopub.status.idle":"2025-11-01T09:32:36.614259Z","shell.execute_reply.started":"2025-11-01T09:32:36.601524Z","shell.execute_reply":"2025-11-01T09:32:36.613719Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create a dictionary to store our final results for the table\nbaseline_results = {}\n\n# We need the true labels from the validation set for final scoring\ny_true = val_df['label'].values\n\n# --- 1. Train and Evaluate VGG-16 ---\nprint(\"\\n--- Training VGG-16 ---\")\nvgg16_model = create_vgg16_baseline()\nvgg16_model.compile(\n    optimizer='adam',\n    loss='sparse_categorical_crossentropy', # Use this for integer labels\n    metrics=['accuracy']  # <-- FIX: Removed problematic Keras metrics\n)\n\n# Create the VGG-16 specific datasets\ntrain_ds_vgg16 = create_dataset(train_df, preprocess_vgg16)\nval_ds_vgg16 = create_dataset(val_df, preprocess_vgg16)\n\n# Train the model\nvgg16_model.fit(\n    train_ds_vgg16,\n    epochs=5, # You can increase this, but 5 is a good start\n    validation_data=val_ds_vgg16\n)\n\n# Get predictions on the validation set\npreds_vgg16 = vgg16_model.predict(val_ds_vgg16)\ny_pred_vgg16 = np.argmax(preds_vgg16, axis=1) # Convert probabilities to class labels\n\n# Calculate and store metrics\nbaseline_results['VGG-16'] = {\n    'Accuracy': accuracy_score(y_true, y_pred_vgg16),\n    'F1 Score': f1_score(y_true, y_pred_vgg16, average='weighted'),\n    'Recall': recall_score(y_true, y_pred_vgg16, average='weighted'),\n    'Precision': precision_score(y_true, y_pred_vgg16, average='weighted', zero_division=0)\n}\n\n\n# --- 2. Train and Evaluate ResNet-50 ---\nprint(\"\\n--- Training ResNet-50 ---\")\nresnet50_model = create_resnet50_baseline()\nresnet50_model.compile(\n    optimizer='adam',\n    loss='sparse_categorical_crossentropy',\n    metrics=['accuracy']  # <-- FIX: Removed problematic Keras metrics\n)\n\n# Create the ResNet-50 specific datasets\ntrain_ds_resnet50 = create_dataset(train_df, preprocess_resnet50)\nval_ds_resnet50 = create_dataset(val_df, preprocess_resnet50)\n\n# Train the model\nresnet50_model.fit(\n    train_ds_resnet50,\n    epochs=5,\n    validation_data=val_ds_resnet50\n)\n\n# Get predictions\npreds_resnet50 = resnet50_model.predict(val_ds_resnet50)\ny_pred_resnet50 = np.argmax(preds_resnet50, axis=1)\n\n# Calculate and store metrics\nbaseline_results['ResNet-50'] = {\n    'Accuracy': accuracy_score(y_true, y_pred_resnet50),\n    'F1 Score': f1_score(y_true, y_pred_resnet50, average='weighted'),\n    'Recall': recall_score(y_true, y_pred_resnet50, average='weighted'),\n    'Precision': precision_score(y_true, y_pred_resnet50, average='weighted', zero_division=0)\n}\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-01T09:32:36.645937Z","iopub.execute_input":"2025-11-01T09:32:36.646568Z","iopub.status.idle":"2025-11-01T09:52:51.659097Z","shell.execute_reply.started":"2025-11-01T09:32:36.646545Z","shell.execute_reply":"2025-11-01T09:52:51.658503Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- 3. Train and Evaluate AlexNet ---\nprint(\"\\n--- Training AlexNet ---\")\nalexnet_model = create_alexnet_baseline()\nalexnet_model.compile(\n    optimizer='adam',\n    loss='sparse_categorical_crossentropy',\n    metrics=['accuracy']  # <-- FIX: Removed problematic Keras metrics\n)\n\n# Create the AlexNet specific datasets\ntrain_ds_alexnet = create_dataset(train_df, preprocess_alexnet)\nval_ds_alexnet = create_dataset(val_df, preprocess_alexnet)\n\n# Train the model\nalexnet_model.fit(\n    train_ds_alexnet,\n    epochs=5,\n    validation_data=val_ds_alexnet\n)\n\n# Get predictions\npreds_alexnet = alexnet_model.predict(val_ds_alexnet)\ny_pred_alexnet = np.argmax(preds_alexnet, axis=1)\n\n# Calculate and store metrics\nbaseline_results['AlexNet'] = {\n    'Accuracy': accuracy_score(y_true, y_pred_alexnet),\n    'F1 Score': f1_score(y_true, y_pred_alexnet, average='weighted'),\n    'Recall': recall_score(y_true, y_pred_alexnet, average='weighted'),\n    'Precision': precision_score(y_true, y_pred_alexnet, average='weighted', zero_division=0)\n}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-01T09:52:51.687634Z","iopub.execute_input":"2025-11-01T09:52:51.688275Z","iopub.status.idle":"2025-11-01T10:02:21.698181Z","shell.execute_reply.started":"2025-11-01T09:52:51.688246Z","shell.execute_reply":"2025-11-01T10:02:21.697416Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Convert the results dictionary to a pandas DataFrame\nresults_df = pd.DataFrame(baseline_results).T\n\n# Re-order columns to match your assignment\nresults_df = results_df[['Accuracy', 'F1 Score', 'Recall', 'Precision']]\n\nprint(\"\\n--- Baseline Model Results ---\")\nprint(results_df)\n\n# You can now copy this output into Table 1 of your assignment","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-01T10:02:21.699082Z","iopub.execute_input":"2025-11-01T10:02:21.699399Z","iopub.status.idle":"2025-11-01T10:02:21.713979Z","shell.execute_reply.started":"2025-11-01T10:02:21.699362Z","shell.execute_reply":"2025-11-01T10:02:21.713241Z"}},"outputs":[],"execution_count":null}]}