{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.12.12"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":13836,"databundleVersionId":1718836,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":14441936,"sourceType":"datasetVersion","datasetId":9224818}],"dockerImageVersionId":31234,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true},"papermill":{"default_parameters":{},"duration":67.01174,"end_time":"2026-01-09T04:32:41.295581","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2026-01-09T04:31:34.283841","version":"2.6.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# ===============================\n# 1) IMPORTS\n# ===============================\nimport os\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom PIL import Image\n\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\n\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nimport timm\n\nprint(\"[INFO] Imports loaded.\")\n","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.status.busy":"2026-01-09T07:05:05.572018Z","iopub.execute_input":"2026-01-09T07:05:05.572393Z","iopub.status.idle":"2026-01-09T07:05:25.853352Z","shell.execute_reply.started":"2026-01-09T07:05:05.572353Z","shell.execute_reply":"2026-01-09T07:05:25.851921Z"},"papermill":{"duration":55.904146,"end_time":"2026-01-09T04:32:34.100851","exception":false,"start_time":"2026-01-09T04:31:38.196705","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===============================\n# 2) PATHS\n# ===============================\nROOT = \"/kaggle/input/cassava-leaf-disease-classification\"\nTEST_DIR = os.path.join(ROOT, \"test_images\")\nSAMPLE_SUB = os.path.join(ROOT, \"sample_submission.csv\")\n\nWEIGHT_PATH = \"/kaggle/input/model-cv-4/best_model (3).pth\"\n\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nAMP = True\n\nprint(\"[INFO] Paths ready.\")\n","metadata":{"execution":{"iopub.status.busy":"2026-01-09T07:05:25.856230Z","iopub.execute_input":"2026-01-09T07:05:25.856542Z","iopub.status.idle":"2026-01-09T07:05:25.866917Z","shell.execute_reply.started":"2026-01-09T07:05:25.856511Z","shell.execute_reply":"2026-01-09T07:05:25.865622Z"},"papermill":{"duration":0.099124,"end_time":"2026-01-09T04:32:34.202132","exception":false,"start_time":"2026-01-09T04:32:34.103008","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===============================\n# 3) MODEL\n# ===============================\nmodel = timm.create_model(\n    \"tf_efficientnet_b4_ns\",  # NoisyStudent pretrained EfficientNet-B4\n    pretrained=False,\n    num_classes=5\n)\nmodel.to(DEVICE)\n\n\nstate = torch.load(WEIGHT_PATH, map_location=DEVICE)\nmodel.load_state_dict(state)\n\nmodel.to(DEVICE)\nmodel.eval()\n\nprint(\"✅ Model loaded successfully!\")\n","metadata":{"execution":{"iopub.status.busy":"2026-01-09T07:05:25.871888Z","iopub.execute_input":"2026-01-09T07:05:25.872330Z","iopub.status.idle":"2026-01-09T07:05:29.718241Z","shell.execute_reply.started":"2026-01-09T07:05:25.872297Z","shell.execute_reply":"2026-01-09T07:05:29.716659Z"},"papermill":{"duration":1.673513,"end_time":"2026-01-09T04:32:35.877721","exception":false,"start_time":"2026-01-09T04:32:34.204208","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"\\n[INFO] Loading weights: {WEIGHT_PATH}\")\n\nmodel.load_state_dict(\n    torch.load(WEIGHT_PATH, map_location=DEVICE)\n)\nmodel.eval()\n\nprint(\"[INFO] Model loaded successfully!\")\n","metadata":{"execution":{"iopub.status.busy":"2026-01-09T07:05:29.719464Z","iopub.execute_input":"2026-01-09T07:05:29.719767Z","iopub.status.idle":"2026-01-09T07:05:29.937384Z","shell.execute_reply.started":"2026-01-09T07:05:29.719738Z","shell.execute_reply":"2026-01-09T07:05:29.935777Z"},"papermill":{"duration":0.145882,"end_time":"2026-01-09T04:32:36.025650","exception":false,"start_time":"2026-01-09T04:32:35.879768","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===============================\n# 4) DATASET\n# ===============================\nclass CassavaTestDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        image_id = self.df.iloc[idx].image_id\n        path = os.path.join(TEST_DIR, image_id)\n\n        image = np.array(Image.open(path).convert(\"RGB\"))\n\n        if self.transform:\n            image = self.transform(image=image)[\"image\"]\n\n        return image_id, image\n","metadata":{"execution":{"iopub.status.busy":"2026-01-09T07:06:33.405185Z","iopub.execute_input":"2026-01-09T07:06:33.406297Z","iopub.status.idle":"2026-01-09T07:06:33.413312Z","shell.execute_reply.started":"2026-01-09T07:06:33.406256Z","shell.execute_reply":"2026-01-09T07:06:33.412020Z"},"papermill":{"duration":0.009236,"end_time":"2026-01-09T04:32:36.036986","exception":false,"start_time":"2026-01-09T04:32:36.027750","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===============================\n# 5) TRANSFORM (KHỚP TRAIN)\n# ===============================\ntest_tf = A.Compose([\n    A.Resize(300, 300),   # ⚠️ quan trọng\n    A.Normalize(\n        mean=(0.485, 0.456, 0.406),\n        std=(0.229, 0.224, 0.225)\n    ),\n    ToTensorV2()\n])\n","metadata":{"execution":{"iopub.status.busy":"2026-01-09T07:07:06.379444Z","iopub.execute_input":"2026-01-09T07:07:06.379923Z","iopub.status.idle":"2026-01-09T07:07:06.388176Z","shell.execute_reply.started":"2026-01-09T07:07:06.379892Z","shell.execute_reply":"2026-01-09T07:07:06.387078Z"},"papermill":{"duration":0.010346,"end_time":"2026-01-09T04:32:36.049394","exception":false,"start_time":"2026-01-09T04:32:36.039048","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===============================\n# 6) DATALOADER\n# ===============================\nsample_sub = pd.read_csv(SAMPLE_SUB)\n\ntest_dataset = CassavaTestDataset(sample_sub, test_tf)\ntest_loader = DataLoader(\n    test_dataset,\n    batch_size=64,\n    shuffle=False,\n    num_workers=2,\n    pin_memory=True\n)\n\nprint(\"[INFO] Test loader ready.\")\n","metadata":{"execution":{"iopub.status.busy":"2026-01-09T07:07:08.167572Z","iopub.execute_input":"2026-01-09T07:07:08.168499Z","iopub.status.idle":"2026-01-09T07:07:08.179224Z","shell.execute_reply.started":"2026-01-09T07:07:08.168457Z","shell.execute_reply":"2026-01-09T07:07:08.177984Z"},"papermill":{"duration":0.028018,"end_time":"2026-01-09T04:32:36.079297","exception":false,"start_time":"2026-01-09T04:32:36.051279","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===============================\n# 7) INFERENCE\n# ===============================\npreds = []\n\nwith torch.no_grad():\n    for image_ids, images in tqdm(test_loader):\n        images = images.to(DEVICE, non_blocking=True)\n\n        with torch.cuda.amp.autocast(enabled=AMP):\n            outputs = model(images)          # (B, 5)\n            predictions = outputs.argmax(1)  # (B,)\n\n        for img_id, pred in zip(image_ids, predictions.cpu().numpy()):\n            preds.append([img_id, int(pred)])\n\nprint(\"✅ Inference done!\")\n","metadata":{"execution":{"iopub.status.busy":"2026-01-09T07:07:09.968805Z","iopub.execute_input":"2026-01-09T07:07:09.970228Z","iopub.status.idle":"2026-01-09T07:07:10.641720Z","shell.execute_reply.started":"2026-01-09T07:07:09.970174Z","shell.execute_reply":"2026-01-09T07:07:10.640373Z"},"papermill":{"duration":2.160134,"end_time":"2026-01-09T04:32:38.241438","exception":false,"start_time":"2026-01-09T04:32:36.081304","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===============================\n# 8) SUBMISSION\n# ===============================\nsubmission = pd.DataFrame(preds, columns=[\"image_id\", \"label\"])\nsubmission.to_csv(\"/kaggle/working/submission.csv\", index=False)\n\nprint(\"🎯 DONE — saved to /kaggle/working/submission.csv\")\nsubmission.head()\n","metadata":{"execution":{"iopub.status.busy":"2026-01-09T07:07:15.364453Z","iopub.execute_input":"2026-01-09T07:07:15.364879Z","iopub.status.idle":"2026-01-09T07:07:15.398732Z","shell.execute_reply.started":"2026-01-09T07:07:15.364842Z","shell.execute_reply":"2026-01-09T07:07:15.397608Z"},"papermill":{"duration":0.036068,"end_time":"2026-01-09T04:32:38.280029","exception":false,"start_time":"2026-01-09T04:32:38.243961","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null}]}