{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":113002,"databundleVersionId":13471427,"sourceType":"competition"}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import tensorflow as tf\nimport os\n\nprint(\"TensorFlow version:\", tf.__version__)\n\n# Check for TPU\ntry:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()\n    strategy = tf.distribute.TPUStrategy(tpu)\n    print(\"✅ TPU connected\")\nexcept Exception as e:\n    print(\"❌ TPU not found:\", e)\n    tpu = None\n\n# Check for GPU\ngpus = tf.config.list_physical_devices('GPU')\nif gpus:\n    try:\n        # Enable memory growth (optional but avoids errors)\n        for gpu in gpus:\n            tf.config.experimental.set_memory_growth(gpu, True)\n        strategy = tf.distribute.MirroredStrategy()\n        print(\"✅ GPU connected:\", gpus)\n    except RuntimeError as e:\n        print(\"⚠️ GPU error:\", e)\nelse:\n    print(\"❌ No GPU found. Using CPU.\")\n    strategy = tf.distribute.get_strategy()\n\nprint(\"\\n>>> Final Strategy:\", strategy)\nprint(\"Number of accelerators in sync:\", strategy.num_replicas_in_sync)\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-09-28T21:10:41.427065Z","iopub.execute_input":"2025-09-28T21:10:41.427383Z","iopub.status.idle":"2025-09-28T21:10:43.057617Z","shell.execute_reply.started":"2025-09-28T21:10:41.427361Z","shell.execute_reply":"2025-09-28T21:10:43.05683Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport tensorflow as tf\n\n# --- 1. Setup base path ---\nBASE_PATH = '/kaggle/input/grand-xray-slam-division-b/'\n\n# Confirm files\nprint(\"Files in dataset:\", os.listdir(BASE_PATH))\n\n# ✅ Use the correct CSV file\ndf = pd.read_csv(os.path.join(BASE_PATH, \"train2.csv\"))\nprint(\"CSV loaded with shape:\", df.shape)\nprint(\"Columns:\", df.columns.tolist())\n\n# --- 2. Labels ---\nLABELS = [\n    'Atelectasis', 'Cardiomegaly', 'Consolidation', 'Edema', 'Enlarged Cardiomediastinum',\n    'Fracture', 'Lung Lesion', 'Lung Opacity', 'No Finding', 'Pleural Effusion',\n    'Pleural Other', 'Pneumonia', 'Pneumothorax', 'Support Devices'\n]\n\n# --- 3. Sample a subset for quick testing ---\nsample_df = df.sample(2000, random_state=42)\n\ndef get_image_path(image_name):\n    return os.path.join(BASE_PATH, \"train2\", image_name)  # inside the train2 folder\n# ✅ Use 'Image_name' (lowercase n)\nsample_df['full_path'] = sample_df['Image_name'].apply(get_image_path)\n\n# --- 4. Build TensorFlow Data Pipeline ---\nIMG_SIZE = 224\nBATCH_SIZE = 32 * strategy.num_replicas_in_sync  # use GPU strategy\n\ndef parse_image_and_labels(file_path, labels):\n    img = tf.io.read_file(file_path)\n    img = tf.io.decode_jpeg(img, channels=3)\n    img = tf.image.resize(img, [IMG_SIZE, IMG_SIZE])\n    img = img / 255.0\n    return img, labels\n\nimage_paths = sample_df['full_path'].values\nimage_labels = sample_df[LABELS].values\n\ndataset = tf.data.Dataset.from_tensor_slices((image_paths, image_labels))\ndataset = dataset.map(parse_image_and_labels, num_parallel_calls=tf.data.AUTOTUNE)\ndataset = dataset.batch(BATCH_SIZE, drop_remainder=True).prefetch(tf.data.AUTOTUNE)\n\nprint(\"✅ Data pipeline created successfully!\")\n\n# --- 5. Inspect a batch ---\nfor images, labels in dataset.take(1):\n    print(\"Images batch shape:\", images.shape)\n    print(\"Labels batch shape:\", labels.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-28T21:10:43.0588Z","iopub.execute_input":"2025-09-28T21:10:43.05907Z","iopub.status.idle":"2025-09-28T21:10:45.033379Z","shell.execute_reply.started":"2025-09-28T21:10:43.05902Z","shell.execute_reply":"2025-09-28T21:10:45.032619Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- NEW CELL FOR SPLITTING DATA ---\n\n# Based on your logs, you have 31 batches of data (2000 sample size / 64 batch size)\nDATASET_SIZE = 31 \nTRAIN_SPLIT = int(0.8 * DATASET_SIZE) # 80% for training\n\n# It's crucial to shuffle the data before splitting\ndataset = dataset.shuffle(buffer_size=1024, seed=42)\n\ntrain_dataset = dataset.take(TRAIN_SPLIT)\nvalidation_dataset = dataset.skip(TRAIN_SPLIT)\n\nprint(f\"✅ Dataset split into {len(train_dataset)} training batches and {len(validation_dataset)} validation batches.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-28T21:10:45.03418Z","iopub.execute_input":"2025-09-28T21:10:45.034365Z","iopub.status.idle":"2025-09-28T21:10:46.82127Z","shell.execute_reply.started":"2025-09-28T21:10:45.034349Z","shell.execute_reply":"2025-09-28T21:10:46.820637Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# We must define and compile the model inside the strategy scope\n# This tells TensorFlow to use the two GPUs we have enabled\nwith strategy.scope():\n    # 1. Load the pre-trained base model\n    # We'll use EfficientNetB0, a strong and efficient model for images\n    base_model = tf.keras.applications.EfficientNetB0(\n        input_shape=(IMG_SIZE, IMG_SIZE, 3),\n        weights='imagenet',   # Load weights pre-trained on millions of internet images\n        include_top=False     # Exclude the final layer that classifies 1000 objects\n    )\n    \n    # 2. Freeze the base model\n    # This prevents the pre-trained knowledge from being erased during initial training\n    base_model.trainable = False\n    \n    # 3. Add our own custom layers on top\n    model = tf.keras.Sequential([\n        base_model,\n        tf.keras.layers.GlobalAveragePooling2D(), # A layer to reduce the feature dimensions\n        tf.keras.layers.Dense(14, activation='sigmoid') # FINAL LAYER: 14 outputs, 1 for each condition\n    ])\n    \n    # 4. Compile the model\n    model.compile(\n        optimizer='adam',\n        loss='binary_crossentropy', # The correct loss function for multi-label problems\n        metrics=[tf.keras.metrics.AUC(multi_label=True, name='auc')] # The competition's evaluation metric\n    )\n\n# Print a summary of our new model's architecture\nprint(\"✅ Model built and compiled successfully!\")\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-28T21:10:46.822626Z","iopub.execute_input":"2025-09-28T21:10:46.822854Z","iopub.status.idle":"2025-09-28T21:10:50.048042Z","shell.execute_reply.started":"2025-09-28T21:10:46.822836Z","shell.execute_reply":"2025-09-28T21:10:50.047334Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping\nimport matplotlib.pyplot as plt\n\n# 1. Configure Early Stopping\nearly_stopping = EarlyStopping(\n    monitor='val_loss',\n    patience=3,\n    restore_best_weights=True\n)\n\n# 2. Train The Model\nprint(\"🚀 Starting model training with Early Stopping...\")\nhistory = model.fit(\n    train_dataset,\n    epochs=50,\n    validation_data=validation_dataset,\n    callbacks=[early_stopping]\n)\nprint(\"\\n✅ Model training complete!\")\n\n# 3. Plot The Updated Results\nprint(\"📊 Generating training & validation history plot...\")\nplt.figure(figsize=(12, 5))\n\n# Plot AUC\nplt.subplot(1, 2, 1)\nplt.plot(history.history['auc'], label='Training AUC')\nplt.plot(history.history['val_auc'], label='Validation AUC')\nplt.title('Model AUC Over Epochs')\nplt.xlabel('Epoch')\nplt.ylabel('AUC')\nplt.legend()\n\n# Plot Loss\nplt.subplot(1, 2, 2)\nplt.plot(history.history['loss'], label='Training Loss')\nplt.plot(history.history['val_loss'], label='Validation Loss')\nplt.title('Model Loss Over Epochs')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\n\n# --- THIS IS THE CORRECTED LINE FOR KAGGLE ---\n# This saves the plot to Kaggle's output directory\nplt.savefig('/kaggle/working/training_validation_history.png', bbox_inches='tight')\n\nplt.show()\n\nprint(\"✅ Plot saved to Kaggle's output directory.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-28T21:10:50.048909Z","iopub.execute_input":"2025-09-28T21:10:50.049283Z","iopub.status.idle":"2025-09-28T21:22:28.747174Z","shell.execute_reply.started":"2025-09-28T21:10:50.049257Z","shell.execute_reply":"2025-09-28T21:22:28.746482Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- 1. Load Test Data Information ---\nprint(\"Loading test data information...\")\n# We use the sample submission file to get the list of test image names in the correct order\nsubmission_df = pd.read_csv(BASE_PATH + 'sample_submission_2.csv')\n\n# Create the full file paths for the test images\ndef get_test_image_path(image_name):\n    # Note that test images are in the 'test2' folder\n    return f\"{BASE_PATH}test2/{image_name}\"\n\nsubmission_df['full_path'] = submission_df['Image_name'].apply(get_test_image_path)\n\nprint(f\"Found {len(submission_df)} images in the test set.\")\n\n# --- 2. Create the Test Data Pipeline ---\n# This pipeline is similar to the training one, but it doesn't process labels\ndef parse_test_image(file_path):\n    img = tf.io.read_file(file_path)\n    img = tf.io.decode_jpeg(img, channels=3)\n    img = tf.image.resize(img, [IMG_SIZE, IMG_SIZE])\n    img = img / 255.0\n    return img\n\ntest_image_paths = submission_df['full_path'].values\n\n# Create a dataset of file paths, then map the parsing function\ntest_dataset = tf.data.Dataset.from_tensor_slices(test_image_paths)\ntest_dataset = test_dataset.map(parse_test_image, num_parallel_calls=tf.data.AUTOTUNE)\ntest_dataset = test_dataset.batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)\n\nprint(\"✅ Test data pipeline created successfully.\")\n\n# --- 3. Make Predictions ---\nprint(\"\\n🧠 Making predictions on the test set...\")\n# The model.predict() function will return the probabilities for each of the 14 labels\npredictions = model.predict(test_dataset)\nprint(\"✅ Predictions complete.\")\n\n# --- 4. Create and Save the Submission File ---\n# Assign the predictions to the correct label columns in our submission DataFrame\nsubmission_df[LABELS] = predictions\n\n# Drop the extra 'full_path' column we created\nsubmission_df = submission_df.drop('full_path', axis=1)\n\n# Save the final DataFrame to a submission.csv file\n# index=False is crucial to avoid an extra unwanted column\nsubmission_df.to_csv('submission.csv', index=False)\n\nprint(\"\\n✅ Submission file 'submission.csv' created successfully!\")\nprint(\"Here's a preview of your submission file:\")\nprint(submission_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-28T21:22:28.748086Z","iopub.execute_input":"2025-09-28T21:22:28.748665Z","iopub.status.idle":"2025-09-28T21:32:50.104694Z","shell.execute_reply.started":"2025-09-28T21:22:28.748636Z","shell.execute_reply":"2025-09-28T21:32:50.104054Z"}},"outputs":[],"execution_count":null}]}