{"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":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":63134,"databundleVersionId":6880857}],"dockerImageVersionId":31287,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns \nimport tensorflow as tf\nimport cv2\nfrom tensorflow import keras\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import EarlyStopping,ReduceLROnPlateau\nfrom tensorflow.keras.layers import Dense,Dropout, Activation, Flatten, Conv2D, MaxPooling2D\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.regularizers import l2\nimport os\nfrom PIL import Image\nimport re","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-03-04T06:58:46.239069Z","iopub.execute_input":"2026-03-04T06:58:46.239938Z","iopub.status.idle":"2026-03-04T06:59:13.54696Z","shell.execute_reply.started":"2026-03-04T06:58:46.239905Z","shell.execute_reply":"2026-03-04T06:59:13.54621Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"root = '/kaggle/input/anyas-gojo-revival-aerospace-enigma'\npath_to_test = '/kaggle/input/competitions/anyas-gojo-revival-aerospace-enigma/test'\npath_to_train = '/kaggle/input/competitions/anyas-gojo-revival-aerospace-enigma/train'\npath_to_res = '/kaggle/input/competitions/anyas-gojo-revival-aerospace-enigma/sample_submission.csv'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T06:59:13.548445Z","iopub.execute_input":"2026-03-04T06:59:13.548999Z","iopub.status.idle":"2026-03-04T06:59:13.552588Z","shell.execute_reply.started":"2026-03-04T06:59:13.548967Z","shell.execute_reply":"2026-03-04T06:59:13.551901Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_val_datagen = ImageDataGenerator(\n    rescale=1./255,\n    rotation_range=20,      # Degree range for random rotations\n    width_shift_range=0.2,  # Fraction of total width for random horizontal shift\n    height_shift_range=0.2, # Fraction of total height for random vertical shift\n    shear_range=0.2,        # Shear intensity (shear angle in radians)\n    zoom_range=0.2,         # Range for random zoom\n    horizontal_flip=True,   # Randomly flip inputs horizontally\n    vertical_flip=True,     # Randomly flip inputs vertically\n    fill_mode='nearest',     # Strategy for filling in newly created pixels (e.g., 'nearest')\n    validation_split=0.15,\n)\ntest_datagen = ImageDataGenerator(rescale=1./255)\nbatch_size = 32\nimage_size = (299, 299)\n\n# Training Generator\ntrain_generator = train_val_datagen.flow_from_directory(\n    path_to_train,\n    target_size=image_size,\n    batch_size=batch_size,\n    class_mode='categorical',\n    subset='training',\n    shuffle=True\n)\n\n# Validation Generator\nval_generator = train_val_datagen.flow_from_directory(\n    path_to_train,\n    target_size=image_size,\n    batch_size=batch_size,\n    class_mode='categorical',\n    subset='validation',\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T06:59:13.553582Z","iopub.execute_input":"2026-03-04T06:59:13.553872Z","iopub.status.idle":"2026-03-04T06:59:15.992772Z","shell.execute_reply.started":"2026-03-04T06:59:13.553843Z","shell.execute_reply":"2026-03-04T06:59:15.992072Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"classes = [\"commercial\", \"glider\", \"helicopter\", \"mig-29\", \"sukhoi\"]\ncounts = []\n\nfor c in classes:\n    class_path = os.path.join(path_to_train, c)\n    if os.path.exists(class_path):\n        counts.append(len(os.listdir(class_path)))\n    else:\n        counts.append(0)\n\nplt.figure(figsize=(10, 6))\nplt.bar(classes, counts, color='skyblue', edgecolor='black')\nplt.xlabel('Aircraft Type', fontsize=12)\nplt.ylabel('Number of Images', fontsize=12)\nplt.title('Frequency of Each Aircraft Label', fontsize=14)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T06:59:15.993757Z","iopub.execute_input":"2026-03-04T06:59:15.994158Z","iopub.status.idle":"2026-03-04T06:59:16.16281Z","shell.execute_reply.started":"2026-03-04T06:59:15.994126Z","shell.execute_reply":"2026-03-04T06:59:16.162091Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import random\nimport matplotlib.image as mpimg\n\ndef view_random_images():\n    images = []\n    labels = []\n    root = '/kaggle/input/competitions/anyas-gojo-revival-aerospace-enigma' \n    \n    class_list = list(train_generator.class_indices.keys())\n    \n    for i in range(20):\n        random_class_name = random.choice(class_list)\n        random_path = os.path.join(root, \"train\", random_class_name)\n        \n        all_images = os.listdir(random_path)\n        random_image_name = random.choice(all_images)\n        \n        images.append(os.path.join(random_path, random_image_name))\n        labels.append(random_class_name)\n\n    plt.figure(figsize=(20, 10))\n    for i in range(1, 21):\n        plt.subplot(4, 5, i) \n        img = mpimg.imread(images[i-1])\n        plt.imshow(img)\n        plt.title(labels[i-1])\n        plt.axis(False)\n    plt.tight_layout()\n    plt.show()\n\nview_random_images()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T06:59:16.164701Z","iopub.execute_input":"2026-03-04T06:59:16.16497Z","iopub.status.idle":"2026-03-04T06:59:18.431167Z","shell.execute_reply.started":"2026-03-04T06:59:16.164949Z","shell.execute_reply":"2026-03-04T06:59:18.430311Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def view_augmented_images(generator):\n    images, labels = next(generator)\n    \n    plt.figure(figsize=(20, 10))\n    for i in range(10):\n        plt.subplot(2, 5, i + 1)\n        plt.imshow(images[i])\n        class_idx = np.argmax(labels[i])\n        class_name = list(generator.class_indices.keys())[class_idx]\n        \n        plt.title(f\"Augmented: {class_name}\")\n        plt.axis(False)\n    plt.show()\n\nview_augmented_images(train_generator)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T06:59:18.43256Z","iopub.execute_input":"2026-03-04T06:59:18.43296Z","iopub.status.idle":"2026-03-04T06:59:19.901064Z","shell.execute_reply.started":"2026-03-04T06:59:18.432931Z","shell.execute_reply":"2026-03-04T06:59:19.900345Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.applications import Xception\nfrom tensorflow.keras.layers import GlobalAveragePooling2D\nbase_model = Xception(input_shape=(299,299,3),weights='imagenet',include_top=False)\nbase_model.trainable = False #Free the base model\nmodel = Sequential()\nmodel.add(base_model)\nmodel.add(GlobalAveragePooling2D())\nmodel.add(Dense(256,activation='relu'))\nmodel.add(Dropout(0.2))\nmodel.add(Dense(64,activation='relu'))\nmodel.add(Dropout(0.2))\nmodel.add(Dense(5,activation='softmax'))\ncallback1 = EarlyStopping(monitor='val_loss', patience=3, verbose=1, mode='auto', restore_best_weights=True)\ncallback2 = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=2, verbose=1, mode='auto', min_delta=1e-6)\n\nepochs = 15\nmodel.compile(\n    optimizer=keras.optimizers.Adam(1e-3),\n    loss=tf.keras.losses.CategoricalCrossentropy(),\n    metrics=[\"accuracy\"],\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T06:59:19.90233Z","iopub.execute_input":"2026-03-04T06:59:19.902969Z","iopub.status.idle":"2026-03-04T06:59:24.20982Z","shell.execute_reply.started":"2026-03-04T06:59:19.902926Z","shell.execute_reply":"2026-03-04T06:59:24.209046Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T06:59:24.210851Z","iopub.execute_input":"2026-03-04T06:59:24.211167Z","iopub.status.idle":"2026-03-04T06:59:24.229991Z","shell.execute_reply.started":"2026-03-04T06:59:24.211135Z","shell.execute_reply":"2026-03-04T06:59:24.229462Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history_xcep = model.fit(\n    train_generator,\n    epochs=epochs,\n    callbacks=[callback1, callback2],\n    validation_data=val_generator,\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T06:59:24.230778Z","iopub.execute_input":"2026-03-04T06:59:24.231046Z","iopub.status.idle":"2026-03-04T07:13:31.831545Z","shell.execute_reply.started":"2026-03-04T06:59:24.231008Z","shell.execute_reply":"2026-03-04T07:13:31.830676Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"acc = history_xcep.history['accuracy']\nval_acc = history_xcep.history['val_accuracy']\nloss = history_xcep.history['loss']\nval_loss = history_xcep.history['val_loss']\nepochs_range = range(len(acc))\n\nplt.figure(figsize=(15, 6))\n\n# Plot Accuracy\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Accuracy', marker='o', color='blue')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy', marker='x', color='orange')\nplt.title('Xception: Training and Validation Accuracy')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend(loc='lower right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\n# Plot Loss\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Loss', marker='o', color='red')\nplt.plot(epochs_range, val_loss, label='Validation Loss', marker='x', color='darkred')\nplt.title('Xception: Training and Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend(loc='upper right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:13:31.832706Z","iopub.execute_input":"2026-03-04T07:13:31.832991Z","iopub.status.idle":"2026-03-04T07:13:32.136483Z","shell.execute_reply.started":"2026-03-04T07:13:31.832965Z","shell.execute_reply":"2026-03-04T07:13:32.135894Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_model.trainable = True\n\nfor layer in base_model.layers[:-30]:\n    layer.trainable = False\n\nmodel.compile(\n    optimizer=keras.optimizers.Adam(1e-5), \n    loss='categorical_crossentropy',\n    metrics=[\"accuracy\"]\n)\n\nhistory_fine = model.fit(\n    train_generator,\n    epochs=15,\n    validation_data=val_generator,\n    callbacks=[callback1, callback2]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:13:32.137348Z","iopub.execute_input":"2026-03-04T07:13:32.137619Z","iopub.status.idle":"2026-03-04T07:21:29.184427Z","shell.execute_reply.started":"2026-03-04T07:13:32.13759Z","shell.execute_reply":"2026-03-04T07:21:29.1838Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"acc = history_fine.history['accuracy']\nval_acc = history_fine.history['val_accuracy']\nloss = history_fine.history['loss']\nval_loss = history_fine.history['val_loss']\nepochs_range = range(len(acc))\n\nplt.figure(figsize=(15, 6))\n\n# Plot Accuracy\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Accuracy', marker='o', color='blue')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy', marker='x', color='orange')\nplt.title('Xception: Training and Validation Accuracy')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend(loc='lower right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\n# Plot Loss\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Loss', marker='o', color='red')\nplt.plot(epochs_range, val_loss, label='Validation Loss', marker='x', color='darkred')\nplt.title('Xception: Training and Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend(loc='upper right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:21:29.18562Z","iopub.execute_input":"2026-03-04T07:21:29.186236Z","iopub.status.idle":"2026-03-04T07:21:29.497822Z","shell.execute_reply.started":"2026-03-04T07:21:29.18621Z","shell.execute_reply":"2026-03-04T07:21:29.497244Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.applications.efficientnet import preprocess_input\n\neff_train_datagen = ImageDataGenerator(\n    preprocessing_function=preprocess_input, # Use the model's native scaler\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    horizontal_flip=True,\n    vertical_flip=True,\n    fill_mode='nearest',\n    validation_split=0.15\n)\n\neff_train_gen = eff_train_datagen.flow_from_directory(\n    path_to_train,\n    target_size=(299, 299),\n    batch_size=32,\n    class_mode='categorical',\n    subset='training'\n)\n\neff_val_gen = eff_train_datagen.flow_from_directory(\n    path_to_train,\n    target_size=(299, 299),\n    batch_size=32,\n    class_mode='categorical',\n    subset='validation'\n)\nfrom tensorflow.keras.applications import EfficientNetB0\neff_base = EfficientNetB0(weights='imagenet', include_top=False, input_shape=(299,299,3))\neff_base.trainable = False\n\nmodel_eff = Sequential([\n    eff_base,\n    layers.GlobalAveragePooling2D(),\n    layers.Dense(256, activation='relu'),\n    layers.Dropout(0.3),\n    layers.Dense(5, activation='softmax')\n])\n\nmodel_eff.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:21:29.498672Z","iopub.execute_input":"2026-03-04T07:21:29.498907Z","iopub.status.idle":"2026-03-04T07:21:30.951694Z","shell.execute_reply.started":"2026-03-04T07:21:29.498885Z","shell.execute_reply":"2026-03-04T07:21:30.951156Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history_eff = model_eff.fit(\n    eff_train_gen,\n    epochs=epochs,\n    callbacks=[callback1, callback2],\n    validation_data=eff_val_gen,\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:21:30.954479Z","iopub.execute_input":"2026-03-04T07:21:30.955126Z","iopub.status.idle":"2026-03-04T07:33:33.956631Z","shell.execute_reply.started":"2026-03-04T07:21:30.9551Z","shell.execute_reply":"2026-03-04T07:33:33.956011Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"acc = history_eff.history['accuracy']\nval_acc = history_eff.history['val_accuracy']\nloss = history_eff.history['loss']\nval_loss = history_eff.history['val_loss']\nepochs_range = range(len(acc))\n\nplt.figure(figsize=(15, 6))\n\n# Plot Accuracy\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Accuracy', marker='o', color='blue')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy', marker='x', color='orange')\nplt.title('EfficientNetB0: Training and Validation Accuracy')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend(loc='lower right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\n# Plot Loss\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Loss', marker='o', color='red')\nplt.plot(epochs_range, val_loss, label='Validation Loss', marker='x', color='darkred')\nplt.title('EfficientNetB0: Training and Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend(loc='upper right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:33:33.959898Z","iopub.execute_input":"2026-03-04T07:33:33.960223Z","iopub.status.idle":"2026-03-04T07:33:34.26577Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"eff_base.trainable = True\n\nfor layer in eff_base.layers[:-20]:\n    layer.trainable = False\n\nmodel_eff.compile(\n    optimizer=keras.optimizers.Adam(1e-5),\n    loss='categorical_crossentropy',\n    metrics=['accuracy']\n)\n\nhistory_eff_fine = model_eff.fit(\n    eff_train_gen,\n    epochs=10,\n    validation_data=eff_val_gen,\n    callbacks=[callback1, callback2]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:33:34.266503Z","iopub.execute_input":"2026-03-04T07:33:34.266744Z","iopub.status.idle":"2026-03-04T07:37:31.017285Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"acc = history_eff_fine.history['accuracy']\nval_acc = history_eff_fine.history['val_accuracy']\nloss = history_eff_fine.history['loss']\nval_loss = history_eff_fine.history['val_loss']\nepochs_range = range(len(acc))\n\nplt.figure(figsize=(15, 6))\n\n# Plot Accuracy\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Accuracy', marker='o', color='blue')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy', marker='x', color='orange')\nplt.title('EfficientNetB0: Training and Validation Accuracy')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend(loc='lower right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\n# Plot Loss\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Loss', marker='o', color='red')\nplt.plot(epochs_range, val_loss, label='Validation Loss', marker='x', color='darkred')\nplt.title('EfficientNetB0: Training and Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend(loc='upper right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:37:31.018217Z","iopub.execute_input":"2026-03-04T07:37:31.018704Z","iopub.status.idle":"2026-03-04T07:37:31.327287Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"conv_datagen = ImageDataGenerator(\n    rotation_range=20,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    horizontal_flip=True,\n    validation_split=0.15\n)\n\nconv_train_gen = conv_datagen.flow_from_directory(\n    path_to_train,\n    target_size=(299, 299),\n    batch_size=32,\n    class_mode='categorical',\n    subset='training'\n)\n\nconv_val_gen = conv_datagen.flow_from_directory(\n    path_to_train,\n    target_size=(299, 299),\n    batch_size=32,\n    class_mode='categorical',\n    subset='validation'\n)\nfrom tensorflow.keras.applications import ConvNeXtTiny\n\nconv_base = ConvNeXtTiny(weights='imagenet', include_top=False, input_shape=(299, 299, 3))\nconv_base.trainable = False\n\nmodel_conv = Sequential([\n    conv_base,\n    layers.GlobalAveragePooling2D(),\n    layers.Dense(256, activation='gelu'), # ConvNeXt often uses GELU instead of ReLU\n    layers.Dropout(0.3),\n    layers.Dense(5, activation='softmax')\n])\n\nmodel_conv.compile(\n    optimizer=keras.optimizers.Adam(1e-3),\n    loss='categorical_crossentropy',\n    metrics=['accuracy']\n)\nhistory_conv = model_conv.fit(\n    conv_train_gen,\n    epochs=10,\n    validation_data=conv_val_gen,\n    callbacks=[callback1, callback2]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:37:31.328051Z","iopub.execute_input":"2026-03-04T07:37:31.328304Z","iopub.status.idle":"2026-03-04T07:46:12.838677Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"acc = history_conv.history['accuracy']\nval_acc = history_conv.history['val_accuracy']\nloss = history_conv.history['loss']\nval_loss = history_conv.history['val_loss']\nepochs_range = range(len(acc))\n\nplt.figure(figsize=(15, 6))\n\n# Plot Accuracy\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Accuracy', marker='o', color='blue')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy', marker='x', color='orange')\nplt.title('ConvNeXt: Training and Validation Accuracy')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend(loc='lower right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\n# Plot Loss\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Loss', marker='o', color='red')\nplt.plot(epochs_range, val_loss, label='Validation Loss', marker='x', color='darkred')\nplt.title('ConvNeXt: Training and Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend(loc='upper right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:46:12.839838Z","iopub.execute_input":"2026-03-04T07:46:12.840233Z","iopub.status.idle":"2026-03-04T07:46:13.129584Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"conv_base.trainable = True\n\nfor layer in conv_base.layers[:-20]:\n    layer.trainable = False\n\nmodel_conv.compile(\n    optimizer=keras.optimizers.Adam(1e-5),\n    loss='categorical_crossentropy',\n    metrics=['accuracy']\n)\n\nhistory_conv_fine = model_conv.fit(\n    conv_train_gen,\n    epochs=10,\n    validation_data=conv_val_gen,\n    callbacks=[callback1, callback2]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:46:13.13043Z","iopub.execute_input":"2026-03-04T07:46:13.130676Z","iopub.status.idle":"2026-03-04T07:55:12.187529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"acc = history_conv_fine.history['accuracy']\nval_acc = history_conv_fine.history['val_accuracy']\nloss = history_conv_fine.history['loss']\nval_loss = history_conv_fine.history['val_loss']\nepochs_range = range(len(acc))\n\nplt.figure(figsize=(15, 6))\n\n# Plot Accuracy\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Fine-tuning Accuracy', marker='o', color='blue')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy', marker='x', color='orange')\nplt.title('ConvNeXt: Training and Validation Accuracy')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend(loc='lower right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\n# Plot Loss\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Fine-tuning Loss', marker='o', color='red')\nplt.plot(epochs_range, val_loss, label='Validation Loss', marker='x', color='darkred')\nplt.title('ConvNeXt: Training and Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend(loc='upper right')\nplt.grid(True, linestyle='--', alpha=0.6)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:55:12.1885Z","iopub.execute_input":"2026-03-04T07:55:12.188734Z","iopub.status.idle":"2026-03-04T07:55:12.489621Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_dir = '/kaggle/input/competitions/anyas-gojo-revival-aerospace-enigma/test'\ntest_filenames = os.listdir(test_dir)\ntest_df = pd.DataFrame({'filename': test_filenames})\n\nprint(f\"Total test images found: {len(test_df)}\")\n\ntest_gen_xcp = ImageDataGenerator(rescale=1./255).flow_from_dataframe(\n    dataframe=test_df,\n    directory=test_dir,\n    x_col='filename',\n    y_col=None,\n    target_size=(299, 299),\n    batch_size=1,\n    class_mode=None,\n    shuffle=False\n)\n\nfrom tensorflow.keras.applications.efficientnet import preprocess_input as eff_preprocess\ntest_gen_eff = ImageDataGenerator(preprocessing_function=eff_preprocess).flow_from_dataframe(\n    dataframe=test_df,\n    directory=test_dir,\n    x_col='filename',\n    y_col=None,\n    target_size=(299, 299),\n    batch_size=1,\n    class_mode=None,\n    shuffle=False\n)\n\ntest_gen_conv = ImageDataGenerator().flow_from_dataframe(\n    dataframe=test_df,\n    directory=test_dir,\n    x_col='filename',\n    y_col=None,\n    target_size=(299, 299),\n    batch_size=1,\n    class_mode=None,\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:55:12.490528Z","iopub.execute_input":"2026-03-04T07:55:12.490794Z","iopub.status.idle":"2026-03-04T07:55:13.161842Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save_weights('xception_weights.weights.h5')\nmodel_eff.save_weights('efficientnet_weights.weights.h5')\nmodel_conv.save_weights('convnext_weights.weights.h5')\nclass_indices = train_generator.class_indices \nwith open('class_indices.json', 'w') as f:\n    json.dump(class_indices, f)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:59:33.357693Z","iopub.execute_input":"2026-03-04T07:59:33.358432Z","iopub.status.idle":"2026-03-04T07:59:35.248951Z","shell.execute_reply.started":"2026-03-04T07:59:33.358401Z","shell.execute_reply":"2026-03-04T07:59:35.24818Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import json\n\nclass_indices = train_generator.class_indices \n\n# Save the models\nmodel.save('xception_model.keras')\nmodel_eff.save('efficientnet_model.keras')\nmodel_conv.save('convnext_model.keras')\n\n# Saving the mapping to JSON\nwith open('class_indices.json', 'w') as f:\n    json.dump(class_indices, f)\n\nprint(\"Success: 3 models and class_indices.json saved.\")\nprint(f\"Mapping saved: {class_indices}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:55:13.170704Z","iopub.status.idle":"2026-03-04T07:55:13.171066Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"p_xcp = model.predict(test_gen_xcp, verbose=1)\np_eff = model_eff.predict(test_gen_eff, verbose=1)\np_conv = model_conv.predict(test_gen_conv, verbose=1)\n\n# Weighted Average Ensemble\nfinal_preds = (0.2 * p_xcp) + (0.4 * p_eff) + (0.4 * p_conv)\nfinal_indices = np.argmax(final_preds, axis=1)\n\nclass_indices = train_generator.class_indices\nlabels_map = {v: k for k, v in class_indices.items()}\nfinal_labels = [labels_map[idx] for idx in final_indices]\n\nsubmission = pd.DataFrame({\n    'image_path': test_df['filename'],\n    'Class': final_labels\n})\n\nsubmission.to_csv('submission.csv', index=False)\nprint(submission.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:55:13.17229Z","iopub.status.idle":"2026-03-04T07:55:13.172607Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_sub = pd.read_csv('/kaggle/input/competitions/anyas-gojo-revival-aerospace-enigma/sample_submission.csv')\n\npreds_dict = dict(zip(submission['image_path'], submission['Class']))\n\nsample_sub['Class'] = sample_sub['image_path'].map(preds_dict)\n\nif sample_sub['Class'].isnull().any():\n    print(\"Warning: Some images in the sample submission were not found in your predictions!\")\n\nsample_sub.to_csv('submission.csv', index=False)\nprint(\"Formatted submission saved!\")\nprint(sample_sub.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:55:13.173894Z","iopub.status.idle":"2026-03-04T07:55:13.17418Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow import keras\n\nmodel = keras.models.load_model(\"xception_model.keras\", compile=False)\n\n# Force single-input reconstruction\ninput_shape = (299, 299, 3)           # ← use your real input shape\ninputs = keras.Input(shape=input_shape)\nx = model(inputs, training=False)     # pass through → Keras rebuilds graph\nclean_model = keras.Model(inputs, x)\n\nclean_model.save(\"xception_model_fixed.keras\", save_format=\"keras_v3\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T07:55:13.175649Z","iopub.status.idle":"2026-03-04T07:55:13.175985Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}