{"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":"none","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset, DataLoader, random_split\nfrom torchvision import transforms\nimport pandas as pd\nimport numpy as np\nimport os\nfrom PIL import Image\nimport matplotlib.pyplot as plt","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:08:30.278135Z","iopub.execute_input":"2025-11-06T06:08:30.278410Z","iopub.status.idle":"2025-11-06T06:08:42.530047Z","shell.execute_reply.started":"2025-11-06T06:08:30.278388Z","shell.execute_reply":"2025-11-06T06:08:42.529033Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CSIRODataset(Dataset):\n    def __init__(self, csv_file, root_dir, transform=None, is_test=False):\n        \"\"\"\n        Dataset for CSIRO Image2Biomass competition.\n\n        Args:\n            csv_file (str): Path to the train/test CSV file.\n            root_dir (str): Root directory where images are stored.\n            transform (callable, optional): Optional transform to be applied on an image.\n            is_test (bool): If True, dataset is for test data (no targets).\n        \"\"\"\n        self.df = pd.read_csv(csv_file)\n        self.root_dir = root_dir\n        self.transform = transform\n        self.is_test = is_test\n\n        if not self.is_test:\n            self.df = self.df.pivot_table(\n                index=[\"image_path\", \"Sampling_Date\", \"State\", \"Species\", \"Pre_GSHH_NDVI\", \"Height_Ave_cm\"],\n                columns=\"target_name\",\n                values=\"target\"\n            ).reset_index()\n            \n            self.target_cols = [\"Dry_Clover_g\", \"Dry_Dead_g\", \"Dry_Green_g\", \"Dry_Total_g\", \"GDM_g\"]\n        else:\n            self.df = self.df.drop_duplicates(subset=\"image_path\").reset_index(drop=True)\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        img_path = os.path.join(self.root_dir, self.df.iloc[idx][\"image_path\"])\n        image = Image.open(img_path).convert(\"RGB\")\n\n        if self.transform:\n            image = self.transform(image)\n\n        if self.is_test:\n            sample_id = self.df.iloc[idx][\"image_path\"].split(\"/\")[-1].split(\".\")[0]\n            target_name = self.df.iloc[idx][\"target_name\"]\n            return image, sample_id, target_name\n\n        ndvi = torch.tensor(self.df.iloc[idx][\"Pre_GSHH_NDVI\"], dtype=torch.float32)\n        height = torch.tensor(self.df.iloc[idx][\"Height_Ave_cm\"], dtype=torch.float32)\n\n        state = self.df.iloc[idx][\"State\"]\n        species = self.df.iloc[idx][\"Species\"]          \n\n        y = torch.tensor(self.df.loc[idx, self.target_cols].values.astype(\"float32\"))\n\n        return {\n            \"image\": image,\n            \"ndvi\": ndvi,\n            \"height\": height,\n            \"state\": state,\n            \"species\": species,\n            \"target\": y,\n        }","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:16.824654Z","iopub.execute_input":"2025-11-06T06:09:16.824979Z","iopub.status.idle":"2025-11-06T06:09:16.836900Z","shell.execute_reply.started":"2025-11-06T06:09:16.824955Z","shell.execute_reply":"2025-11-06T06:09:16.835941Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# train_transform = transforms.Compose(\n#     [\n#         transforms.RandomResizedCrop(224),\n#         transforms.RandomHorizontalFlip(p=0.5),\n#         transforms.ToTensor(),\n#         transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n#     ]\n# )\n# test_transform = transforms.Compose(\n#     [\n#         transforms.RandomResizedCrop(224),\n#         transforms.ToTensor(),\n#         transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n#     ]\n# )\n\nfrom torchvision import transforms\nfrom PIL import ImageFilter\n\ntrain_transform = transforms.Compose([\n    transforms.RandomResizedCrop(224, scale=(0.8, 1.0)),\n    \n    transforms.RandomHorizontalFlip(p=0.5),\n    transforms.RandomVerticalFlip(p=0.5),\n    \n    transforms.RandomRotation(degrees=(0, 360)),\n    \n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.05),\n    \n    transforms.RandomApply([transforms.GaussianBlur(kernel_size=3)], p=0.2),\n    transforms.RandomApply([transforms.Lambda(lambda x: x.filter(ImageFilter.UnsharpMask(radius=2, percent=150)))], p=0.2),\n\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                         std=[0.229, 0.224, 0.225]),\n])\n\ntest_transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                         std=[0.229, 0.224, 0.225]),\n])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:17.037195Z","iopub.execute_input":"2025-11-06T06:09:17.037979Z","iopub.status.idle":"2025-11-06T06:09:17.043620Z","shell.execute_reply.started":"2025-11-06T06:09:17.037951Z","shell.execute_reply":"2025-11-06T06:09:17.042610Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_path = \"/kaggle/input/csiro-biomass/train.csv\"\ntest_path = \"/kaggle/input/csiro-biomass/test.csv\"\ntrain_dir = \"/kaggle/input/csiro-biomass/\"\ntest_dir = \"/kaggle/input/csiro-biomass/\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:17.275090Z","iopub.execute_input":"2025-11-06T06:09:17.275754Z","iopub.status.idle":"2025-11-06T06:09:17.280095Z","shell.execute_reply.started":"2025-11-06T06:09:17.275725Z","shell.execute_reply":"2025-11-06T06:09:17.279189Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_ds = CSIRODataset(csv_file=train_path, root_dir=train_dir, transform=train_transform)\ntest_ds = CSIRODataset(csv_file=test_path, root_dir=test_dir, transform=test_transform, is_test=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:17.765944Z","iopub.execute_input":"2025-11-06T06:09:17.766418Z","iopub.status.idle":"2025-11-06T06:09:17.847181Z","shell.execute_reply.started":"2025-11-06T06:09:17.766392Z","shell.execute_reply":"2025-11-06T06:09:17.846297Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_size = int(0.8 * len(train_ds))\nval_size = len(train_ds) - train_size\n\ntrain_data, val_data = random_split(train_ds, [train_size, val_size])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:20.151140Z","iopub.execute_input":"2025-11-06T06:09:20.151827Z","iopub.status.idle":"2025-11-06T06:09:20.159117Z","shell.execute_reply.started":"2025-11-06T06:09:20.151799Z","shell.execute_reply":"2025-11-06T06:09:20.158312Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_loader = DataLoader(train_data, batch_size = 32, shuffle=True)\nval_loader = DataLoader(val_data, batch_size = 32, shuffle=False)\ntest_loader = DataLoader(test_ds, batch_size = 32, shuffle=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:20.442197Z","iopub.execute_input":"2025-11-06T06:09:20.442537Z","iopub.status.idle":"2025-11-06T06:09:20.447921Z","shell.execute_reply.started":"2025-11-06T06:09:20.442483Z","shell.execute_reply":"2025-11-06T06:09:20.446965Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_0 = train_ds[0]\nprint(\"Label (Numeric):\", data_0[\"target\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:20.775724Z","iopub.execute_input":"2025-11-06T06:09:20.776268Z","iopub.status.idle":"2025-11-06T06:09:21.007079Z","shell.execute_reply.started":"2025-11-06T06:09:20.776232Z","shell.execute_reply":"2025-11-06T06:09:21.006231Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_iter = iter(train_loader)\ndata_r = next(data_iter)\nimages = data_r[\"image\"]\nlabels = data_r[\"target\"]\n\nimage = images[0].numpy().transpose((1, 2, 0))\nmean = [0.485, 0.456, 0.406]\nstd = [0.229, 0.224, 0.225]\nimage = std * image + mean\nimage = image.clip(0, 1)\n\nplt.imshow(image)\nplt.title(f\"Label: {labels[0]}\")\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:21.816273Z","iopub.execute_input":"2025-11-06T06:09:21.816614Z","iopub.status.idle":"2025-11-06T06:09:25.406346Z","shell.execute_reply.started":"2025-11-06T06:09:21.816591Z","shell.execute_reply":"2025-11-06T06:09:25.405368Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\nfrom torchvision import models\n\nclass CSIRORegressor(nn.Module):\n    def __init__(self, base_model='resnet18', pretrained=False, num_outputs=1):\n        super().__init__()\n        self.base_model = base_model.lower()\n\n        # -------------------------\n        # 🔸 ResNet\n        # -------------------------\n        if self.base_model == 'resnet18':\n            self.backbone = models.resnet18(pretrained=pretrained)\n            in_features = self.backbone.fc.in_features\n            self.backbone.fc = nn.Linear(in_features, num_outputs)\n\n        elif self.base_model == 'resnet50':\n            self.backbone = models.resnet50(pretrained=pretrained)\n            in_features = self.backbone.fc.in_features\n            self.backbone.fc = nn.Linear(in_features, num_outputs)\n\n        # -------------------------\n        # 🔸 EfficientNet\n        # -------------------------\n        elif self.base_model == 'efficientnet_b0':\n            self.backbone = models.efficientnet_b0(pretrained=pretrained)\n            in_features = self.backbone.classifier[1].in_features\n            self.backbone.classifier[1] = nn.Linear(in_features, num_outputs)\n\n        elif self.base_model == 'efficientnet_b4':\n            self.backbone = models.efficientnet_b4(pretrained=pretrained)\n            in_features = self.backbone.classifier[1].in_features\n            self.backbone.classifier[1] = nn.Linear(in_features, num_outputs)\n\n        # -------------------------\n        # 🔸 ConvNeXt\n        # -------------------------\n        elif self.base_model == 'convnext_tiny':\n            self.backbone = models.convnext_tiny(pretrained=pretrained)\n            in_features = self.backbone.classifier[2].in_features\n            self.backbone.classifier[2] = nn.Linear(in_features, num_outputs)\n\n        elif self.base_model == 'convnext_base':\n            self.backbone = models.convnext_base(pretrained=pretrained)\n            in_features = self.backbone.classifier[2].in_features\n            self.backbone.classifier[2] = nn.Linear(in_features, num_outputs)\n\n        # -------------------------\n        # 🔸 ViT (Vision Transformer)\n        # -------------------------\n        elif self.base_model == 'vit_b_16':\n            self.backbone = models.vit_b_16(pretrained=pretrained)\n            in_features = self.backbone.heads.head.in_features\n            self.backbone.heads.head = nn.Linear(in_features, num_outputs)\n\n        # -------------------------\n        # 🔸 DenseNet\n        # -------------------------\n        elif self.base_model == 'densenet121':\n            self.backbone = models.densenet121(pretrained=pretrained)\n            in_features = self.backbone.classifier.in_features\n            self.backbone.classifier = nn.Linear(in_features, num_outputs)\n\n        else:\n            raise ValueError(f\"❌ Unknown base model: {self.base_model}\")\n\n    def forward(self, x):\n        out = self.backbone(x)\n        return out.squeeze(1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:25.407910Z","iopub.execute_input":"2025-11-06T06:09:25.408242Z","iopub.status.idle":"2025-11-06T06:09:25.424669Z","shell.execute_reply.started":"2025-11-06T06:09:25.408215Z","shell.execute_reply":"2025-11-06T06:09:25.423569Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T06:09:25.425573Z","iopub.execute_input":"2025-11-06T06:09:25.425906Z","iopub.status.idle":"2025-11-06T06:09:25.450646Z","shell.execute_reply.started":"2025-11-06T06:09:25.425880Z","shell.execute_reply":"2025-11-06T06:09:25.449557Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = CSIRORegressor(base_model='efficientnet_b0', pretrained=False, num_outputs=5)\nmodel = model.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T08:22:17.217896Z","iopub.execute_input":"2025-11-06T08:22:17.218218Z","iopub.status.idle":"2025-11-06T08:22:17.342948Z","shell.execute_reply.started":"2025-11-06T08:22:17.218197Z","shell.execute_reply":"2025-11-06T08:22:17.341868Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.optim as optim\nfrom sklearn.metrics import r2_score","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T08:22:17.512266Z","iopub.execute_input":"2025-11-06T08:22:17.512690Z","iopub.status.idle":"2025-11-06T08:22:17.517772Z","shell.execute_reply.started":"2025-11-06T08:22:17.512666Z","shell.execute_reply":"2025-11-06T08:22:17.516903Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"criterion = nn.MSELoss()\noptimizer = optim.Adam(model.parameters(), lr=4e-4)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T08:22:17.731764Z","iopub.execute_input":"2025-11-06T08:22:17.732125Z","iopub.status.idle":"2025-11-06T08:22:17.740022Z","shell.execute_reply.started":"2025-11-06T08:22:17.732098Z","shell.execute_reply":"2025-11-06T08:22:17.739169Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# weights = {\n#     \"Dry_Green_g\": 0.1,\n#     \"Dry_Dead_g\": 0.1,\n#     \"Dry_Clover_g\": 0.1,\n#     \"GDM_g\": 0.2,\n#     \"Dry_Total_g\": 0.5\n# }\nweights = {\n    \"Dry_Clover_g\": 0.1,\n    \"Dry_Dead_g\": 0.1,\n    \"Dry_Green_g\": 0.1,\n    \"Dry_Total_g\": 0.5,\n    \"GDM_g\": 0.2\n}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T08:28:56.979109Z","iopub.execute_input":"2025-11-06T08:28:56.979812Z","iopub.status.idle":"2025-11-06T08:28:56.984401Z","shell.execute_reply.started":"2025-11-06T08:28:56.979783Z","shell.execute_reply":"2025-11-06T08:28:56.983550Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"target_names = [\"Dry_Clover_g\", \"Dry_Dead_g\", \"Dry_Green_g\", \"Dry_Total_g\", \"GDM_g\"]\n# [\"Dry_Green_g\",\"Dry_Dead_g\",\"Dry_Clover_g\",\"GDM_g\",\"Dry_Total_g\"]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T08:28:57.829196Z","iopub.execute_input":"2025-11-06T08:28:57.829545Z","iopub.status.idle":"2025-11-06T08:28:57.834142Z","shell.execute_reply.started":"2025-11-06T08:28:57.829522Z","shell.execute_reply":"2025-11-06T08:28:57.833055Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# def weighted_r2(y_true, y_pred):\n#     \"\"\"\n#     Weighted R² for multi-target regression.\n\n#     y_true, y_pred: torch tensors, shape = [num_samples, num_targets]\n#     weights: dict, mapping target names to their weights\n#     \"\"\"\n#     y_true = y_true.detach().cpu().numpy()\n#     y_pred = y_pred.detach().cpu().numpy()\n\n#     w_col = np.array([weights[name] for name in target_names])\n\n#     ss_res = np.sum(((y_true - y_pred)**2) * w_col[np.newaxis, :])\n    \n#     y_mean = np.sum(y_true * w_col[np.newaxis, :], axis=0) / np.sum(w_col)\n    \n#     ss_tot = np.sum(((y_true - y_mean[np.newaxis, :])**2) * w_col[np.newaxis, :])\n\n#     return 1 - ss_res / ss_tot\n\n\nlabels = [\"Dry_Clover_g\", \"Dry_Dead_g\", \"Dry_Green_g\", \"Dry_Total_g\", \"GDM_g\"]\n\ndef weighted_r2(y_true, y_pred) -> float:\n    \"\"\"\n    Weighted R² metric for CSIRO Image2Biomass competition.\n\n    Args:\n        y_true, y_pred: torch tensors of shape [num_samples, 5]\n\n    Returns:\n        float: weighted R² score\n    \"\"\"\n    # Convert to numpy\n    y_true = y_true.detach().cpu().numpy()\n    y_pred = y_pred.detach().cpu().numpy()\n\n    # Weighted mean of targets\n    y_weighted = 0\n    for l, label in enumerate(labels):\n        y_weighted += y_true[:, l].mean() * weights[label]\n\n    # Compute weighted SS_res and SS_tot\n    ss_res = 0\n    ss_tot = 0\n    for l, label in enumerate(labels):\n        ss_res += ((y_true[:, l] - y_pred[:, l])**2).mean() * weights[label]\n        ss_tot += ((y_true[:, l] - y_weighted)**2).mean() * weights[label]\n\n    return 1 - ss_res / ss_tot\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T08:44:09.262134Z","iopub.execute_input":"2025-11-06T08:44:09.262452Z","iopub.status.idle":"2025-11-06T08:44:09.271613Z","shell.execute_reply.started":"2025-11-06T08:44:09.262429Z","shell.execute_reply":"2025-11-06T08:44:09.270467Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import mean_squared_error, mean_absolute_error\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\nnum_epochs = 150\n\nfor epoch in range(num_epochs):\n    # -------------------------\n    # 🔹 Training\n    # -------------------------\n    model.train()\n    train_running_loss = 0.0\n    train_preds = []\n    train_targets = []\n    for batch in train_loader:\n        images = batch['image'].to(device)\n        targets = batch['target'].to(device)\n\n        optimizer.zero_grad()\n        outputs = model(images)\n        loss = criterion(outputs, targets)\n        loss.backward()\n        optimizer.step()\n\n        train_running_loss += loss.item() * images.size(0)\n        train_preds.append(outputs)\n        train_targets.append(targets)\n\n    train_loss = train_running_loss / len(train_loader.dataset)\n    train_preds = torch.cat(train_preds, dim=0)\n    train_targets = torch.cat(train_targets, dim=0)\n\n    train_r2 = weighted_r2(train_targets, train_preds)\n    train_mse = mean_squared_error(train_targets.detach().cpu().numpy(), train_preds.detach().cpu().numpy())\n    train_mae = mean_absolute_error(train_targets.detach().cpu().numpy(), train_preds.detach().cpu().numpy())\n\n    # -------------------------\n    # 🔹 Validation\n    # -------------------------\n    model.eval()\n    val_running_loss = 0.0\n    val_preds = []\n    val_targets = []\n    with torch.no_grad():\n        for batch in val_loader:\n            images = batch['image'].to(device)\n            targets = batch['target'].to(device)\n\n            outputs = model(images)\n            loss = criterion(outputs, targets)\n            val_running_loss += loss.item() * images.size(0)\n\n            val_preds.append(outputs)\n            val_targets.append(targets)\n\n    val_loss = val_running_loss / len(val_loader.dataset)\n    val_preds = torch.cat(val_preds, dim=0)\n    val_targets = torch.cat(val_targets, dim=0)\n\n    val_r2 = weighted_r2(val_targets, val_preds)\n    val_mse = mean_squared_error(val_targets.detach().cpu().numpy(), val_preds.detach().cpu().numpy())\n    val_mae = mean_absolute_error(val_targets.detach().cpu().numpy(), val_preds.detach().cpu().numpy())\n\n    # -------------------------\n    # 🔹 Print metrics\n    # -------------------------\n    print(f\"Epoch [{epoch+1}/{num_epochs}]\")\n    print(f\"  Train Loss: {train_loss:.4f}, R²: {train_r2:.4f}, MSE: {train_mse:.4f}, MAE: {train_mae:.4f}\")\n    print(f\"  Val   Loss: {val_loss:.4f}, R²: {val_r2:.4f}, MSE: {val_mse:.4f}, MAE: {val_mae:.4f}\")\n    print(\"-\"*60)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-06T08:44:09.947618Z","iopub.execute_input":"2025-11-06T08:44:09.948288Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.eval()\nall_preds = []\nsample_ids = []\n\nwith torch.no_grad():\n    for batch in test_loader:\n        images = batch[0].to(device)\n        batch_ids = batch[1]\n        outputs = model(images)\n        outputs = outputs.cpu().numpy()\n        \n        for i, sid in enumerate(batch_ids):\n            for j, tname in enumerate(target_names):\n                all_preds.append({\n                    \"sample_id\": f\"{sid}__{tname}\",\n                    \"target\": float(outputs[i,j])\n                })\n\nsubmission = pd.DataFrame(all_preds)\nsubmission.to_csv(\"submission.csv\", index=False)\nprint(\"✅ Submission saved: submission.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T13:49:25.781903Z","iopub.execute_input":"2025-11-04T13:49:25.782293Z","iopub.status.idle":"2025-11-04T13:49:25.958123Z","shell.execute_reply.started":"2025-11-04T13:49:25.782256Z","shell.execute_reply":"2025-11-04T13:49:25.956321Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}