{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":21154,"databundleVersionId":1243559,"sourceType":"competition"}],"dockerImageVersionId":30787,"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","execution":{"iopub.status.busy":"2024-11-02T17:20:24.118474Z","iopub.execute_input":"2024-11-02T17:20:24.118861Z","iopub.status.idle":"2024-11-02T17:20:25.18139Z","shell.execute_reply.started":"2024-11-02T17:20:24.118818Z","shell.execute_reply":"2024-11-02T17:20:25.180398Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom tensorflow.keras import layers\nimport os\n\nprint(\"Tensorflow version:\", tf.__version__)\nprint(\"GPU Available:\", tf.config.list_physical_devices('GPU'))","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:20:41.065356Z","iopub.execute_input":"2024-11-02T17:20:41.065872Z","iopub.status.idle":"2024-11-02T17:20:53.181179Z","shell.execute_reply.started":"2024-11-02T17:20:41.065838Z","shell.execute_reply":"2024-11-02T17:20:53.180178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Configuration\nIMAGE_SIZE = 224\nBATCH_SIZE = 32\nEPOCHS = 25\nNUM_CLASSES = 104\nAUTO = tf.data.AUTOTUNE\n\n# Dataset paths\nDATA_PATH = '/kaggle/input/tpu-getting-started/tfrecords-jpeg-224x224'\nTRAIN_FILENAMES = tf.io.gfile.glob(DATA_PATH + '/train/*.tfrec')\nVAL_FILENAMES = tf.io.gfile.glob(DATA_PATH + '/val/*.tfrec')\n\nprint(f\"Train TFRecord Files: {len(TRAIN_FILENAMES)}\")\nprint(f\"Validation TFRecord Files: {len(VAL_FILENAMES)}\")","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:21:08.075831Z","iopub.execute_input":"2024-11-02T17:21:08.07707Z","iopub.status.idle":"2024-11-02T17:21:08.093218Z","shell.execute_reply.started":"2024-11-02T17:21:08.077019Z","shell.execute_reply":"2024-11-02T17:21:08.092225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def decode_image(image_data):\n    \"\"\"Decode and preprocess the image.\"\"\"\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0  # Normalize to [0,1]\n    image = tf.image.resize(image, [IMAGE_SIZE, IMAGE_SIZE])\n    return image\n\ndef read_tfrecord(example):\n    \"\"\"Read and parse a single TFRecord example.\"\"\"\n    features = {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"class\": tf.io.FixedLenFeature([], tf.int64)\n    }\n    example = tf.io.parse_single_example(example, features)\n    image = decode_image(example['image'])\n    label = tf.cast(example['class'], tf.int32)\n    return image, label\n\ndef load_dataset(filenames, ordered=False):\n    \"\"\"Create a tf.data.Dataset from TFRecord files.\"\"\"\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO)\n    dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTO)\n    if not ordered:\n        dataset = dataset.shuffle(1024)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO)\n    return dataset","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:21:24.717279Z","iopub.execute_input":"2024-11-02T17:21:24.717635Z","iopub.status.idle":"2024-11-02T17:21:24.727502Z","shell.execute_reply.started":"2024-11-02T17:21:24.717603Z","shell.execute_reply":"2024-11-02T17:21:24.726582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_augmentation_layers():\n    \"\"\"Create data augmentation layers.\"\"\"\n    return tf.keras.Sequential([\n        layers.RandomFlip(\"horizontal\"),\n        layers.RandomRotation(0.2),\n        layers.RandomZoom(0.2),\n        layers.RandomBrightness(0.2),\n        layers.RandomContrast(0.2),\n    ])","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:21:35.508583Z","iopub.execute_input":"2024-11-02T17:21:35.509496Z","iopub.status.idle":"2024-11-02T17:21:35.514528Z","shell.execute_reply.started":"2024-11-02T17:21:35.509451Z","shell.execute_reply":"2024-11-02T17:21:35.513498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_model():\n    \"\"\"Create and compile the model.\"\"\"\n    # Base model - EfficientNetB0\n    base_model = tf.keras.applications.EfficientNetB0(\n        input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3),\n        include_top=False,\n        weights='imagenet'\n    )\n    \n    # Freeze the base model\n    base_model.trainable = False\n    \n    # Create the model\n    model = tf.keras.Sequential([\n        # Input\n        layers.Input(shape=(IMAGE_SIZE, IMAGE_SIZE, 3)),\n        \n        # Data augmentation\n        get_augmentation_layers(),\n        \n        # Base model\n        base_model,\n        \n        # Head\n        layers.GlobalAveragePooling2D(),\n        layers.BatchNormalization(),\n        layers.Dropout(0.2),\n        layers.Dense(NUM_CLASSES, activation='softmax')\n    ])\n    \n    # Compile\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n        loss='sparse_categorical_crossentropy',\n        metrics=['accuracy']\n    )\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:21:42.227696Z","iopub.execute_input":"2024-11-02T17:21:42.228524Z","iopub.status.idle":"2024-11-02T17:21:42.236444Z","shell.execute_reply.started":"2024-11-02T17:21:42.228479Z","shell.execute_reply":"2024-11-02T17:21:42.235212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_callbacks():\n    \"\"\"Define training callbacks.\"\"\"\n    return [\n        tf.keras.callbacks.EarlyStopping(\n            monitor='val_accuracy',\n            patience=3,\n            restore_best_weights=True\n        ),\n        tf.keras.callbacks.ReduceLROnPlateau(\n            monitor='val_accuracy',\n            factor=0.5,\n            patience=2,\n            verbose=1\n        ),\n        tf.keras.callbacks.ModelCheckpoint(\n            'best_model.keras',  # Changed from .h5 to .keras\n            monitor='val_accuracy',\n            save_best_only=True,\n            verbose=1\n        )\n    ]","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:23:57.544356Z","iopub.execute_input":"2024-11-02T17:23:57.545267Z","iopub.status.idle":"2024-11-02T17:23:57.550961Z","shell.execute_reply.started":"2024-11-02T17:23:57.54522Z","shell.execute_reply":"2024-11-02T17:23:57.550106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create datasets\ntrain_dataset = load_dataset(TRAIN_FILENAMES)\nvalidation_dataset = load_dataset(VAL_FILENAMES, ordered=True)\n\n# Create model\nmodel = build_model()\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:24:00.490306Z","iopub.execute_input":"2024-11-02T17:24:00.4914Z","iopub.status.idle":"2024-11-02T17:24:01.741841Z","shell.execute_reply.started":"2024-11-02T17:24:00.491351Z","shell.execute_reply":"2024-11-02T17:24:01.740656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train\nhistory = model.fit(\n    train_dataset,\n    epochs=EPOCHS,\n    validation_data=validation_dataset,\n    callbacks=get_callbacks(),\n    verbose=1\n)","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:24:06.911533Z","iopub.execute_input":"2024-11-02T17:24:06.912386Z","iopub.status.idle":"2024-11-02T17:27:06.750519Z","shell.execute_reply.started":"2024-11-02T17:24:06.912337Z","shell.execute_reply":"2024-11-02T17:27:06.749575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_training_history(history):\n    \"\"\"Plot training and validation metrics.\"\"\"\n    plt.figure(figsize=(12, 4))\n    \n    # Accuracy\n    plt.subplot(1, 2, 1)\n    plt.plot(history.history['accuracy'], label='Training Accuracy')\n    plt.plot(history.history['val_accuracy'], label='Validation Accuracy')\n    plt.title('Model Accuracy')\n    plt.xlabel('Epoch')\n    plt.ylabel('Accuracy')\n    plt.legend()\n    \n    # Loss\n    plt.subplot(1, 2, 2)\n    plt.plot(history.history['loss'], label='Training Loss')\n    plt.plot(history.history['val_loss'], label='Validation Loss')\n    plt.title('Model Loss')\n    plt.xlabel('Epoch')\n    plt.ylabel('Loss')\n    plt.legend()\n    \n    plt.tight_layout()\n    plt.show()\n\n# Plot training history\nplot_training_history(history)","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:40:34.538218Z","iopub.execute_input":"2024-11-02T17:40:34.538659Z","iopub.status.idle":"2024-11-02T17:40:35.217559Z","shell.execute_reply.started":"2024-11-02T17:40:34.538617Z","shell.execute_reply":"2024-11-02T17:40:35.216655Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def fine_tune_model(model):\n    \"\"\"Fine-tune the model by unfreezing some layers.\"\"\"\n    # Get the base model (EfficientNetB0)\n    base_model = model.layers[1]  # EfficientNetB0 is at index 1\n    print(f\"Base model found: {base_model.name}\")\n    \n    # Unfreeze the base model\n    base_model.trainable = True\n    \n    # Get total number of layers\n    total_layers = len(base_model.layers)\n    print(f\"Total layers in base model: {total_layers}\")\n    \n    # Freeze all layers except the last 30\n    for layer in base_model.layers[:-30]:\n        layer.trainable = False\n    \n    # Count trainable and non-trainable parameters\n    trainable_count = sum([tf.keras.backend.count_params(w) for w in base_model.trainable_weights])\n    non_trainable_count = sum([tf.keras.backend.count_params(w) for w in base_model.non_trainable_weights])\n    print(f'Trainable params in base model: {trainable_count:,}')\n    print(f'Non-trainable params in base model: {non_trainable_count:,}')\n    \n    # Recompile with a lower learning rate\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),\n        loss='sparse_categorical_crossentropy',\n        metrics=['accuracy']\n    )\n    \n    return model\n\n# Print model structure before fine-tuning\nprint(\"Model layers before fine-tuning:\")\nfor i, layer in enumerate(model.layers):\n    print(f\"Layer {i}: {layer.name}, Trainable: {layer.trainable}\")\n\nprint(\"\\nBefore fine-tuning:\")\nprint(\"Trainable weights:\", len(model.trainable_weights))\nprint(\"Non-trainable weights:\", len(model.non_trainable_weights))\n\n# Fine-tune the model\nmodel = fine_tune_model(model)\n\n# Print model structure after fine-tuning\nprint(\"\\nModel layers after fine-tuning:\")\nfor i, layer in enumerate(model.layers):\n    print(f\"Layer {i}: {layer.name}, Trainable: {layer.trainable}\")\n\nprint(\"\\nAfter fine-tuning:\")\nprint(\"Trainable weights:\", len(model.trainable_weights))\nprint(\"Non-trainable weights:\", len(model.non_trainable_weights))\n\n# Continue training with fine-tuning\nhistory_fine = model.fit(\n    train_dataset,\n    epochs=10,\n    validation_data=validation_dataset,\n    callbacks=get_callbacks()\n)\n\n# Plot fine-tuning results\ndef plot_fine_tuning_history(history_fine):\n    plt.figure(figsize=(12, 4))\n    \n    # Accuracy\n    plt.subplot(1, 2, 1)\n    plt.plot(history_fine.history['accuracy'], label='Training Accuracy')\n    plt.plot(history_fine.history['val_accuracy'], label='Validation Accuracy')\n    plt.title('Model Accuracy (Fine-tuning)')\n    plt.xlabel('Epoch')\n    plt.ylabel('Accuracy')\n    plt.legend()\n    \n    # Loss\n    plt.subplot(1, 2, 2)\n    plt.plot(history_fine.history['loss'], label='Training Loss')\n    plt.plot(history_fine.history['val_loss'], label='Validation Loss')\n    plt.title('Model Loss (Fine-tuning)')\n    plt.xlabel('Epoch')\n    plt.ylabel('Loss')\n    plt.legend()\n    \n    plt.tight_layout()\n    plt.show()\n\n# Plot fine-tuning history\nplot_fine_tuning_history(history_fine)","metadata":{"execution":{"iopub.status.busy":"2024-11-02T17:43:03.535802Z","iopub.execute_input":"2024-11-02T17:43:03.536791Z","iopub.status.idle":"2024-11-02T17:48:02.557226Z","shell.execute_reply.started":"2024-11-02T17:43:03.536743Z","shell.execute_reply":"2024-11-02T17:48:02.556211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_enhanced_model():\n    \"\"\"Create an enhanced model with more complexity.\"\"\"\n    # Base model - EfficientNetB0\n    base_model = tf.keras.applications.EfficientNetB0(\n        input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3),\n        include_top=False,\n        weights='imagenet'\n    )\n    \n    # Freeze the base model initially\n    base_model.trainable = False\n    \n    # Create the model with a more complex head\n    model = tf.keras.Sequential([\n        # Input\n        layers.Input(shape=(IMAGE_SIZE, IMAGE_SIZE, 3)),\n        \n        # Data augmentation\n        layers.RandomFlip(\"horizontal\"),\n        layers.RandomRotation(0.2),\n        layers.RandomZoom(0.2),\n        layers.RandomBrightness(0.2),\n        layers.RandomContrast(0.2),\n        layers.RandomTranslation(0.1, 0.1),\n        \n        # Base model\n        base_model,\n        \n        # Enhanced head\n        layers.GlobalAveragePooling2D(),\n        layers.BatchNormalization(),\n        \n        # First dense block\n        layers.Dense(512),\n        layers.BatchNormalization(),\n        layers.Activation('relu'),\n        layers.Dropout(0.5),\n        \n        # Second dense block\n        layers.Dense(256),\n        layers.BatchNormalization(),\n        layers.Activation('relu'),\n        layers.Dropout(0.3),\n        \n        # Output layer\n        layers.Dense(NUM_CLASSES, activation='softmax')\n    ])\n    \n    # Compile with a different optimizer setup\n    optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)\n    \n    model.compile(\n        optimizer=optimizer,\n        loss='sparse_categorical_crossentropy',\n        metrics=['accuracy']\n    )\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-11-02T18:04:08.311584Z","iopub.execute_input":"2024-11-02T18:04:08.312627Z","iopub.status.idle":"2024-11-02T18:04:08.322482Z","shell.execute_reply.started":"2024-11-02T18:04:08.312577Z","shell.execute_reply":"2024-11-02T18:04:08.321392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_enhanced_callbacks():\n    return [\n        # Early stopping with more patience\n        tf.keras.callbacks.EarlyStopping(\n            monitor='val_accuracy',\n            patience=5,\n            restore_best_weights=True,\n            verbose=1\n        ),\n        \n        # Learning rate reduction\n        tf.keras.callbacks.ReduceLROnPlateau(\n            monitor='val_accuracy',\n            factor=0.2,\n            patience=3,\n            min_lr=1e-6,\n            verbose=1\n        ),\n        \n        # Model checkpoint\n        tf.keras.callbacks.ModelCheckpoint(\n            'best_model.keras',\n            monitor='val_accuracy',\n            save_best_only=True,\n            verbose=1\n        ),\n        \n        # CSV logger\n        tf.keras.callbacks.CSVLogger('training_log.csv')\n    ]\n\n# Create the enhanced model\nmodel = build_enhanced_model()\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-11-02T18:04:23.393967Z","iopub.execute_input":"2024-11-02T18:04:23.394641Z","iopub.status.idle":"2024-11-02T18:04:24.627069Z","shell.execute_reply.started":"2024-11-02T18:04:23.394598Z","shell.execute_reply":"2024-11-02T18:04:24.626194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# Initial training phase (longer)\nprint(\"\\nStarting initial training phase...\")\nhistory = model.fit(\n    train_dataset,\n    epochs=30,  # Increased epochs\n    validation_data=validation_dataset,\n    callbacks=get_enhanced_callbacks(),\n    verbose=1\n)","metadata":{"execution":{"iopub.status.busy":"2024-11-02T18:04:41.123951Z","iopub.execute_input":"2024-11-02T18:04:41.12475Z","iopub.status.idle":"2024-11-02T18:11:13.87939Z","shell.execute_reply.started":"2024-11-02T18:04:41.124703Z","shell.execute_reply":"2024-11-02T18:11:13.878342Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def advanced_fine_tune_model(model):\n    \"\"\"Fine-tune the model with a more gradual approach.\"\"\"\n    # Get the base model (EfficientNetB0)\n    base_model = None\n    for layer in model.layers:\n        if isinstance(layer, tf.keras.Model):  # Find the EfficientNetB0 model\n            base_model = layer\n            break\n    \n    if base_model is None:\n        print(\"Could not find base model!\")\n        return model, []\n    \n    print(f\"Base model found: {base_model.name}\")\n    \n    # Unfreeze the base model\n    base_model.trainable = True\n    \n    # Fine-tuning strategy\n    fine_tune_phases = [\n        {'lr': 1e-4, 'epochs': 5},\n        {'lr': 5e-5, 'epochs': 5},\n        {'lr': 1e-5, 'epochs': 5}\n    ]\n    \n    histories = []\n    \n    for i, phase in enumerate(fine_tune_phases):\n        print(f\"\\nFine-tuning phase {i+1}\")\n        print(f\"Learning rate: {phase['lr']}\")\n        \n        # Recompile with new learning rate\n        model.compile(\n            optimizer=tf.keras.optimizers.Adam(learning_rate=phase['lr']),\n            loss='sparse_categorical_crossentropy',\n            metrics=['accuracy']\n        )\n        \n        # Train for this phase\n        history = model.fit(\n            train_dataset,\n            epochs=phase['epochs'],\n            validation_data=validation_dataset,\n            callbacks=[\n                tf.keras.callbacks.EarlyStopping(\n                    monitor='val_accuracy',\n                    patience=2,\n                    restore_best_weights=True\n                ),\n                tf.keras.callbacks.ReduceLROnPlateau(\n                    monitor='val_accuracy',\n                    factor=0.2,\n                    patience=1,\n                    min_lr=1e-7,\n                    verbose=1\n                ),\n                tf.keras.callbacks.ModelCheckpoint(\n                    f'best_model_phase_{i+1}.keras',\n                    monitor='val_accuracy',\n                    save_best_only=True,\n                    verbose=1\n                )\n            ]\n        )\n        \n        histories.append(history)\n    \n    return model, histories\n\n# Create the enhanced model first\ndef build_enhanced_model():\n    \"\"\"Create an enhanced model with more complexity.\"\"\"\n    # Base model - EfficientNetB0\n    base_model = tf.keras.applications.EfficientNetB0(\n        input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3),\n        include_top=False,\n        weights='imagenet'\n    )\n    \n    # Freeze the base model initially\n    base_model.trainable = False\n    \n    # Create the model with a more complex head\n    inputs = layers.Input(shape=(IMAGE_SIZE, IMAGE_SIZE, 3))\n    \n    # Data augmentation\n    x = layers.RandomFlip(\"horizontal\")(inputs)\n    x = layers.RandomRotation(0.2)(x)\n    x = layers.RandomZoom(0.2)(x)\n    x = layers.RandomBrightness(0.2)(x)\n    x = layers.RandomContrast(0.2)(x)\n    \n    # Base model\n    x = base_model(x)\n    \n    # Enhanced head\n    x = layers.GlobalAveragePooling2D()(x)\n    x = layers.BatchNormalization()(x)\n    \n    # First dense block\n    x = layers.Dense(512)(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.Activation('relu')(x)\n    x = layers.Dropout(0.5)(x)\n    \n    # Second dense block\n    x = layers.Dense(256)(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.Activation('relu')(x)\n    x = layers.Dropout(0.3)(x)\n    \n    # Output layer\n    outputs = layers.Dense(NUM_CLASSES, activation='softmax')(x)\n    \n    # Create model\n    model = tf.keras.Model(inputs, outputs)\n    \n    # Compile\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n        loss='sparse_categorical_crossentropy',\n        metrics=['accuracy']\n    )\n    \n    return model\n\n# Create and train the model\nmodel = build_enhanced_model()\nmodel.summary()\n\n# Initial training phase\nprint(\"\\nStarting initial training phase...\")\nhistory = model.fit(\n    train_dataset,\n    epochs=30,\n    validation_data=validation_dataset,\n    callbacks=get_enhanced_callbacks(),\n    verbose=1\n)\n\n# Perform advanced fine-tuning\nprint(\"\\nStarting advanced fine-tuning...\")\nmodel, fine_tune_histories = advanced_fine_tune_model(model)\n\n# Plot the comprehensive training history\nplot_comprehensive_history(history, fine_tune_histories)","metadata":{"execution":{"iopub.status.busy":"2024-11-02T18:23:40.208529Z","iopub.execute_input":"2024-11-02T18:23:40.208974Z","iopub.status.idle":"2024-11-02T19:06:44.51913Z","shell.execute_reply.started":"2024-11-02T18:23:40.208921Z","shell.execute_reply":"2024-11-02T19:06:44.517649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_comprehensive_history(initial_history, fine_tune_histories):\n    \"\"\"Plot the complete training history including initial training and fine-tuning phases.\"\"\"\n    plt.figure(figsize=(15, 5))\n    \n    # Combine all histories\n    acc = initial_history.history['accuracy']\n    val_acc = initial_history.history['val_accuracy']\n    loss = initial_history.history['loss']\n    val_loss = initial_history.history['val_loss']\n    \n    # Add markers to separate initial training and fine-tuning phases\n    phase_boundaries = [len(acc)]\n    \n    for hist in fine_tune_histories:\n        acc.extend(hist.history['accuracy'])\n        val_acc.extend(hist.history['val_accuracy'])\n        loss.extend(hist.history['loss'])\n        val_loss.extend(hist.history['val_loss'])\n        phase_boundaries.append(len(acc))\n    \n    # Plot accuracy\n    plt.subplot(1, 2, 1)\n    plt.plot(acc, label='Training Accuracy', linewidth=2)\n    plt.plot(val_acc, label='Validation Accuracy', linewidth=2)\n    \n    # Add vertical lines for phase boundaries\n    for boundary in phase_boundaries[:-1]:\n        plt.axvline(x=boundary, color='r', linestyle='--', alpha=0.3)\n    \n    plt.title('Model Accuracy Over Time')\n    plt.xlabel('Epoch')\n    plt.ylabel('Accuracy')\n    plt.legend(loc='lower right')\n    plt.grid(True, alpha=0.3)\n    \n    # Plot loss\n    plt.subplot(1, 2, 2)\n    plt.plot(loss, label='Training Loss', linewidth=2)\n    plt.plot(val_loss, label='Validation Loss', linewidth=2)\n    \n    # Add vertical lines for phase boundaries\n    for boundary in phase_boundaries[:-1]:\n        plt.axvline(x=boundary, color='r', linestyle='--', alpha=0.3)\n    \n    plt.title('Model Loss Over Time')\n    plt.xlabel('Epoch')\n    plt.ylabel('Loss')\n    plt.legend(loc='upper right')\n    plt.grid(True, alpha=0.3)\n    \n    plt.tight_layout()\n    plt.show()\n    \n    # Print summary statistics\n    print(\"\\nTraining Summary:\")\n    print(f\"Final training accuracy: {acc[-1]:.4f}\")\n    print(f\"Final validation accuracy: {val_acc[-1]:.4f}\")\n    print(f\"Best validation accuracy: {max(val_acc):.4f}\")\n    print(f\"Final training loss: {loss[-1]:.4f}\")\n    print(f\"Final validation loss: {val_loss[-1]:.4f}\")\n    print(f\"Best validation loss: {min(val_loss):.4f}\")\n\n# Now you can use this after training:\nplot_comprehensive_history(history, fine_tune_histories)\n\n# Optionally, save the training history\nimport json\n\n# Save training history to file\nhistory_dict = {\n    'initial_training': {\n        'accuracy': initial_history.history['accuracy'],\n        'val_accuracy': initial_history.history['val_accuracy'],\n        'loss': initial_history.history['loss'],\n        'val_loss': initial_history.history['val_loss']\n    },\n    'fine_tuning': []\n}\n\nfor i, hist in enumerate(fine_tune_histories):\n    history_dict['fine_tuning'].append({\n        'phase': i+1,\n        'accuracy': hist.history['accuracy'],\n        'val_accuracy': hist.history['val_accuracy'],\n        'loss': hist.history['loss'],\n        'val_loss': hist.history['val_loss']\n    })\n\nwith open('training_history.json', 'w') as f:\n    json.dump(history_dict, f)\n\nprint(\"Training history saved to 'training_history.json'\")","metadata":{"execution":{"iopub.status.busy":"2024-11-02T19:08:37.440789Z","iopub.execute_input":"2024-11-02T19:08:37.441213Z","iopub.status.idle":"2024-11-02T19:08:38.099844Z","shell.execute_reply.started":"2024-11-02T19:08:37.441148Z","shell.execute_reply":"2024-11-02T19:08:38.098555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}