{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.13.15","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# R","metadata":{}},{"cell_type":"code","source":"# 1. Install py7zr in this new notebook session\n!pip install py7zr\n\nimport os\nimport py7zr\nimport glob\n\n# 2. Find the test.7z file\ntest_7z_path = None\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        if filename == 'test.7z':\n            test_7z_path = os.path.join(dirname, filename)\n            break\n\nprint(f\"Found test.7z at: {test_7z_path}\")\n\n# 3. Extract it\nif test_7z_path:\n    with py7zr.SevenZipFile(test_7z_path, mode='r') as z:\n        z.extractall()\n    print(\"Extraction complete!\")\n    \n    # 4. Verify\n    print(f\"Number of test images: {len(glob.glob('test/*'))}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-10T13:14:17.536797Z","iopub.execute_input":"2026-10-10T13:14:17.537362Z","iopub.status.idle":"2026-10-10T13:17:54.280631Z","shell.execute_reply.started":"2026-10-10T13:14:17.537335Z","shell.execute_reply":"2026-10-10T13:17:54.279909Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, models, regularizers\nimport math\nimport numpy as np\n\n# --- Load CIFAR-10 (cached, takes seconds) ---\n(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()\nx_train = x_train.astype('float32') / 255.0\nx_test = x_test.astype('float32') / 255.0\ny_train = y_train.flatten()\ny_test = y_test.flatten()\nprint(f\"Train: {x_train.shape}, Test: {x_test.shape}\")\n\n# --- CutOut Layer (Advanced Augmentation) ---\nclass CutOut(layers.Layer):\n    def __init__(self, patch_size=8, **kwargs):\n        super().__init__(**kwargs)\n        self.patch_size = patch_size\n\n    def call(self, images, training=None):\n        if not training:\n            return images\n        shape = tf.shape(images)\n        batch_size, h, w = shape[0], shape[1], shape[2]\n        cx = tf.random.uniform([batch_size], 0, w, dtype=tf.int32)\n        cy = tf.random.uniform([batch_size], 0, h, dtype=tf.int32)\n        x = tf.range(w)\n        y = tf.range(h)\n        x1 = tf.maximum(0, cx - self.patch_size // 2)\n        x2 = tf.minimum(w, cx + self.patch_size // 2)\n        y1 = tf.maximum(0, cy - self.patch_size // 2)\n        y2 = tf.minimum(h, cy + self.patch_size // 2)\n        in_x = tf.logical_and(x[None, :] >= x1[:, None], x[None, :] < x2[:, None])  # [B, W]\n        in_y = tf.logical_and(y[None, :] >= y1[:, None], y[None, :] < y2[:, None])  # [B, H]\n        mask = tf.logical_not(in_y[:, :, None] & in_x[:, None, :])  # [B, H, W]\n        mask = tf.cast(mask, images.dtype)[:, :, :, None]           # [B, H, W, 1]\n        return images * mask\n\n# --- Custom ResNet Architecture (designed from scratch) ---\ndef residual_block(x, filters, stride=1):\n    shortcut = x\n    x = layers.Conv2D(filters, (3, 3), strides=stride, padding='same',\n                      kernel_regularizer=regularizers.l2(1e-4))(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.Activation('relu')(x)\n    x = layers.Conv2D(filters, (3, 3), strides=1, padding='same',\n                      kernel_regularizer=regularizers.l2(1e-4))(x)\n    x = layers.BatchNormalization()(x)\n    if stride != 1 or shortcut.shape[-1] != filters:\n        shortcut = layers.Conv2D(filters, (1, 1), strides=stride, padding='same')(shortcut)\n        shortcut = layers.BatchNormalization()(shortcut)\n    x = layers.Add()([x, shortcut])\n    return layers.Activation('relu')(x)\n\ndef build_model():\n    inputs = layers.Input(shape=(32, 32, 3))\n    # Augmentation only active during training\n    x = layers.RandomFlip(\"horizontal\")(inputs)\n    x = layers.RandomTranslation(0.1, 0.1)(x)\n    x = CutOut(patch_size=8)(x)\n    \n    x = layers.Conv2D(64, (3, 3), padding='same')(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.Activation('relu')(x)\n    \n    x = residual_block(x, 64, 1)\n    x = residual_block(x, 64, 1)\n    x = residual_block(x, 128, 2)\n    x = residual_block(x, 128, 1)\n    x = residual_block(x, 256, 2)\n    x = residual_block(x, 256, 1)\n    x = residual_block(x, 512, 2)\n    x = residual_block(x, 512, 1)\n    \n    x = layers.GlobalAveragePooling2D()(x)\n    x = layers.Dropout(0.4)(x)\n    outputs = layers.Dense(10, activation='softmax')(x)\n    return models.Model(inputs, outputs)\n\n# --- Warmup + Cosine Annealing Schedule ---\nclass WarmUpCosineDecay(tf.keras.optimizers.schedules.LearningRateSchedule):\n    def __init__(self, base_lr, warmup_steps, total_steps, min_lr=1e-6):\n        super().__init__()\n        self.base_lr = base_lr\n        self.warmup_steps = warmup_steps\n        self.total_steps = total_steps\n        self.min_lr = min_lr\n    def __call__(self, step):\n        step = tf.cast(step, tf.float32)\n        warmup_lr = self.base_lr * (step / self.warmup_steps)\n        progress = (step - self.warmup_steps) / (self.total_steps - self.warmup_steps)\n        cosine_lr = self.min_lr + 0.5 * (self.base_lr - self.min_lr) * (1 + tf.cos(math.pi * progress))\n        return tf.where(step < self.warmup_steps, warmup_lr, cosine_lr)\n\n# --- Setup ---\nEPOCHS = 100\nBATCH_SIZE = 128\nsteps_per_epoch = len(x_train) // BATCH_SIZE\ntotal_steps = EPOCHS * steps_per_epoch\nwarmup_steps = 5 * steps_per_epoch\n\nmodel = build_model()\nlr_schedule = WarmUpCosineDecay(base_lr=0.001, warmup_steps=warmup_steps, total_steps=total_steps)\noptimizer = tf.keras.optimizers.AdamW(learning_rate=lr_schedule, weight_decay=5e-4)\nmodel.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])\nmodel.summary()\nprint(\"\\n✅ Model, optimizer, and schedule ready. Run the next cell to train.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-10T15:10:41.184833Z","iopub.execute_input":"2026-10-10T15:10:41.18565Z","iopub.status.idle":"2026-10-10T15:10:44.351836Z","shell.execute_reply.started":"2026-10-10T15:10:41.185622Z","shell.execute_reply":"2026-10-10T15:10:44.350896Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\ntf.keras.backend.clear_session()\nmodel = build_model()  # rebuilds from random init\nlr_schedule = WarmUpCosineDecay(base_lr=0.001, warmup_steps=warmup_steps, total_steps=total_steps)\noptimizer = tf.keras.optimizers.AdamW(learning_rate=lr_schedule, weight_decay=5e-4)\nmodel.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])\nprint(\"Model reset to random weights\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-10T17:09:30.408857Z","iopub.execute_input":"2026-10-10T17:09:30.409321Z","iopub.status.idle":"2026-10-10T17:09:31.771491Z","shell.execute_reply.started":"2026-10-10T17:09:30.409294Z","shell.execute_reply":"2026-10-10T17:09:31.770662Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = model.fit(\n    x_train, y_train,\n    epochs=EPOCHS,\n    batch_size=BATCH_SIZE,\n    validation_data=(x_test, y_test),\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-10T17:09:35.644097Z","iopub.execute_input":"2026-10-10T17:09:35.644879Z","iopub.status.idle":"2026-10-10T19:14:49.735599Z","shell.execute_reply.started":"2026-10-10T17:09:35.644851Z","shell.execute_reply":"2026-10-10T19:14:49.734887Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport glob\nfrom PIL import Image\nimport tensorflow as tf\n\n# 1. Use the model already in memory (no loading needed)\n# model is already defined from your training run\n\n# 2. Get all test image paths\ntest_dir = 'test'\nimage_paths = sorted(glob.glob(os.path.join(test_dir, '*')),\n                     key=lambda x: int(os.path.splitext(os.path.basename(x))[0]))\n\nprint(f\"Found {len(image_paths)} test images\")\n\n# 3. Preprocess function\ndef load_img(path):\n    path = path.numpy().decode('utf-8')\n    img = Image.open(path).convert('RGB').resize((32, 32))\n    return np.array(img).astype('float32') / 255.0\n\n# 4. Create dataset pipeline\ntest_ds = tf.data.Dataset.from_tensor_slices(image_paths)\ntest_ds = test_ds.map(lambda x: tf.py_function(load_img, [x], tf.float32),\n                      num_parallel_calls=tf.data.AUTOTUNE).batch(256).prefetch(tf.data.AUTOTUNE)\n\n# 5. Predict\nprint(\"Predicting on 300,000 images. This will take a few minutes...\")\npreds = model.predict(test_ds)\nlabels = np.argmax(preds, axis=1)\n\n# 6. Map integers to STRING names (CRITICAL FOR KAGGLE SCORE)\nlabel_map = {0:'airplane', 1:'automobile', 2:'bird', 3:'cat', 4:'deer',\n             5:'dog', 6:'frog', 7:'horse', 8:'ship', 9:'truck'}\nnames = [label_map[l] for l in labels]\n\n# 7. Create the DataFrame and save to CSV\nids = [int(os.path.splitext(os.path.basename(p))[0]) for p in image_paths]\nsubmission = pd.DataFrame({'id': ids, 'label': names})\nsubmission.to_csv('submission.csv', index=False)\n\nprint(\"✅ submission.csv created! Check the left sidebar to download it.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-10T19:42:43.14384Z","iopub.execute_input":"2026-10-10T19:42:43.144249Z","iopub.status.idle":"2026-10-10T19:49:44.478925Z","shell.execute_reply.started":"2026-10-10T19:42:43.144222Z","shell.execute_reply":"2026-10-10T19:49:44.478085Z"}},"outputs":[],"execution_count":null},{"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\n\n# Use the kagglehub client library to attach Kaggle resources like competitions, datasets, and models to your session\n# Learn more about kagglehub: https://github.com/Kaggle/kagglehub/blob/main/README.md\n\nimport kagglehub\n# kagglehub.dataset_download('<owner>/<dataset-slug>')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-10-10T13:07:49.518258Z","iopub.execute_input":"2026-10-10T13:07:49.518585Z","iopub.status.idle":"2026-10-10T13:07:52.362308Z","shell.execute_reply.started":"2026-10-10T13:07:49.518554Z","shell.execute_reply":"2026-10-10T13:07:52.361318Z"}},"outputs":[],"execution_count":null}]}