{"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"},{"sourceId":312126,"sourceType":"datasetVersion","datasetId":130727}],"dockerImageVersionId":31090,"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","trusted":true,"execution":{"iopub.status.busy":"2025-09-21T05:58:49.038594Z","iopub.execute_input":"2025-09-21T05:58:49.039082Z","iopub.status.idle":"2025-09-21T05:58:49.726209Z","shell.execute_reply.started":"2025-09-21T05:58:49.039059Z","shell.execute_reply":"2025-09-21T05:58:49.725135Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# CIFAR-10 | ResNet-18 (scratch) + Kaggle submission\nimport os, math, random, glob, warnings\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow.keras import layers, models, regularizers\nfrom tensorflow.keras.datasets import cifar10\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, LearningRateScheduler\nfrom tensorflow.keras.optimizers import AdamW\n\nwarnings.filterwarnings(\"ignore\")\nos.environ[\"TF_CPP_MIN_LOG_LEVEL\"] = \"2\"\n\nprint(\"TF:\", tf.__version__)\nprint(\"GPU:\", tf.config.list_physical_devices(\"GPU\"))\n\nSEED = 1337\nrandom.seed(SEED); np.random.seed(SEED); tf.random.set_seed(SEED)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T06:39:59.254226Z","iopub.execute_input":"2025-09-21T06:39:59.254789Z","iopub.status.idle":"2025-09-21T06:39:59.272900Z","shell.execute_reply.started":"2025-09-21T06:39:59.254768Z","shell.execute_reply":"2025-09-21T06:39:59.272170Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Paths / constants (Kaggle)\nDATA_DIR = \"/kaggle/input/cifar10-object-recognition-in-images-zip-file\"\nSAMPLE_SUB_PATH = os.path.join(DATA_DIR, \"sampleSubmission.csv\")\n\n# Typical locations of test images in this dataset\nTEST_DIR_CANDIDATES = [\n    os.path.join(DATA_DIR, \"train_test\"),\n    os.path.join(DATA_DIR, \"train_test\", \"test\"),\n    os.path.join(DATA_DIR, \"train_test\", \"test\", \"test\"),\n    \"test\", \"/kaggle/working/test\",  # in case you extracted elsewhere\n]\n\nCKPT_PATH = \"/kaggle/working/best_model_loss.h5\"\nprint(\"Sample sub exists:\", os.path.exists(SAMPLE_SUB_PATH))\nprint(\"Checkpoint target:\", CKPT_PATH)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T06:40:04.502747Z","iopub.execute_input":"2025-09-21T06:40:04.503020Z","iopub.status.idle":"2025-09-21T06:40:04.508618Z","shell.execute_reply.started":"2025-09-21T06:40:04.502999Z","shell.execute_reply":"2025-09-21T06:40:04.507913Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load CIFAR-10 (for training/validation)\n(x_train, y_train), (x_val, y_val) = cifar10.load_data()\nx_train = x_train.astype(\"float32\")/255.0\nx_val   = x_val.astype(\"float32\")/255.0\ny_train = to_categorical(y_train, 10)\ny_val   = to_categorical(y_val, 10)\nprint(\"Train:\", x_train.shape, y_train.shape, \"| Val:\", x_val.shape, y_val.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T06:40:23.287178Z","iopub.execute_input":"2025-09-21T06:40:23.287845Z","iopub.status.idle":"2025-09-21T06:40:26.073213Z","shell.execute_reply.started":"2025-09-21T06:40:23.287820Z","shell.execute_reply":"2025-09-21T06:40:26.072544Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ResNet-18 style building blocks + model (random init)\ndef _conv(x, f, s=1):\n    y = layers.Conv2D(f, 3, strides=s, padding=\"same\",\n                      use_bias=False, kernel_regularizer=regularizers.l2(1e-4))(x)\n    y = layers.BatchNormalization()(y)\n    return layers.Activation(\"relu\")(y)\n\ndef _resblock(x, f, down=False):\n    s = 2 if down else 1\n    y = _conv(x, f, s)\n    y = _conv(y, f, 1)\n    if down or x.shape[-1] != f:\n        x = layers.Conv2D(f, 1, strides=s, padding=\"same\",\n                          use_bias=False, kernel_regularizer=regularizers.l2(1e-4))(x)\n        x = layers.BatchNormalization()(x)\n    z = layers.add([x, y])\n    return layers.Activation(\"relu\")(z)\n\ndef build_resnet18():\n    inp = layers.Input((32, 32, 3))\n    x = _conv(inp, 64)\n    x = _resblock(x, 64); x = _resblock(x, 64)\n    x = _resblock(x, 128, down=True); x = _resblock(x, 128)\n    x = _resblock(x, 256, down=True); x = _resblock(x, 256)\n    x = _resblock(x, 512, down=True); x = _resblock(x, 512)\n    x = layers.GlobalAveragePooling2D()(x)\n    x = layers.Dropout(0.5)(x)\n    out = layers.Dense(10, activation=\"softmax\")(x)\n    return models.Model(inp, out)\n\n_tmp = build_resnet18()\nprint(\"✅ Built ResNet-18 | layers:\", len(_tmp.layers), \"| params:\", _tmp.count_params())\n_tmp.summary(); del _tmp\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T06:40:43.671601Z","iopub.execute_input":"2025-09-21T06:40:43.671879Z","iopub.status.idle":"2025-09-21T06:40:44.040791Z","shell.execute_reply.started":"2025-09-21T06:40:43.671860Z","shell.execute_reply":"2025-09-21T06:40:44.040073Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Instantiate + compile (AdamW)\nmodel = build_resnet18()\nmodel.compile(optimizer=AdamW(learning_rate=3e-4, weight_decay=1e-5, clipnorm=1.0),\n              loss=\"categorical_crossentropy\",\n              metrics=[\"accuracy\"])\nprint(\"✅ Compiled.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T06:40:59.011016Z","iopub.execute_input":"2025-09-21T06:40:59.011744Z","iopub.status.idle":"2025-09-21T06:40:59.286760Z","shell.execute_reply.started":"2025-09-21T06:40:59.011719Z","shell.execute_reply":"2025-09-21T06:40:59.286187Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Augmentation + callbacks\ndatagen = ImageDataGenerator(width_shift_range=0.1,\n                             height_shift_range=0.1,\n                             horizontal_flip=True)\ndatagen.fit(x_train)\n\ndef cosine_lr(epoch, total=60, base=3e-4):\n    return 0.5*base*(1+math.cos(math.pi*epoch/total))\n\ncheckpoint_cb = ModelCheckpoint(CKPT_PATH, monitor=\"val_loss\", save_best_only=True, verbose=1)\nearlystop_cb  = EarlyStopping(monitor=\"val_loss\", patience=12, restore_best_weights=True, verbose=1)\nlrsched_cb    = LearningRateScheduler(lambda e: cosine_lr(e))\n\nBATCH_SIZE = 128\nEPOCHS     = 60\nprint(\"✅ Callbacks ready. Saving best to:\", CKPT_PATH)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T06:41:02.418974Z","iopub.execute_input":"2025-09-21T06:41:02.419491Z","iopub.status.idle":"2025-09-21T06:41:02.634996Z","shell.execute_reply.started":"2025-09-21T06:41:02.419468Z","shell.execute_reply":"2025-09-21T06:41:02.634421Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train (skip if best checkpoint already present)\nif not os.path.exists(CKPT_PATH):\n    print(\"No checkpoint found → training...\")\n    history = model.fit(\n        datagen.flow(x_train, y_train, batch_size=BATCH_SIZE),\n        validation_data=(x_val, y_val),\n        steps_per_epoch=len(x_train)//BATCH_SIZE,\n        epochs=EPOCHS,\n        callbacks=[checkpoint_cb, earlystop_cb, lrsched_cb],\n        verbose=1\n    )\nelse:\n    print(\"Checkpoint exists → skipping training.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T06:41:07.271228Z","iopub.execute_input":"2025-09-21T06:41:07.271929Z","iopub.status.idle":"2025-09-21T06:41:07.276796Z","shell.execute_reply.started":"2025-09-21T06:41:07.271906Z","shell.execute_reply":"2025-09-21T06:41:07.276192Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 7C — Force a fresh 60-epoch log (separate model; checkpoint untouched)\nfrom tensorflow.keras.callbacks import LearningRateScheduler\nfrom tensorflow.keras.optimizers import AdamW\nimport math\n\nmodel_log = build_resnet18()\nmodel_log.compile(optimizer=AdamW(3e-4, weight_decay=1e-5, clipnorm=1.0),\n                  loss=\"categorical_crossentropy\", metrics=[\"accuracy\"])\n\ndef cosine_lr(e, total=60, base=3e-4):\n    return 0.5 * base * (1 + math.cos(math.pi * e / total))\n\nhist60 = model_log.fit(\n    datagen.flow(x_train, y_train, batch_size=BATCH_SIZE),\n    validation_data=(x_val, y_val),\n    steps_per_epoch=len(x_train)//BATCH_SIZE,\n    epochs=60,\n    callbacks=[LearningRateScheduler(lambda e: cosine_lr(e))],\n    verbose=1\n)\n\nfor e, (a, va) in enumerate(zip(hist60.history['accuracy'], hist60.history['val_accuracy']), start=1):\n    print(f\"Epoch {e:02d}/60 - accuracy: {a:.4f} - val_accuracy: {va:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T06:41:35.550835Z","iopub.execute_input":"2025-09-21T06:41:35.551320Z","iopub.status.idle":"2025-09-21T06:57:04.441696Z","shell.execute_reply.started":"2025-09-21T06:41:35.551299Z","shell.execute_reply":"2025-09-21T06:57:04.440980Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load best model (robust)\ndef load_best():\n    for p in [CKPT_PATH, \"best_model_loss.h5\", \"/kaggle/working/best_model.h5\"]:\n        if os.path.exists(p):\n            print(\"Loading:\", p); return tf.keras.models.load_model(p)\n    sm = glob.glob(\"/kaggle/working/**/saved_model.pb\", recursive=True)\n    if sm:\n        mdir = os.path.dirname(sm[0])\n        print(\"Loading SavedModel from:\", mdir)\n        return tf.keras.models.load_model(mdir)\n    raise FileNotFoundError(\"No best model found; (re)run training.\")\n\nbest_model = load_best()\nprint(\"✅ Best model loaded.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T06:27:56.052870Z","iopub.execute_input":"2025-09-21T06:27:56.053491Z","iopub.status.idle":"2025-09-21T06:27:56.487068Z","shell.execute_reply.started":"2025-09-21T06:27:56.053462Z","shell.execute_reply":"2025-09-21T06:27:56.486498Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# FAST Cell — index test images once, then create the tf.data pipeline\n\nimport os, glob, tensorflow as tf, pandas as pd, numpy as np\n\n# 1) Load IDs\nassert os.path.exists(SAMPLE_SUB_PATH), \"sampleSubmission.csv missing!\"\nsub_df  = pd.read_csv(SAMPLE_SUB_PATH)\nid_list = sub_df[\"id\"].tolist()\nprint(\"IDs to predict:\", len(id_list))\n\n# 2) Build an index {id -> path} by scanning folders once (much faster)\nindex = {}\nfor base in TEST_DIR_CANDIDATES:\n    if not os.path.isdir(base): \n        continue\n    for ext in (\"png\",\"jpg\",\"jpeg\"):\n        for p in glob.glob(os.path.join(base, f\"*.{ext}\")):\n            name = os.path.splitext(os.path.basename(p))[0]\n            if not name.isdigit(): \n                continue\n            img_id = int(name)\n            if img_id not in index:     # first hit wins\n                index[img_id] = p\nprint(\"Indexed files:\", len(index))\n\n# 3) Build the paths aligned with Kaggle ID order\nmissing = [i for i in id_list if i not in index]\nassert not missing, f\"Missing {len(missing)} ids, e.g. {missing[:5]}\"\npaths = [index[i] for i in id_list]\nprint(\"✅ Paths resolved:\", len(paths), \"| example:\", paths[0])\n\n# 4) tf.data pipeline for inference\ndef _load(path):\n    b = tf.io.read_file(path)\n    x = tf.io.decode_image(b, channels=3, expand_animations=False)\n    x = tf.image.convert_image_dtype(x, tf.float32)\n    x = tf.image.resize(x, [32, 32])\n    return x\n\nBATCH_PRED = 1024\nds = tf.data.Dataset.from_tensor_slices(paths).map(_load, num_parallel_calls=tf.data.AUTOTUNE)\nds = ds.batch(BATCH_PRED).prefetch(tf.data.AUTOTUNE)\nprint(\"✅ Test dataset ready.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T07:03:10.358494Z","iopub.execute_input":"2025-09-21T07:03:10.359011Z","iopub.status.idle":"2025-09-21T07:03:19.130939Z","shell.execute_reply.started":"2025-09-21T07:03:10.358987Z","shell.execute_reply":"2025-09-21T07:03:19.130160Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Predict → build submission.csv\nprobs = best_model.predict(ds, verbose=1)\npred  = np.argmax(probs, axis=1)\n\nclasses = [\"airplane\",\"automobile\",\"bird\",\"cat\",\"deer\",\"dog\",\"frog\",\"horse\",\"ship\",\"truck\"]\nlabels  = [classes[i] for i in pred]\n\nsubmission = pd.DataFrame({\"id\": id_list, \"label\": labels})\nsubmission.to_csv(\"submission.csv\", index=False)\n\nprint(\"📁 Saved submission.csv\")\nprint(submission.head())\nprint(\"Shape:\", submission.shape, \"| Unique IDs?:\", submission['id'].is_unique)\nprint(\"NaNs:\", submission.isna().sum().to_dict())\nprint(\"Label distribution (top):\")\nprint(submission[\"label\"].value_counts().head(10))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-21T07:03:50.380302Z","iopub.execute_input":"2025-09-21T07:03:50.380776Z","iopub.status.idle":"2025-09-21T07:15:40.501275Z","shell.execute_reply.started":"2025-09-21T07:03:50.380751Z","shell.execute_reply":"2025-09-21T07:15:40.500603Z"}},"outputs":[],"execution_count":null}]}