{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"}],"dockerImageVersionId":31234,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Import Library","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport torch\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import StandardScaler\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision.transforms as transforms\nimport torchvision.models as models\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nimport joblib","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:29:36.368758Z","iopub.execute_input":"2025-12-26T04:29:36.369770Z","iopub.status.idle":"2025-12-26T04:29:45.509224Z","shell.execute_reply.started":"2025-12-26T04:29:36.369743Z","shell.execute_reply":"2025-12-26T04:29:45.508609Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Prepare Dataset","metadata":{}},{"cell_type":"markdown","source":"### Define Dataset","metadata":{}},{"cell_type":"code","source":"class ImageDataset(Dataset):\n    def __init__(self, df, transform, scaler):\n        self.samples = list(df.itertuples(index=False))\n        self.image_dir = \"/kaggle/input/csiro-biomass\"\n        self.targets = ['Dry_Clover_g', 'Dry_Dead_g', 'Dry_Green_g', 'Dry_Total_g', 'GDM_g']\n        self.transform = transform\n        self.scaler = scaler\n\n    def __len__(self):\n        return len(self.samples)\n\n    def __getitem__(self, idx):\n        row = self.samples[idx]\n\n        img_path = os.path.join(self.image_dir, row.image_path)\n        image = Image.open(img_path).convert(\"RGB\")\n        image = self.transform(image)\n\n        target = torch.tensor([getattr(row, t) for t in self.targets], dtype=torch.float32)\n        target = torch.tensor(self.scaler.transform([target.numpy()])[0], dtype=torch.float32)\n\n        return image, target","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:29:45.509903Z","iopub.execute_input":"2025-12-26T04:29:45.510237Z","iopub.status.idle":"2025-12-26T04:29:45.516116Z","shell.execute_reply.started":"2025-12-26T04:29:45.510217Z","shell.execute_reply":"2025-12-26T04:29:45.515265Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Make Transform","metadata":{}},{"cell_type":"code","source":"transform = transforms.Compose([\n        transforms.Resize((512, 512)),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=(0.485,0.456,0.406),\n                             std=(0.229,0.224,0.225)),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:29:45.518123Z","iopub.execute_input":"2025-12-26T04:29:45.518478Z","iopub.status.idle":"2025-12-26T04:29:45.533308Z","shell.execute_reply.started":"2025-12-26T04:29:45.518456Z","shell.execute_reply":"2025-12-26T04:29:45.532632Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Load csv File","metadata":{}},{"cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/csiro-biomass/train.csv\")\ndf = df[[\"image_path\", \"target_name\", \"target\"]]\ndf = df.pivot_table(index=[\"image_path\"],columns='target_name',values=\"target\").reset_index()\n\ndf_train, df_val = train_test_split(df, test_size=0.2, random_state=42, shuffle=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:29:45.533934Z","iopub.execute_input":"2025-12-26T04:29:45.534211Z","iopub.status.idle":"2025-12-26T04:29:45.589579Z","shell.execute_reply.started":"2025-12-26T04:29:45.534194Z","shell.execute_reply":"2025-12-26T04:29:45.589070Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Make Scaler","metadata":{}},{"cell_type":"code","source":"scaler = StandardScaler()\ntargets=['Dry_Clover_g', 'Dry_Dead_g', 'Dry_Green_g', 'Dry_Total_g', 'GDM_g']\nscaler.fit(df_train[targets].values)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:29:45.590281Z","iopub.execute_input":"2025-12-26T04:29:45.590512Z","iopub.status.idle":"2025-12-26T04:29:45.601793Z","shell.execute_reply.started":"2025-12-26T04:29:45.590483Z","shell.execute_reply":"2025-12-26T04:29:45.601155Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Make DataLoader for Training","metadata":{}},{"cell_type":"code","source":"batch_size = 16\n\ntrain_dataset = ImageDataset(df_train, transform, scaler)\nval_dataset = ImageDataset(df_val, transform, scaler)\n\ntrain_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_dataloader = DataLoader(val_dataset,batch_size=batch_size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:29:45.602540Z","iopub.execute_input":"2025-12-26T04:29:45.602809Z","iopub.status.idle":"2025-12-26T04:29:45.610014Z","shell.execute_reply.started":"2025-12-26T04:29:45.602780Z","shell.execute_reply":"2025-12-26T04:29:45.609411Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Define Model","metadata":{}},{"cell_type":"code","source":"class BiomassModel(nn.Module):\n    def __init__(self, pretrained=True):\n        super(BiomassModel, self).__init__()\n        if pretrained:\n            weights = models.ConvNeXt_Tiny_Weights.DEFAULT\n            model = models.convnext_tiny(weights=weights)\n        else:\n            model = models.convnext_tiny(weights=None)\n        self.model = model.features\n        \n        self.head = nn.Sequential(\n            nn.Linear(768, 512),             \n            nn.Dropout(0.1),     \n\n            nn.Linear(512, 128),                 \n            nn.Dropout(0.1),     \n\n            nn.Linear(128, 5)\n        )\n        \n    def forward(self, images):\n        x = self.model(images)\n        x = x.mean(dim=(2,3))\n        return self.head(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:29:45.610744Z","iopub.execute_input":"2025-12-26T04:29:45.611050Z","iopub.status.idle":"2025-12-26T04:29:45.623524Z","shell.execute_reply.started":"2025-12-26T04:29:45.611018Z","shell.execute_reply":"2025-12-26T04:29:45.622859Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Training","metadata":{}},{"cell_type":"markdown","source":"### Define Parameters","metadata":{}},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\nmodel = BiomassModel()\nmodel.to(device)\n\nlr = 1e-4\noptimizer = optim.Adam(model.parameters(), lr=lr)\ncriterion = nn.MSELoss()\nepochs = 20","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:29:45.624218Z","iopub.execute_input":"2025-12-26T04:29:45.624458Z","iopub.status.idle":"2025-12-26T04:29:47.179069Z","shell.execute_reply.started":"2025-12-26T04:29:45.624436Z","shell.execute_reply":"2025-12-26T04:29:47.178477Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Do Train","metadata":{}},{"cell_type":"code","source":"min_loss = np.inf\nbest_model = model\nfor epoch in range(epochs):\n    model.train()\n    train_loss = 0.0\n\n    for data, label in train_dataloader:\n        data = data.to(device)\n        label = label.to(device)\n\n        preds = model(data)\n        loss = criterion(preds, label)\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        train_loss += loss.item()\n\n    train_loss_res = train_loss / len(train_dataloader)\n\n\n    model.eval()\n    test_loss = 0.0\n\n    with torch.no_grad():\n        for data, label in val_dataloader:\n            data = data.to(device)\n            label = label.to(device)\n\n            preds = model(data)\n            loss = criterion(preds, label)\n            test_loss += loss.item()\n\n    test_loss_res = test_loss / len(val_dataloader)\n\n    print(f\"epoch{epoch+1} | train_loss:{train_loss_res:.4f} | test_loss:{test_loss_res:.4f}\")\n\n    if min_loss >= test_loss_res:\n        print(f'best model (epoch{epoch+1}) | loss {test_loss_res}\\n')\n        min_loss = test_loss_res\n        best_model=model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:29:47.181141Z","iopub.execute_input":"2025-12-26T04:29:47.181364Z","iopub.status.idle":"2025-12-26T04:46:26.530984Z","shell.execute_reply.started":"2025-12-26T04:29:47.181331Z","shell.execute_reply":"2025-12-26T04:46:26.530343Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Save Results","metadata":{}},{"cell_type":"markdown","source":"### save best model","metadata":{}},{"cell_type":"code","source":"torch.save(best_model.state_dict(), \"model.pth\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:46:26.531858Z","iopub.execute_input":"2025-12-26T04:46:26.532480Z","iopub.status.idle":"2025-12-26T04:46:26.667168Z","shell.execute_reply.started":"2025-12-26T04:46:26.532457Z","shell.execute_reply":"2025-12-26T04:46:26.666492Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### save scaler","metadata":{}},{"cell_type":"code","source":"joblib.dump(scaler, 'scaler.joblib')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-26T04:46:26.668027Z","iopub.execute_input":"2025-12-26T04:46:26.668300Z","iopub.status.idle":"2025-12-26T04:46:26.674493Z","shell.execute_reply.started":"2025-12-26T04:46:26.668276Z","shell.execute_reply":"2025-12-26T04:46:26.673757Z"}},"outputs":[],"execution_count":null}]}