{"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":"# Inference with my own trained weights: ResNeXt50 baseline (384 px, no TTA)\n\nThis notebook predicts the test images with **one model that I trained myself**: ResNeXt50, fold 0, 384 px, 8 epochs, plain cross-entropy (the weights from my baseline training notebook). It does not use any of the winners' released weights. Its purpose is to show what my own training achieves on the leaderboard.\n\n**Result:** Private score **0.8742** and Public score **0.8706**. The validation accuracy of the same weights on fold 0 was 0.87388, so the validation score and the leaderboard score agree closely.\n\n**How it differs from the full winning ensemble** (`Final Version Inference`, private 0.9134, public 0.9143): That notebook averages 12 models (5 ViT, 5 ResNeXt, EfficientNetB4, CropNet), while this one uses a single ResNeXt50 from one fold. A lower score is expected. I did not test how much of the gap comes from each factor.\n\n**How the code works:**\n1. **Cell 1** lists the files under `/kaggle/input` and prints the path of the `.pth` weights file.\n2. **Cell 2** builds the same `CustomResNext` structure used in training (ResNeXt50 with a 5-class final layer) and loads my weights with `load_state_dict`.\n3. Test images are resized to **384 x 384** and normalised. The size matches training, and the transform matches the validation transform in the training notebook (resize and normalise only).\n4. The model outputs a probability for each of the 5 classes, and `argmax` picks the predicted class, which is written to `submission.csv`.\n\nThe notebook runs offline and needs no internet. It was committed on GPU and submitted from its output.\n\n**Related notebooks:**\n* Training notebook for these weights (384 px, 8 epochs): https://www.kaggle.com/code/ananyaamadhursharma/cassava-leaf-disease-resnext50\n* Same weights with flip TTA, label smoothing and ensemble versions: see the other `inference-own-resnext-384-...` notebooks on my profile\n* Full winning ensemble: https://www.kaggle.com/code/ananyaamadhursharma/final-version-inference","metadata":{}},{"cell_type":"code","source":"import os\n\nprint(\"Input folders:\", os.listdir(\"/kaggle/input\"))\nprint()\nfor root, dirs, files in os.walk(\"/kaggle/input\"):\n    for f in files:\n        if f.endswith(\".pth\"):\n            print(\"WEIGHTS:\", os.path.join(root, f))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-10-14T12:26:48.190794Z","iopub.execute_input":"2026-10-14T12:26:48.19187Z","iopub.status.idle":"2026-10-14T12:27:26.556372Z","shell.execute_reply.started":"2026-10-14T12:26:48.191828Z","shell.execute_reply":"2026-10-14T12:27:26.55516Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ====================================================\n# Inference with my own trained ResNeXt50 (fold 0, 384 px)\n# ====================================================\nimport os, sys\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import DataLoader, Dataset\nfrom albumentations import Compose, Normalize, Resize\nfrom albumentations.pytorch import ToTensorV2\n\n# timm is normally preinstalled on Kaggle; these paths are a fallback\nsys.path.append('../input/pytorch-image-models/pytorch-image-models-master')\nimport timm\n\n# ---------------- settings ----------------\nWEIGHTS_PATH = \"/kaggle/input/datasets/ananyaamadhursharma/cassava-resnext-fold0-384-baseline/resnext50_32x4d_fold0_best.pth\"\nSIZE = 384      # must match the training image size\n\n# find the competition test folder (the paths differ between setups)\ncandidates = [\n    \"../input/cassava-leaf-disease-classification/test_images/\",\n    \"/kaggle/input/cassava-leaf-disease-classification/test_images/\",\n    \"/kaggle/input/competitions/cassava-leaf-disease-classification/test_images/\",\n]\nTEST_DIR = next(p for p in candidates if os.path.exists(p))\nprint(\"Using test folder:\", TEST_DIR)\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(\"Device:\", device)\n\n# ---------------- model (same structure as training) ----------------\nclass CustomResNext(nn.Module):\n    def __init__(self, model_name='resnext50_32x4d', pretrained=False):\n        super().__init__()\n        self.model = timm.create_model(model_name, pretrained=pretrained)\n        n_features = self.model.fc.in_features\n        self.model.fc = nn.Linear(n_features, 5)\n\n    def forward(self, x):\n        return self.model(x)\n\n# ---------------- dataset ----------------\nclass TestDataset(Dataset):\n    def __init__(self, files, transform=None):\n        self.files = files\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.files)\n\n    def __getitem__(self, idx):\n        image = cv2.imread(self.files[idx])\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        return self.transform(image=image)['image']\n\n# same transform as validation in training: Resize + Normalize\ntransform = Compose([\n    Resize(SIZE, SIZE),\n    Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ToTensorV2(),\n])\n\n# ---------------- load my trained weights ----------------\nmodel = CustomResNext(pretrained=False)\nstate = torch.load(WEIGHTS_PATH, map_location=\"cpu\", weights_only=False)\nmodel.load_state_dict(state['model'])\nmodel.to(device)\nmodel.eval()\nprint(\"My trained weights loaded.\")\n\n# ---------------- predict ----------------\nimage_ids = sorted(os.listdir(TEST_DIR))\nfiles = [TEST_DIR + i for i in image_ids]\nloader = DataLoader(TestDataset(files, transform), batch_size=16,\n                    shuffle=False, num_workers=2, pin_memory=True)\n\nprobs = []\nwith torch.no_grad():\n    for images in loader:\n        out = model(images.to(device))\n        probs.append(out.softmax(1).cpu().numpy())\nprobs = np.concatenate(probs)\n\n# ---------------- save submission ----------------\nsubmission = pd.DataFrame({\"image_id\": image_ids, \"label\": probs.argmax(1)})\nsubmission.to_csv(\"submission.csv\", index=False)\nprint(submission.head())\nprint(\"Rows:\", len(submission))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-14T12:27:53.029757Z","iopub.execute_input":"2026-10-14T12:27:53.030675Z","iopub.status.idle":"2026-10-14T12:28:44.853413Z","shell.execute_reply.started":"2026-10-14T12:27:53.03063Z","shell.execute_reply":"2026-10-14T12:28:44.851911Z"}},"outputs":[],"execution_count":null}]}