{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":7327,"databundleVersionId":861871,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 一、数据预处理","metadata":{}},{"cell_type":"code","source":"# 导入相关的包\nimport torch\nimport torch.nn as nn\nimport pandas as pd\nimport numpy as np\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom PIL import Image\nimport os\nimport matplotlib.pyplot as plt\nimport torchvision.models\n# 使用tqdm库创建进度条\nfrom tqdm import tqdm\nimport seaborn as sns","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:14.406608Z","iopub.execute_input":"2024-10-27T02:27:14.406991Z","iopub.status.idle":"2024-10-27T02:27:14.412673Z","shell.execute_reply.started":"2024-10-27T02:27:14.406953Z","shell.execute_reply":"2024-10-27T02:27:14.411775Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 看看label文件长啥样\nbreeds_dataframe = pd.read_csv('../input/dog-breed-identification/labels.csv')\nbreeds_dataframe.head(5)","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:15.176355Z","iopub.execute_input":"2024-10-27T02:27:15.176738Z","iopub.status.idle":"2024-10-27T02:27:15.207321Z","shell.execute_reply.started":"2024-10-27T02:27:15.176701Z","shell.execute_reply":"2024-10-27T02:27:15.206328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#显示条形图\ndef barw(ax): \n    for p in ax.patches:\n        val = p.get_width() #height of the bar\n        x = p.get_x()+ p.get_width() # x- position \n        y = p.get_y() + p.get_height()/2 #y-position\n        ax.annotate(round(val,2),(x,y))\n        \n#finding top dog\nplt.figure(figsize = (15,30))\nax0 =sns.countplot(y=breeds_dataframe['breed'],order=breeds_dataframe['breed'].value_counts().index)\nbarw(ax0)\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:15.624694Z","iopub.execute_input":"2024-10-27T02:27:15.625477Z","iopub.status.idle":"2024-10-27T02:27:17.264516Z","shell.execute_reply.started":"2024-10-27T02:27:15.625438Z","shell.execute_reply":"2024-10-27T02:27:17.263584Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 把狗的品种排个序\ndog_breeds = sorted(list(set(breeds_dataframe['breed'])))\nn_breeds = len(dog_breeds)\nprint(n_breeds)\ndog_breeds[:10]","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:17.266487Z","iopub.execute_input":"2024-10-27T02:27:17.267292Z","iopub.status.idle":"2024-10-27T02:27:17.280318Z","shell.execute_reply.started":"2024-10-27T02:27:17.267230Z","shell.execute_reply":"2024-10-27T02:27:17.279108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 把品种转成对应的数字\nbreed_to_num = dict(zip(dog_breeds, range(n_breeds)))\nbreed_to_num","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:17.281839Z","iopub.execute_input":"2024-10-27T02:27:17.282425Z","iopub.status.idle":"2024-10-27T02:27:17.295662Z","shell.execute_reply.started":"2024-10-27T02:27:17.282381Z","shell.execute_reply":"2024-10-27T02:27:17.294819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 把字典翻转一下，从数字对应到品种\nnum_to_breed = {num:breed for breed, num in breed_to_num.items()}\nnum_to_breed","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:17.298169Z","iopub.execute_input":"2024-10-27T02:27:17.298642Z","iopub.status.idle":"2024-10-27T02:27:17.314529Z","shell.execute_reply.started":"2024-10-27T02:27:17.298592Z","shell.execute_reply":"2024-10-27T02:27:17.313430Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 自定义Dataset","metadata":{}},{"cell_type":"code","source":"# 继承pytorch的dataset，创建自己的数据集\nclass DogDataset(Dataset):\n    def __init__(self, csv_path, file_path, mode=\"train\", transform=None,valid_ratio=0.2, \n                 resize_height=224, resize_width=224):\n        \"\"\"\n        Args:\n            csv_path: csv文件路径\n            img_path: 图像文件路径\n            mode: 训练模式还是测试模式\n            valid_ratio:验证集比例\n        \"\"\"\n        \n        # 将图片大小调整为224 * 224\n        self.resize_height = resize_height\n        self.resize_width = resize_width\n        self.file_path = file_path\n        self.mode = mode\n        self.transform = transform\n        \n        # 用pandas读取csv文件\n        if csv_path != None:\n            self.data_info = pd.read_csv(csv_path)\n            # 计算 length\n            self.data_len = len(self.data_info.index)\n            self.train_len = int(self.data_len * (1 - valid_ratio))\n        \n        if mode == \"train\":\n            # 第一列包含图像文件的名称\n            self.train_image = np.asarray(self.data_info.iloc[0:self.train_len, 0])\n            # 第二列是图像的 breed\n            self.train_breed = np.asarray(self.data_info.iloc[0:self.train_len, 1])\n            self.image_arr = self.train_image \n            self.breed_arr = self.train_breed\n        elif mode == \"valid\":\n            # 第一列包含图像文件的名称\n            self.valid_image = np.asarray(self.data_info.iloc[self.train_len:, 0])\n            # 第二列是图像的 breed\n            self.valid_breed = np.asarray(self.data_info.iloc[self.train_len:, 1])\n            self.image_arr = self.valid_image \n            self.breed_arr = self.valid_breed\n        elif mode == 'test':\n            self.image_arr = [f.split('.')[0] for f in os.listdir(file_path)]\n        \n        self.real_len = len(self.image_arr)\n        print('Finished reading the {} set of Leaves Dataset ({} samples found)'\n              .format(mode, self.real_len))\n        \n        \n        \n    def __getitem__(self, index):\n        # 从image_arr得到索引对应的文件名\n        single_image_name = self.image_arr[index]\n\n        # 读取图像, 拼接出完成的路径\n        img_as_img = Image.open(self.file_path + single_image_name + \".jpg\")\n        # 图像增广\n        img_as_img = self.transform(img_as_img)\n\n        if self.mode == \"test\":\n            return img_as_img, single_image_name # 把图像id也返回\n        else:\n            # 得到图像的 breed\n            breed = self.breed_arr[index]\n            # breed转换为对应的数字\n            number_breed = breed_to_num[breed]\n            return img_as_img, number_breed  #返回每一个index对应的图片数据和\n        \n    def __len__(self):\n        return self.real_len\n        ","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:22.754457Z","iopub.execute_input":"2024-10-27T02:27:22.754821Z","iopub.status.idle":"2024-10-27T02:27:22.768257Z","shell.execute_reply.started":"2024-10-27T02:27:22.754786Z","shell.execute_reply":"2024-10-27T02:27:22.767315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 图像增广","metadata":{}},{"cell_type":"code","source":"# 下面进行图像增广\ntrain_transform = transforms.Compose([\n    transforms.RandomResizedCrop(\n        224, # 然后，缩放图像以创建224x224的新图像\n        scale=(0.08, 1.0),  # 随机裁剪图像，所得图像为原始面积的0.08～1之间，高宽比在3/4和4/3之间。                                                   \n        ratio=(3.0/4.0, 4.0/3.0)\n    ),\n    transforms.RandomHorizontalFlip(p=0.5),\n    # 随机更改亮度，对比度和饱和度\n    transforms.ColorJitter(\n        brightness=0.4,\n        contrast=0.4,\n        saturation=0.4\n    ),\n    transforms.ToTensor(),\n    # 标准化图像的每个通道\n    transforms.Normalize([0.485, 0.456, 0.406],\n                        [0.229, 0.224, 0.225])\n])\n\ntest_transform = transforms.Compose([\n    transforms.Resize(256),\n    # 从图像中心裁切224x224大小的图片\n    transforms.CenterCrop(224),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406],\n                                     [0.229, 0.224, 0.225])\n])","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:24.752940Z","iopub.execute_input":"2024-10-27T02:27:24.753344Z","iopub.status.idle":"2024-10-27T02:27:24.760972Z","shell.execute_reply.started":"2024-10-27T02:27:24.753305Z","shell.execute_reply":"2024-10-27T02:27:24.759974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 创建数据加载器","metadata":{}},{"cell_type":"code","source":"train_path = '/kaggle/input/dog-breed-identification/labels.csv'\ntrain_img_path = '/kaggle/input/dog-breed-identification/train/'\ntest_img_path = '/kaggle/input/dog-breed-identification/test/'\n\ntrain_dataset = DogDataset(train_path, train_img_path, mode=\"train\", transform=train_transform)\nvalid_dataset = DogDataset(train_path, train_img_path, mode='valid', transform=test_transform)\ntest_dataset = DogDataset(None, test_img_path, mode='test', transform=test_transform)\nprint(train_dataset)\nprint(valid_dataset)\nprint(test_dataset)","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:26.644642Z","iopub.execute_input":"2024-10-27T02:27:26.645261Z","iopub.status.idle":"2024-10-27T02:27:26.702527Z","shell.execute_reply.started":"2024-10-27T02:27:26.645222Z","shell.execute_reply":"2024-10-27T02:27:26.701576Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 128\ntrain_iter = DataLoader(\n        dataset=train_dataset, \n        batch_size=batch_size, \n        shuffle=True, \n        drop_last=False\n)\n\nvalid_iter = DataLoader(\n    dataset=valid_dataset, \n    batch_size=batch_size, \n    shuffle=True,\n    drop_last=False\n)\n\ntest_iter = DataLoader(\n    dataset=test_dataset, \n    batch_size=batch_size, \n    shuffle=False,\n    drop_last=False\n)","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:28.940360Z","iopub.execute_input":"2024-10-27T02:27:28.941056Z","iopub.status.idle":"2024-10-27T02:27:28.946713Z","shell.execute_reply.started":"2024-10-27T02:27:28.941001Z","shell.execute_reply":"2024-10-27T02:27:28.945806Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 二、训练模型","metadata":{}},{"cell_type":"code","source":"# 看一下是在cpu还是GPU上\ndef get_device():\n    return 'cuda' if torch.cuda.is_available() else 'cpu'\n\ndevice = get_device()\nprint(device)","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:34.476988Z","iopub.execute_input":"2024-10-27T02:27:34.477778Z","iopub.status.idle":"2024-10-27T02:27:34.482775Z","shell.execute_reply.started":"2024-10-27T02:27:34.477739Z","shell.execute_reply":"2024-10-27T02:27:34.481848Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 构建模型\n这里，我们使用resnet50 + 两个全连接层","metadata":{}},{"cell_type":"code","source":"def get_net(device):\n    finetune_net = nn.Sequential()\n    # 特征提取部分，使用预训练的resnet50\n    finetune_net.features = torchvision.models.resnet50(weights=\"ResNet50_Weights.DEFAULT\")\n    # 定义一个新的输出网络，共有120个输出类别\n    finetune_net.output_new = nn.Sequential(nn.Linear(1000, 256),\n                                            nn.ReLU(),\n                                            nn.Linear(256, 120))\n    # 将模型参数分配给用于计算的CPU或GPU\n    finetune_net = finetune_net.to(device)\n    # 冻结参数\n    for param in finetune_net.features.parameters():\n        param.requires_grad = False\n    return finetune_net","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:41.837851Z","iopub.execute_input":"2024-10-27T02:27:41.838647Z","iopub.status.idle":"2024-10-27T02:27:41.844606Z","shell.execute_reply.started":"2024-10-27T02:27:41.838605Z","shell.execute_reply":"2024-10-27T02:27:41.843499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 定义超参数","metadata":{}},{"cell_type":"code","source":"# 超参数\nlearning_rate = 1e-4\nweight_decay = 1e-3\nnum_epoch = 50\nmodel_path = '/kaggle/working/pre_res_model.ckpt'","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:44.155670Z","iopub.execute_input":"2024-10-27T02:27:44.156071Z","iopub.status.idle":"2024-10-27T02:27:44.160704Z","shell.execute_reply.started":"2024-10-27T02:27:44.156014Z","shell.execute_reply":"2024-10-27T02:27:44.159711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 模型训练","metadata":{}},{"cell_type":"code","source":"# 初始化模型，并放在指定设备\nmodel = get_net(device)\n\n# 加载训练好的模型\n# model.load_state_dict(torch.load(model_path))\n# model.device = device\n\n# 分类任务，使用交叉熵cross-entropy作为损失函数\nloss_func = nn.CrossEntropyLoss()\n\n# 初始化优化器，可以微调一些超参数\noptimizer = torch.optim.Adam(model.parameters(), lr=learning_rate,\n                            weight_decay=weight_decay)\n# 训练的epochs\nn_epochs = num_epoch\n\n# 保存每个epoch的损失和精度\ntotal_train_loss = []\ntotal_train_accs = []\ntotal_valid_loss = []\ntotal_valid_accs = []\n\nbest_acc = 0.0\nfor epoch in range(n_epochs):\n    # -------------------------开始训练--------------------------\n    # 确保模型处于训练模式\n    model.train()\n    # These are used to record information in training.\n    train_loss = []\n    train_accs = []\n    # Iterate the training set by batches.\n    for batch in tqdm(train_iter):\n        # A batch consists of image data and corresponding breed.\n        imgs, breeds = batch\n         # Forward the data. (Make sure data and model are on the same device.)\n        imgs = imgs.to(device)\n        breeds = breeds.to(device)\n        # 上一步骤中存储在参数中的梯度应首先清除。\n        optimizer.zero_grad()\n        # 预测\n        logits = model(imgs)\n        # Calculate the cross-entropy loss.\n        loss = loss_func(logits, breeds)\n        # 计算梯度，更新参数\n        loss.backward()\n        optimizer.step()\n        \n        # 计算当前批次的精确度\n        # logits.argmax(dim=-1) 即求出每张图的类别\n        acc = (logits.argmax(dim=-1)==breeds).float().mean()\n        \n        # 记录损失和精度\n        train_loss.append(loss)\n        train_accs.append(acc)\n        # for结束\n    # 本次训练的平均损失和平均精度\n    train_loss = sum(train_loss) / len(train_loss)\n    train_acc = sum(train_accs) / len(train_accs)\n    # 保存信息\n    total_train_loss.append(train_loss.item())\n    total_train_accs.append(train_acc.item())\n    \n    # 打印信息\n    print(f\"[Train | {epoch+1:03d}/{n_epochs:03d}] loss = {train_loss:.5f}, acc = {train_acc:.5f}\")\n          \n    # ---------- Validation ----------\n    # Make sure the model is in eval mode so that some modules \n    # like dropout are disabled and work normally.\n    model.eval()\n    # 记录验证过程的信息\n    valid_loss = []\n    valid_accs = []\n    \n    # 按照批次迭代验证\n    for batch in tqdm(valid_iter):\n        imgs, breeds = batch\n        imgs = imgs.to(device)\n        breeds = breeds.to(device)\n        # 验证过程不用计算梯度\n        with torch.no_grad():\n              logits = model(imgs)\n\n        # 计算损失，但是没有梯度\n        loss = loss_func(logits, breeds)\n\n        # 计算当前批次的精度\n        acc = (logits.argmax(dim=-1) == breeds).float().mean()\n        # 记录损失和精度\n        valid_loss.append(loss)\n        valid_accs.append(acc)\n    \n                             \n    # 整个验证过程的平均损失和精度\n    valid_loss = sum(valid_loss) / len(valid_loss)\n    valid_acc = sum(valid_accs) / len(valid_accs)\n    total_valid_loss.append(valid_loss.item())\n    total_valid_accs.append(valid_acc.item())\n                             \n    # 打印信息\n    print(f\"[ Valid | {epoch + 1:03d}/{n_epochs:03d} ] loss = {valid_loss:.5f}, acc = {valid_acc:.5f}\")\n    \n# 保存模型\ntorch.save(model.state_dict(), model_path)\nprint('模型保存成功，目录为：{}'.format(model_path))","metadata":{"execution":{"iopub.status.busy":"2024-10-27T00:21:47.153384Z","iopub.execute_input":"2024-10-27T00:21:47.153667Z","iopub.status.idle":"2024-10-27T01:31:49.497212Z","shell.execute_reply.started":"2024-10-27T00:21:47.153637Z","shell.execute_reply":"2024-10-27T01:31:49.496198Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 画出损失图和精度图","metadata":{}},{"cell_type":"code","source":"print(total_train_loss)\nprint(total_train_accs)\nprint(total_valid_loss)\nprint(total_valid_accs)","metadata":{"execution":{"iopub.status.busy":"2024-10-27T01:34:21.709408Z","iopub.execute_input":"2024-10-27T01:34:21.709802Z","iopub.status.idle":"2024-10-27T01:34:21.913853Z","shell.execute_reply.started":"2024-10-27T01:34:21.709765Z","shell.execute_reply":"2024-10-27T01:34:21.912877Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 画出损失函数和精度图\n# 设置Seaborn的风格\nsns.set(style=\"darkgrid\")\nepochs = np.arange(1, num_epoch+1, 1)\n# 创建一个画布\nplt.figure(figsize=(12, 12))\n\n# 绘制损失图\nplt.subplot(2, 1, 1)\nsns.lineplot(x=epochs, y=total_train_loss, label='Train Loss')\nsns.lineplot(x=epochs, y=total_valid_loss, label='Valid Loss')\nplt.title('Loss over epochs')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\n\n# 绘制精度图\nplt.subplot(2, 1, 2)\nsns.lineplot(x=epochs, y=total_train_accs, label='Train Accuracy')\nsns.lineplot(x=epochs, y=total_valid_accs, label='Valid Accuracy')\nplt.title('Accuracy over epochs')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend()\n\n# 显示图表\n# plt.tight_layout()\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 三、预测结果","metadata":{}},{"cell_type":"code","source":"# 保存文件目录\nsaveFileName = '/kaggle/working/submission.csv'\nmodel =  get_net(device)\n# 加载训练好的模型\nmodel.load_state_dict(torch.load(model_path))","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:27:53.110428Z","iopub.execute_input":"2024-10-27T02:27:53.111193Z","iopub.status.idle":"2024-10-27T02:27:53.715027Z","shell.execute_reply.started":"2024-10-27T02:27:53.111152Z","shell.execute_reply":"2024-10-27T02:27:53.714089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_path = \"/kaggle/input/dog-breed-identification/test\"\npredict = pd.DataFrame(columns=[\"id\",*dog_breeds])\nids = sorted([f.split('.')[0] for f in os.listdir(test_path)])\n# ids","metadata":{"execution":{"iopub.status.busy":"2024-10-27T01:51:37.507561Z","iopub.execute_input":"2024-10-27T01:51:37.508319Z","iopub.status.idle":"2024-10-27T01:51:37.551130Z","shell.execute_reply.started":"2024-10-27T01:51:37.508280Z","shell.execute_reply":"2024-10-27T01:51:37.549999Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## predict\n# 开启eval模式,评估模式\nmodel.eval()\n\npreds = [] # 保存预测结果\nids = [] # 保存每张图片的id\n# 按照批次迭代\nfor batch in tqdm(test_iter):\n    imgs, imgs_id = batch\n    with torch.no_grad():\n        # 使用softmax对结果处理\n        output = torch.nn.functional.softmax(model(imgs.to(device)), dim=1)\n        preds.extend(output.cpu().numpy())\n        ids.extend(imgs_id)","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:28:13.703141Z","iopub.execute_input":"2024-10-27T02:28:13.703997Z","iopub.status.idle":"2024-10-27T02:29:33.390550Z","shell.execute_reply.started":"2024-10-27T02:28:13.703957Z","shell.execute_reply":"2024-10-27T02:29:33.389450Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(preds[:2])\nprint(ids[:2])","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:53:01.215831Z","iopub.execute_input":"2024-10-27T02:53:01.216827Z","iopub.status.idle":"2024-10-27T02:53:01.225830Z","shell.execute_reply.started":"2024-10-27T02:53:01.216775Z","shell.execute_reply":"2024-10-27T02:53:01.224721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ids[0] + ',' + ','.join([str(n) for n in preds[0]])","metadata":{"execution":{"iopub.status.busy":"2024-10-27T02:58:56.348376Z","iopub.execute_input":"2024-10-27T02:58:56.348757Z","iopub.status.idle":"2024-10-27T02:58:56.355284Z","shell.execute_reply.started":"2024-10-27T02:58:56.348719Z","shell.execute_reply":"2024-10-27T02:58:56.354591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open('/kaggle/working/submission.csv', 'w', encoding='utf-8') as f:\n    f.write('id,' + ','.join(dog_breeds) + '\\n')\n    for i, output in zip(ids, preds):\n        f.write(i + ',' + ','.join([str(n) for n in output]) + '\\n')","metadata":{"execution":{"iopub.status.busy":"2024-10-27T03:04:14.796607Z","iopub.execute_input":"2024-10-27T03:04:14.797492Z","iopub.status.idle":"2024-10-27T03:04:15.712654Z","shell.execute_reply.started":"2024-10-27T03:04:14.797447Z","shell.execute_reply":"2024-10-27T03:04:15.711843Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}