{"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":3649,"databundleVersionId":46718,"sourceType":"competition"}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install py7zr --quiet","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-05T18:09:04.360789Z","iopub.execute_input":"2025-10-05T18:09:04.361052Z","iopub.status.idle":"2025-10-05T18:09:07.415666Z","shell.execute_reply.started":"2025-10-05T18:09:04.361029Z","shell.execute_reply":"2025-10-05T18:09:07.414735Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os, math, random, warnings\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers, models, regularizers\nfrom tensorflow.keras.datasets import cifar10\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, Callback\nfrom tensorflow.keras.optimizers import AdamW\nimport tensorflow_probability as tfp\n\nwarnings.filterwarnings(\"ignore\")\nprint(\"TensorFlow:\", tf.__version__)\nprint(\"GPUs Available:\", tf.config.list_physical_devices('GPU'))\n\n# Reproducibility\nSEED = 42\nrandom.seed(SEED)\nnp.random.seed(SEED)\ntf.random.set_seed(SEED)\n\n# Paths\nDATA_PATH = \"/kaggle/input/cifar10-object-recognition-in-images-zip-file\"\nSUBMISSION_TEMPLATE = os.path.join(DATA_PATH, \"sampleSubmission.csv\")\nBEST_MODEL_PATH = \"/kaggle/working/best_custom_rescnn.weights.h5\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T18:09:07.417107Z","iopub.execute_input":"2025-10-05T18:09:07.417418Z","iopub.status.idle":"2025-10-05T18:09:11.723150Z","shell.execute_reply.started":"2025-10-05T18:09:07.417377Z","shell.execute_reply":"2025-10-05T18:09:11.722451Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"(x_train, y_train), (x_val, y_val) = cifar10.load_data()\n\nx_train = x_train.astype(\"float32\") / 255.0\nx_val = x_val.astype(\"float32\") / 255.0\n\ny_train = to_categorical(y_train, 10)\ny_val = to_categorical(y_val, 10)\n\nprint(\"Train:\", x_train.shape, y_train.shape)\nprint(\"Val:\", x_val.shape, y_val.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T18:09:11.723914Z","iopub.execute_input":"2025-10-05T18:09:11.724524Z","iopub.status.idle":"2025-10-05T18:09:14.499646Z","shell.execute_reply.started":"2025-10-05T18:09:11.724496Z","shell.execute_reply":"2025-10-05T18:09:14.498849Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def conv_bn_relu(x, filters, kernel_size=3, stride=1):\n    x = layers.Conv2D(filters, kernel_size, strides=stride, padding=\"same\",\n                      use_bias=False, kernel_regularizer=regularizers.l2(1e-4))(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n    return x\n\ndef residual_block(x, filters, downsample=False):\n    stride = 2 if downsample else 1\n    shortcut = x\n    y = conv_bn_relu(x, filters, stride=stride)\n    y = layers.Conv2D(filters, 3, padding=\"same\", use_bias=False,\n                      kernel_regularizer=regularizers.l2(1e-4))(y)\n    y = layers.BatchNormalization()(y)\n\n    if downsample or x.shape[-1] != filters:\n        shortcut = layers.Conv2D(filters, 1, strides=stride, padding=\"same\",\n                                 use_bias=False, kernel_regularizer=regularizers.l2(1e-4))(shortcut)\n        shortcut = layers.BatchNormalization()(shortcut)\n\n    out = layers.add([shortcut, y])\n    return layers.ReLU()(out)\n\ndef build_custom_rescnn(input_shape=(32, 32, 3), num_classes=10):\n    inputs = keras.Input(shape=input_shape)\n    x = conv_bn_relu(inputs, 64)\n    x = residual_block(x, 64)\n    x = residual_block(x, 128, downsample=True)\n    x = residual_block(x, 128)\n    x = residual_block(x, 256, downsample=True)\n    x = residual_block(x, 256)\n    x = layers.GlobalAveragePooling2D()(x)\n    x = layers.Dropout(0.5)(x)\n    outputs = layers.Dense(num_classes, activation=\"softmax\")(x)\n    return keras.Model(inputs, outputs)\n\nmodel = build_custom_rescnn()\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T18:09:14.501119Z","iopub.execute_input":"2025-10-05T18:09:14.501516Z","iopub.status.idle":"2025-10-05T18:09:15.804661Z","shell.execute_reply.started":"2025-10-05T18:09:14.501496Z","shell.execute_reply":"2025-10-05T18:09:15.804071Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class WarmupCosine(tf.keras.optimizers.schedules.LearningRateSchedule):\n    def __init__(self, base_lr, total_steps, warmup_steps, min_lr=1e-6):\n        super().__init__()\n        self.base_lr = base_lr\n        self.total_steps = total_steps\n        self.warmup_steps = warmup_steps\n        self.min_lr = min_lr\n\n    def __call__(self, step):\n        step = tf.cast(step, tf.float32)\n        warmup_lr = self.min_lr + (self.base_lr - self.min_lr) * (step / self.warmup_steps)\n        cosine_lr = self.min_lr + 0.5 * (self.base_lr - self.min_lr) * (\n            1 + tf.cos(math.pi * (step - self.warmup_steps) / (self.total_steps - self.warmup_steps))\n        )\n        return tf.cond(step < self.warmup_steps, lambda: warmup_lr, lambda: cosine_lr)\n\nEPOCHS = 400\nBATCH_SIZE = 128\nsteps_per_epoch = x_train.shape[0] // BATCH_SIZE\ntotal_steps = EPOCHS * steps_per_epoch\nwarmup_steps = int(0.1 * total_steps)\n\nlr_schedule = WarmupCosine(base_lr=3e-4, total_steps=total_steps, warmup_steps=warmup_steps)\noptimizer = AdamW(learning_rate=lr_schedule, weight_decay=1e-5)\nmodel.compile(optimizer=optimizer, loss=\"categorical_crossentropy\", metrics=[\"accuracy\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T18:09:15.805315Z","iopub.execute_input":"2025-10-05T18:09:15.805504Z","iopub.status.idle":"2025-10-05T18:09:15.819434Z","shell.execute_reply.started":"2025-10-05T18:09:15.805489Z","shell.execute_reply":"2025-10-05T18:09:15.818814Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"AUTO = tf.data.AUTOTUNE\n\n# --- Safe Cutout ---\ndef cutout(image, size=8):\n    h, w, c = image.shape\n    y = tf.random.uniform([], 0, h, tf.int32)\n    x = tf.random.uniform([], 0, w, tf.int32)\n    y1 = tf.clip_by_value(y - size // 2, 0, h)\n    y2 = tf.clip_by_value(y + size // 2, 0, h)\n    x1 = tf.clip_by_value(x - size // 2, 0, w)\n    x2 = tf.clip_by_value(x + size // 2, 0, w)\n\n    # Create mask by cropping and padding\n    mask = tf.pad(\n        tf.zeros((y2 - y1, x2 - x1, c)),\n        [[y1, h - y2], [x1, w - x2], [0, 0]],\n        constant_values=1.0\n    )\n    return image * mask\n\n# --- Safe CutMix ---\ndef cutmix(images, labels, alpha=1.0):\n    batch_size = tf.shape(images)[0]\n    index = tf.random.shuffle(tf.range(batch_size))\n    shuffled_images = tf.gather(images, index)\n    shuffled_labels = tf.gather(labels, index)\n\n    # Sample lambda (convert to float32 for TensorFlow math)\n    lam = tf.cast(tfp.distributions.Beta(alpha, alpha).sample([]), tf.float32)\n\n    r_x = tf.random.uniform([], 0, 32, tf.int32)\n    r_y = tf.random.uniform([], 0, 32, tf.int32)\n    r_w = tf.cast(32 * tf.sqrt(1 - lam), tf.int32)\n    r_h = tf.cast(32 * tf.sqrt(1 - lam), tf.int32)\n    x1 = tf.clip_by_value(r_x - r_w // 2, 0, 32)\n    y1 = tf.clip_by_value(r_y - r_h // 2, 0, 32)\n    x2 = tf.clip_by_value(r_x + r_w // 2, 0, 32)\n    y2 = tf.clip_by_value(r_y + r_h // 2, 0, 32)\n\n    pad_left = x1\n    pad_top = y1\n    pad_right = 32 - x2\n    pad_bottom = 32 - y2\n\n    patch = shuffled_images[:, y1:y2, x1:x2, :]\n    patch = tf.pad(patch, [[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]])\n    mask = tf.cast(tf.not_equal(patch, 0.0), tf.float32)\n\n    images = images * (1 - mask) + patch\n    labels = lam * tf.cast(labels, tf.float32) + (1 - lam) * tf.cast(shuffled_labels, tf.float32)\n    return images, labels\n\n# --- Augmentation pipeline ---\ndef augment(image, label):\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_brightness(image, 0.1)\n    image = cutout(image)\n    return image, label\n    \ndef augment_batch(images, labels):\n    images, labels = cutmix(images, labels)\n    return images, labels\n# --- Dataset build ---\ntrain_ds = (tf.data.Dataset.from_tensor_slices((x_train, y_train))\n            .shuffle(10000)\n            .map(augment, num_parallel_calls=AUTO)\n            .batch(BATCH_SIZE)\n            .map(augment_batch, num_parallel_calls=AUTO)\n            .prefetch(AUTO))\n\nval_ds = (tf.data.Dataset.from_tensor_slices((x_val, y_val))\n          .batch(BATCH_SIZE)\n          .prefetch(AUTO))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T18:09:15.820066Z","iopub.execute_input":"2025-10-05T18:09:15.820295Z","iopub.status.idle":"2025-10-05T18:09:19.806997Z","shell.execute_reply.started":"2025-10-05T18:09:15.820264Z","shell.execute_reply":"2025-10-05T18:09:19.806425Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ckpt = keras.callbacks.ModelCheckpoint(\n    BEST_MODEL_PATH,\n    monitor=\"val_accuracy\",\n    mode=\"max\",\n    save_best_only=True,\n    verbose=1,\n    save_weights_only=True \n)\nearly = EarlyStopping(monitor=\"val_accuracy\", patience=50,\n                      restore_best_weights=True, verbose=1)\n\nhistory = model.fit(\n    train_ds,\n    validation_data=val_ds,\n    epochs=EPOCHS,\n    callbacks=[ckpt, early],\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T18:09:19.807750Z","iopub.execute_input":"2025-10-05T18:09:19.807966Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_acc = max(history.history[\"val_accuracy\"])\nprint(f\"Best Validation Accuracy: {val_acc:.4f}\")\n\nif val_acc >= 0.942:\n    print(\"🏆 Expected Grade: 6/6 (Excellent)\")\nelif val_acc >= 0.931:\n    print(\"🎯 Expected Grade: 5/6 (Great)\")\nelif val_acc >= 0.921:\n    print(\"✅ Expected Grade: 4/6 (Strong)\")\nelif val_acc >= 0.911:\n    print(\"⚙️ Expected Grade: 3/6 (Good)\")\nelif val_acc >= 0.901:\n    print(\"📈 Expected Grade: 2/6 (Fair)\")\nelif val_acc >= 0.88:\n    print(\"🧩 Expected Grade: 1/6 (Passable)\")\nelse:\n    print(\"❌ Expected Grade: 0/6 (Needs Improvement)\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T19:55:07.752191Z","iopub.execute_input":"2025-10-05T19:55:07.752732Z","iopub.status.idle":"2025-10-05T19:55:07.757947Z","shell.execute_reply.started":"2025-10-05T19:55:07.752710Z","shell.execute_reply":"2025-10-05T19:55:07.757049Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport py7zr\nimport pandas as pd\nimport tensorflow as tf\n\nprint(\"✅ Loading best model architecture and weights...\")\nbest_model = build_custom_rescnn()  # same function you used to define your model\nbest_model.load_weights(BEST_MODEL_PATH)\nprint(\"✅ Weights loaded successfully!\")\n\n# --- Step 1: Extract archives if necessary ---\ninput_dir = \"/kaggle/input/cifar-10\"\nextract_dir = \"./extracted_data\"\n\nos.makedirs(extract_dir, exist_ok=True)\n\nfor fname in [\"train.7z\", \"test.7z\"]:\n    archive_path = os.path.join(input_dir, fname)\n    if os.path.exists(archive_path):\n        print(f\"📦 Extracting {fname} ...\")\n        with py7zr.SevenZipFile(archive_path, mode='r') as z:\n            z.extractall(path=extract_dir)\n    else:\n        print(f\"⚠️ Archive not found: {archive_path}\")\n\n# --- Step 2: Find test directory automatically ---\npossible_test_dirs = [\n    os.path.join(extract_dir, \"test\"),\n    os.path.join(extract_dir, \"train_test/test\"),\n    os.path.join(extract_dir, \"train_test/test/test\"),\n]\n\ntest_dir = None\nfor d in possible_test_dirs:\n    if os.path.exists(d) and len(os.listdir(d)) > 0:\n        test_dir = d\n        break\n\nif test_dir is None:\n    raise FileNotFoundError(\"❌ Could not find test directory after extraction!\")\n\nprint(f\"✅ Using test directory: {test_dir}\")\n\n# --- Step 3: Locate submission template ---\npossible_templates = [\n    os.path.join(input_dir, \"sampleSubmission.csv\"),\n    \"/kaggle/input/cifar10-object-recognition-in-images-zip-file/sampleSubmission.csv\"\n]\nsubmission_template = next((p for p in possible_templates if os.path.exists(p)), None)\n\nif submission_template is None:\n    raise FileNotFoundError(\"❌ sampleSubmission.csv not found!\")\nprint(f\"✅ Found submission template: {submission_template}\")\n\n# --- Step 4: Gather image paths ---\npaths = sorted([\n    os.path.join(test_dir, f)\n    for f in os.listdir(test_dir)\n    if f.endswith(\".png\")\n])\nif len(paths) == 0:\n    raise FileNotFoundError(f\"❌ No .png files found in {test_dir}\")\nprint(f\"✅ Found {len(paths)} test images.\")\n\n# --- Step 5: Preprocess and predict ---\ndef preprocess_img(path):\n    img = tf.io.read_file(path)\n    img = tf.io.decode_image(img, channels=3, expand_animations=False)\n    img = tf.image.resize(img, [32, 32])\n    return tf.cast(img, tf.float32) / 255.0\n\nAUTO = tf.data.AUTOTUNE\ntest_ds = (tf.data.Dataset.from_tensor_slices(paths)\n           .map(preprocess_img, num_parallel_calls=AUTO)\n           .batch(1024)\n           .prefetch(AUTO))\n\nprint(\"🚀 Running inference ...\")\npreds = best_model.predict(test_ds, verbose=1)\npred_classes = tf.argmax(preds, axis=1).numpy()\n\n# --- Step 6: Prepare submission ---\nlabels = [\"airplane\", \"automobile\", \"bird\", \"cat\", \"deer\",\n          \"dog\", \"frog\", \"horse\", \"ship\", \"truck\"]\n\npred_labels = [labels[i] for i in pred_classes]\nids = [os.path.splitext(os.path.basename(p))[0] for p in paths]\n\nsubmission = pd.DataFrame({\"id\": ids, \"label\": pred_labels})\nsubmission.to_csv(\"submission.csv\", index=False)\n\nprint(\"✅ submission.csv generated successfully!\")\nprint(submission.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-05T19:55:16.560793Z","iopub.execute_input":"2025-10-05T19:55:16.561044Z","iopub.status.idle":"2025-10-05T19:58:11.340739Z","shell.execute_reply.started":"2025-10-05T19:55:16.561028Z","shell.execute_reply":"2025-10-05T19:58:11.340011Z"}},"outputs":[],"execution_count":null}]}