{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"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","execution":{"iopub.status.busy":"2023-08-31T15:58:22.880855Z","iopub.execute_input":"2023-08-31T15:58:22.881393Z","iopub.status.idle":"2023-08-31T15:58:23.228678Z","shell.execute_reply.started":"2023-08-31T15:58:22.88135Z","shell.execute_reply":"2023-08-31T15:58:23.227724Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from pathlib import Path\nimport shutil","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:23.230963Z","iopub.execute_input":"2023-08-31T15:58:23.231642Z","iopub.status.idle":"2023-08-31T15:58:23.23626Z","shell.execute_reply.started":"2023-08-31T15:58:23.231607Z","shell.execute_reply":"2023-08-31T15:58:23.235109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Creat work dir","metadata":{}},{"cell_type":"code","source":"!mkdir data\n\n!mkdir data/train\n!mkdir data/test\n\n!mkdir data/train/beneign\n!mkdir data/train/malignant\n!mkdir data/train/normal\n\n!mkdir data/test/beneign\n!mkdir data/test/malignant\n!mkdir data/test/normal\n\ntrain_beneign_path = Path(\"/kaggle/input/bioverse-hackathon-a/train/beneign\")\ntrain_beneign_path = sorted(list(map(str, list(train_beneign_path.glob(\"*/*.png\")))))\nval_beneign_path = train_beneign_path[-28:]\ntrain_beneign_path = train_beneign_path[:-28]\n\ntrain_malignant_path = Path(\"/kaggle/input/bioverse-hackathon-a/train/malignant\")\ntrain_malignant_path = sorted(list(map(str, list(train_malignant_path.glob(\"*/*.png\")))))\nval_malignant_path = train_beneign_path[-20:]\ntrain_malignant_path = train_malignant_path[:-20]\n\n\ntrain_normal_path = Path(\"/kaggle/input/bioverse-hackathon-a/train/normal\")\ntrain_normal_path = sorted(list(map(str, list(train_normal_path.glob(\"*/*.png\")))))\nval_normal_path = train_normal_path[-28:]\ntrain_normal_path = train_normal_path[:-28]\n\ntrain_b_path = \"/kaggle/working/data/train/beneign\"\ntrain_m_path = \"/kaggle/working/data/train/malignant\"\ntrain_n_path = \"/kaggle/working/data/train/normal\"\n\nval_b_path = \"/kaggle/working/data/test/beneign\"\nval_m_path = \"/kaggle/working/data/test/malignant\"\nval_n_path = \"/kaggle/working/data/test/normal\"\n\ncounter = 0\nfor img in train_beneign_path:\n    shutil.copy(img, f\"{train_b_path}/b_{counter}.png\")\n    counter += 1 \ncounter = 0\nfor img in val_beneign_path:\n    shutil.copy(img, f\"{val_b_path}/b_{counter}.png\")\n    counter += 1\n    \ncounter = 0\nfor img in train_malignant_path:\n    shutil.copy(img, f\"{train_m_path}/m_{counter}.png\")\n    counter += 1\ncounter = 0\nfor img in val_malignant_path:\n    shutil.copy(img, f\"{val_m_path}/m_{counter}.png\")\n    counter += 1\n    \ncounter = 0\nfor img in train_normal_path:\n    shutil.copy(img, f\"{train_n_path}/n_{counter}.png\")\n    counter += 1\ncounter = 0\nfor img in val_normal_path:\n    shutil.copy(img, f\"{val_n_path}/n_{counter}.png\")\n    counter += 1","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:23.239925Z","iopub.execute_input":"2023-08-31T15:58:23.240228Z","iopub.status.idle":"2023-08-31T15:58:39.061813Z","shell.execute_reply.started":"2023-08-31T15:58:23.240176Z","shell.execute_reply":"2023-08-31T15:58:39.060524Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install easyfsl -q","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:39.063779Z","iopub.execute_input":"2023-08-31T15:58:39.064169Z","iopub.status.idle":"2023-08-31T15:58:52.615045Z","shell.execute_reply.started":"2023-08-31T15:58:39.064131Z","shell.execute_reply":"2023-08-31T15:58:52.613691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nfrom torch import nn, optim\nfrom torch.utils.data import DataLoader\nfrom torchvision.datasets import ImageFolder\nfrom torchvision import transforms\nfrom torchvision.datasets import Omniglot\nfrom torchvision.models import resnet18\nfrom tqdm import tqdm\n\nfrom easyfsl.samplers import TaskSampler\nfrom easyfsl.utils import plot_images, sliding_average","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:52.619973Z","iopub.execute_input":"2023-08-31T15:58:52.620306Z","iopub.status.idle":"2023-08-31T15:58:56.304305Z","shell.execute_reply.started":"2023-08-31T15:58:52.620274Z","shell.execute_reply":"2023-08-31T15:58:56.303328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Taining pipline","metadata":{}},{"cell_type":"code","source":"INPUT_HEIGHT = INPUT_WIDTH = 224\ntrain_path = \"/kaggle/working/data/train\"\nval_path = \"/kaggle/working/data/test\"\n\nN_WAY = 3 # Number of classes in a task\nN_SHOT = 10 # Number of images per class in the support set\nN_QUERY = 10 # Number of images per class in the query set\nN_EVALUATION_TASKS = 100\n\nN_TRAINING_EPISODES = 500\nN_VALIDATION_TASKS = 100\n","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:56.306034Z","iopub.execute_input":"2023-08-31T15:58:56.306722Z","iopub.status.idle":"2023-08-31T15:58:56.312363Z","shell.execute_reply.started":"2023-08-31T15:58:56.306688Z","shell.execute_reply":"2023-08-31T15:58:56.311252Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"resize = transforms.Resize(size=(INPUT_HEIGHT, INPUT_WIDTH)) #Resize\nvFlip = transforms.RandomVerticalFlip(p=0.25) #Vertical Flip\nrotate = transforms.RandomRotation(degrees=15) # RandomRotation\ntrainTransforms = transforms.Compose([resize, vFlip, rotate, transforms.ToTensor()])\nvalTransforms = transforms.Compose([resize, transforms.ToTensor()])","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:56.313893Z","iopub.execute_input":"2023-08-31T15:58:56.314684Z","iopub.status.idle":"2023-08-31T15:58:56.32644Z","shell.execute_reply.started":"2023-08-31T15:58:56.314651Z","shell.execute_reply":"2023-08-31T15:58:56.325338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainDataset = ImageFolder(root=train_path, transform=trainTransforms)\nvalDataset = ImageFolder(root=val_path,  transform=valTransforms)\nprint(\"[INFO] training dataset contains {} samples...\".format(len(trainDataset)))\nprint(\"[INFO] validation dataset contains {} samples...\".format(len(valDataset)))","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:56.328119Z","iopub.execute_input":"2023-08-31T15:58:56.328546Z","iopub.status.idle":"2023-08-31T15:58:56.344936Z","shell.execute_reply.started":"2023-08-31T15:58:56.328513Z","shell.execute_reply":"2023-08-31T15:58:56.343822Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainDataset.get_labels = lambda: [instance[1] for instance in trainDataset.imgs]\nvalDataset.get_labels = lambda: [instance[1] for instance in valDataset.imgs]","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:56.346343Z","iopub.execute_input":"2023-08-31T15:58:56.3471Z","iopub.status.idle":"2023-08-31T15:58:56.352658Z","shell.execute_reply.started":"2023-08-31T15:58:56.347064Z","shell.execute_reply":"2023-08-31T15:58:56.351701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Import necessary modules\nfrom torch.utils.data import DataLoader\n\n# Define a TaskSampler for training data\ntrain_sampler = TaskSampler(\n    trainDataset,  # Training dataset\n    n_way=N_WAY,   # Number of classes per task\n    n_shot=N_SHOT,  # Number of support examples per class\n    n_query=N_QUERY,  # Number of query examples per class\n    n_tasks=N_TRAINING_EPISODES  # Number of training episodes (tasks)\n)\n\n# Create a DataLoader for training data using the TaskSampler\ntrain_loader = DataLoader(\n    trainDataset,  # Training dataset\n    batch_sampler=train_sampler,  # Use the defined TaskSampler\n    num_workers=2,  # Number of worker processes for data loading\n    pin_memory=True,  # Pin memory for faster GPU transfers\n    collate_fn=train_sampler.episodic_collate_fn  # Collate function for episodic data\n)\n\n# Define a TaskSampler for testing (validation) data\ntest_sampler = TaskSampler(\n    valDataset,  # Validation dataset\n    n_way=N_WAY,   # Number of classes per task\n    n_shot=N_SHOT,  # Number of support examples per class\n    n_query=N_QUERY,  # Number of query examples per class\n    n_tasks=N_EVALUATION_TASKS  # Number of evaluation tasks\n)\n\n# Create a DataLoader for testing (validation) data using the TaskSampler\ntest_loader = DataLoader(\n    valDataset,  # Validation dataset\n    batch_sampler=test_sampler,  # Use the defined TaskSampler\n    num_workers=2,  # Number of worker processes for data loading\n    pin_memory=True,  # Pin memory for faster GPU transfers\n    collate_fn=test_sampler.episodic_collate_fn,  # Collate function for episodic data\n)\n","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:56.353847Z","iopub.execute_input":"2023-08-31T15:58:56.35475Z","iopub.status.idle":"2023-08-31T15:58:56.365407Z","shell.execute_reply.started":"2023-08-31T15:58:56.354718Z","shell.execute_reply":"2023-08-31T15:58:56.364461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Import necessary libraries\nfrom torchvision.models import convnext_tiny\nfrom torchvision.models import ConvNeXt_Tiny_Weights\n\n# Import required modules from PyTorch\nimport torch\nimport torch.nn as nn\n\n# Define a class for the Prototypical Networks\nclass PrototypicalNetworks(nn.Module):\n    def __init__(self, backbone: nn.Module):\n        super(PrototypicalNetworks, self).__init__()\n        self.backbone = backbone\n\n    def forward(\n        self,\n        support_images: torch.Tensor,\n        support_labels: torch.Tensor,\n        query_images: torch.Tensor,\n    ) -> torch.Tensor:\n        \"\"\"\n        Forward pass of the Prototypical Networks.\n        Predict query labels using labeled support images.\n        \"\"\"\n        # Extract the features of support and query images using the provided backbone\n        z_support = self.backbone.forward(support_images)\n        z_query = self.backbone.forward(query_images)\n\n        # Infer the number of different classes (ways) from the labels of the support set\n        n_way = len(torch.unique(support_labels))\n        \n        # Calculate prototypes for each class by taking the mean of support features with the same label\n        z_proto = torch.cat(\n            [\n                z_support[torch.nonzero(support_labels == label)].mean(0)\n                for label in range(n_way)\n            ]\n        )\n\n        # Compute the Euclidean distance from query features to prototypes\n        dists = torch.cdist(z_query, z_proto)\n\n        # Calculate classification scores based on the negative of distances\n        scores = -dists\n        return scores\n\n# Load a pre-trained ResNet18 model as the backbone for feature extraction\nconvolutional_network = resnet18(pretrained=True)\nconvolutional_network.fc = nn.Flatten()  # Replace the fully connected layer with a flattening operation\nprint(convolutional_network)\n\n# Create an instance of the PrototypicalNetworks model using the provided backbone\nmodel = PrototypicalNetworks(convolutional_network).cuda()\n","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:58:56.367323Z","iopub.execute_input":"2023-08-31T15:58:56.368271Z","iopub.status.idle":"2023-08-31T15:59:00.032831Z","shell.execute_reply.started":"2023-08-31T15:58:56.368237Z","shell.execute_reply":"2023-08-31T15:59:00.031821Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Import necessary modules\nimport torch.optim as optim\n\n# Define the loss function\ncriterion = nn.CrossEntropyLoss()\n\n# Define the optimizer\noptimizer = optim.Adam(model.parameters(), lr=0.0015)\n\n# Define the 'fit' function for training\ndef fit(\n    support_images: torch.Tensor,\n    support_labels: torch.Tensor,\n    query_images: torch.Tensor,\n    query_labels: torch.Tensor,\n) -> float:\n    # Reset gradients in the optimizer\n    optimizer.zero_grad()\n\n    # Forward pass through the model\n    classification_scores = model(\n        support_images.cuda(), support_labels.cuda(), query_images.cuda()\n    )\n\n    # Calculate the loss using the specified loss function\n    loss = criterion(classification_scores, query_labels.cuda())\n    \n    # Backpropagate the gradients\n    loss.backward()\n    \n    # Update the model's parameters using the optimizer\n    optimizer.step()\n\n    # Return the loss value as a floating-point number\n    return loss.item()\n","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:59:00.034135Z","iopub.execute_input":"2023-08-31T15:59:00.03451Z","iopub.status.idle":"2023-08-31T15:59:00.042642Z","shell.execute_reply.started":"2023-08-31T15:59:00.034478Z","shell.execute_reply":"2023-08-31T15:59:00.041448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Set the frequency for logging updates\nlog_update_frequency = 10\n\n# Initialize an empty list to store loss values\nall_loss = []\n\n# Set the model in training mode\nmodel.train()\n\n# Use tqdm to create a progress bar over the training loader\nwith tqdm(enumerate(train_loader), total=len(train_loader)) as tqdm_train:\n    # Iterate through training episodes\n    for episode_index, (\n        support_images,\n        support_labels,\n        query_images,\n        query_labels,\n        _,\n    ) in tqdm_train:\n        # Calculate the loss and perform optimization through the 'fit' function\n        loss_value = fit(support_images, support_labels, query_images, query_labels)\n        \n        # Append the loss value to the list\n        all_loss.append(loss_value)\n\n        # Log the loss at the specified frequency\n        if episode_index % log_update_frequency == 0:\n            # Calculate a sliding average of the loss values\n            sliding_avg_loss = sliding_average(all_loss, log_update_frequency)\n            \n            # Update the tqdm progress bar with the current loss\n            tqdm_train.set_postfix(loss=sliding_avg_loss)\n","metadata":{"execution":{"iopub.status.busy":"2023-08-31T15:59:00.044195Z","iopub.execute_input":"2023-08-31T15:59:00.044765Z","iopub.status.idle":"2023-08-31T16:38:11.595303Z","shell.execute_reply.started":"2023-08-31T15:59:00.044733Z","shell.execute_reply":"2023-08-31T16:38:11.594157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom typing import List\nfrom sklearn.metrics import f1_score, accuracy_score\ndef evaluate_on_one_task(\n    support_images: torch.Tensor,\n    support_labels: torch.Tensor,\n    query_images: torch.Tensor,\n    query_labels: torch.Tensor,\n) -> [float, float, List[int], List[int]]:\n    \"\"\"\n    Returns the F1 score and accuracy for the predictions of query labels,\n    along with the true labels and predicted labels.\n    \"\"\"\n    predictions = torch.max(\n        model(support_images.cuda(), support_labels.cuda(), query_images.cuda())\n        .detach()\n        .data,\n        1,\n    )[1].cpu().numpy()\n    f1 = f1_score(query_labels.cpu(), predictions, average='weighted')\n    accuracy = accuracy_score(query_labels.cpu(), predictions)\n    return f1, accuracy, query_labels.cpu().numpy(), predictions\n\n\ndef evaluate(data_loader: DataLoader):\n    # We'll count everything and compute the average F1 score and accuracy at the end\n    total_f1 = 0\n    total_accuracy = 0\n\n    model.eval()\n    with torch.no_grad():\n        for episode_index, (\n            support_images,\n            support_labels,\n            query_images,\n            query_labels,\n            class_ids,\n        ) in tqdm(enumerate(data_loader), total=len(data_loader)):\n\n            f1, accuracy, true_labels, predicted_labels = evaluate_on_one_task(\n                support_images, support_labels, query_images, query_labels\n            )\n\n            total_f1 += f1\n            total_accuracy += accuracy\n\n            # Plotting true labels and predicted labels\n            plt.figure()\n            plt.imshow(query_images[0].cpu().numpy().transpose(1, 2, 0))\n            plt.title(f\"True: {true_labels[0]}, Predicted: {predicted_labels[0]}\")\n            plt.axis('off')\n            plt.show()\n\n    average_f1 = total_f1 / len(data_loader)\n    average_accuracy = total_accuracy / len(data_loader)\n    print(f\"Model tested on {len(data_loader)} tasks.\")\n    print(f\"Average F1 score: {average_f1:.4f}\")\n    print(f\"Average Accuracy: {(100 * average_accuracy):.2f}%\")\n\n\nevaluate(test_loader)","metadata":{"execution":{"iopub.status.busy":"2023-08-31T16:38:11.600852Z","iopub.execute_input":"2023-08-31T16:38:11.601701Z","iopub.status.idle":"2023-08-31T16:45:55.542161Z","shell.execute_reply.started":"2023-08-31T16:38:11.601654Z","shell.execute_reply":"2023-08-31T16:45:55.541166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.save(model.state_dict(), \"model_weights.pth\")","metadata":{"execution":{"iopub.status.busy":"2023-08-31T16:46:20.518244Z","iopub.execute_input":"2023-08-31T16:46:20.518647Z","iopub.status.idle":"2023-08-31T16:46:20.60431Z","shell.execute_reply.started":"2023-08-31T16:46:20.518616Z","shell.execute_reply":"2023-08-31T16:46:20.603255Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"(\n    example_support_images,\n    example_support_labels,\n    example_query_images,\n    example_query_labels,\n    example_class_ids,\n) = next(iter(train_loader))","metadata":{"execution":{"iopub.status.busy":"2023-08-31T17:24:38.773055Z","iopub.execute_input":"2023-08-31T17:24:38.773452Z","iopub.status.idle":"2023-08-31T17:24:57.139333Z","shell.execute_reply.started":"2023-08-31T17:24:38.773403Z","shell.execute_reply":"2023-08-31T17:24:57.13761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_imgs = os.listdir(\"/kaggle/input/bioverse-hackathon-a/test/\")\ntest_imgs = [\"/kaggle/input/bioverse-hackathon-a/test/\" + x for x in test_imgs]\npred_labels = []","metadata":{"execution":{"iopub.status.busy":"2023-08-31T17:23:41.328661Z","iopub.execute_input":"2023-08-31T17:23:41.329066Z","iopub.status.idle":"2023-08-31T17:23:41.336369Z","shell.execute_reply.started":"2023-08-31T17:23:41.329033Z","shell.execute_reply":"2023-08-31T17:23:41.334947Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfor imgg in test_imgs:\n    img = Image.open(imgg).convert(\"RGB\")\n    img = valTransforms(img)\n    img = torch.unsqueeze(img, 0)\n    pred = model(example_support_images.cuda(), example_support_labels.cuda(), img.cuda())\n    pred_class = np.argmax(pred.cpu().detach().numpy())\n    pred_labels.append(pred_class)","metadata":{"execution":{"iopub.status.busy":"2023-08-31T17:24:57.142737Z","iopub.execute_input":"2023-08-31T17:24:57.143417Z","iopub.status.idle":"2023-08-31T17:25:22.039026Z","shell.execute_reply.started":"2023-08-31T17:24:57.143373Z","shell.execute_reply":"2023-08-31T17:25:22.035145Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.DataFrame({\"filename\": [x.split(\"/\")[-1] for x in test_imgs], \"class\": pred_labels})\n\nidx_to_class = {v: k for k, v in trainDataset.class_to_idx.items()}\n\ndef idx_cls(idx):\n    return idx_to_class[idx]\n\ndf[\"class\"] = df[\"class\"].apply(idx_cls)\n\ndf.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2023-08-31T17:29:17.320911Z","iopub.execute_input":"2023-08-31T17:29:17.321304Z","iopub.status.idle":"2023-08-31T17:29:17.331274Z","shell.execute_reply.started":"2023-08-31T17:29:17.321275Z","shell.execute_reply":"2023-08-31T17:29:17.330266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# inference time","metadata":{}},{"cell_type":"code","source":"import time\nimg = Image.open(imgg).convert(\"RGB\")\nimg = valTransforms(img)\nimg = torch.unsqueeze(img, 0)\nstart_time = time.time()\npred = model(example_support_images.cuda(), example_support_labels.cuda(), img.cuda())\nend_time = time.time()\n\nprint(f\"Time: {end_time - start_time} Second(s)\")","metadata":{"execution":{"iopub.status.busy":"2023-08-31T17:49:12.355032Z","iopub.execute_input":"2023-08-31T17:49:12.355414Z","iopub.status.idle":"2023-08-31T17:49:12.472254Z","shell.execute_reply.started":"2023-08-31T17:49:12.355384Z","shell.execute_reply":"2023-08-31T17:49:12.471233Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2023-08-31T17:33:26.160839Z","iopub.execute_input":"2023-08-31T17:33:26.161281Z","iopub.status.idle":"2023-08-31T17:33:26.167108Z","shell.execute_reply.started":"2023-08-31T17:33:26.161248Z","shell.execute_reply":"2023-08-31T17:33:26.166105Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2023-08-31T17:34:05.557057Z","iopub.execute_input":"2023-08-31T17:34:05.55745Z","iopub.status.idle":"2023-08-31T17:34:05.570594Z","shell.execute_reply.started":"2023-08-31T17:34:05.557401Z","shell.execute_reply":"2023-08-31T17:34:05.569412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2023-08-31T17:32:45.994414Z","iopub.execute_input":"2023-08-31T17:32:45.99537Z","iopub.status.idle":"2023-08-31T17:32:46.000389Z","shell.execute_reply.started":"2023-08-31T17:32:45.995337Z","shell.execute_reply":"2023-08-31T17:32:45.999206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}],"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}}