{"metadata":{"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"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport tensorflow as tf\nimport tensorflow.keras as keras\nimport PIL\nimport cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport os\nimport random\nfrom tqdm import tqdm\nimport tensorflow_addons as tfa\nimport random\nfrom sklearn.preprocessing import MultiLabelBinarizer\nimport torch\nimport torchvision\nimport torchvision.models as models\nfrom PIL import Image\nimport torchvision.transforms as transforms\nimport os\nfrom torchvision import datasets\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport tqdm\nfrom tqdm import tqdm\nimport torch.optim as optim\nfrom PIL import ImageFile\nImageFile.LOAD_TRUNCATED_IMAGES = True\nfrom torch.utils.data import Dataset, DataLoader\nimport cv2                \nfrom PIL import Image\nfrom sklearn.metrics import accuracy_score\nfrom albumentations import *\nimport albumentations\nfrom albumentations.pytorch.transforms import ToTensorV2\nimport sys","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-09-14T15:34:56.868180Z","iopub.execute_input":"2022-09-14T15:34:56.868916Z","iopub.status.idle":"2022-09-14T15:35:06.936476Z","shell.execute_reply.started":"2022-09-14T15:34:56.868773Z","shell.execute_reply":"2022-09-14T15:35:06.935511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pip install --upgrade efficientnet-pytorch","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:06.939345Z","iopub.execute_input":"2022-09-14T15:35:06.940352Z","iopub.status.idle":"2022-09-14T15:35:19.472626Z","shell.execute_reply.started":"2022-09-14T15:35:06.940311Z","shell.execute_reply":"2022-09-14T15:35:19.471142Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from efficientnet_pytorch import EfficientNet","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.474563Z","iopub.execute_input":"2022-09-14T15:35:19.475121Z","iopub.status.idle":"2022-09-14T15:35:19.487805Z","shell.execute_reply.started":"2022-09-14T15:35:19.475076Z","shell.execute_reply":"2022-09-14T15:35:19.486898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv('../input/plant-pathology-2021-fgvc8/train.csv')\ndf['labels'] = df['labels'].apply(lambda string: string.split(' '))\n#df=df[:100]\ns = list(df['labels'])\nmlb = MultiLabelBinarizer()\ntrainx = pd.DataFrame(mlb.fit_transform(s), columns=mlb.classes_, index=df.index)\n#df['image'] = df['image'].str.replace(r'.jpg', '')\ntrainx.insert(0, \"image\", df['image'], True)\ntrainx","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.492190Z","iopub.execute_input":"2022-09-14T15:35:19.494302Z","iopub.status.idle":"2022-09-14T15:35:19.577033Z","shell.execute_reply.started":"2022-09-14T15:35:19.494273Z","shell.execute_reply":"2022-09-14T15:35:19.576137Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"t_df=pd.read_csv('../input/plant-pathology-2021-fgvc8/sample_submission.csv')\ntest_df=t_df.drop(['labels'], axis=1)\n#test_df['image'] = test_df['image'].str.replace(r'.jpg', '')\ntest_df","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.578802Z","iopub.execute_input":"2022-09-14T15:35:19.579159Z","iopub.status.idle":"2022-09-14T15:35:19.597212Z","shell.execute_reply.started":"2022-09-14T15:35:19.579124Z","shell.execute_reply":"2022-09-14T15:35:19.596090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ntrain_df=trainx\ntrain_df.reset_index(drop=True,inplace=True)\ntest_df.reset_index(drop=True,inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.598667Z","iopub.execute_input":"2022-09-14T15:35:19.599274Z","iopub.status.idle":"2022-09-14T15:35:19.604561Z","shell.execute_reply.started":"2022-09-14T15:35:19.599239Z","shell.execute_reply":"2022-09-14T15:35:19.603392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomDataset(Dataset):\n    def __init__(self,df,root_dir,transform=None,iftest=False):\n        self.df=df\n        self.root_dir=root_dir\n        self.transform=transform\n        self.iftest=iftest\n    \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self,idx):\n        if torch.is_tensor(idx):\n            idx=idx.tolist()\n        img_name=self.root_dir+self.df.iloc[idx,0]\n#         print(img_name)\n        image= cv2.imread(img_name,cv2.IMREAD_COLOR)\n#         image= cv2.imread(img_name)\n#         print(img_name,image)\n        image= cv2.cvtColor(image,cv2.COLOR_BGR2RGB)\n#         image = Image.fromarray(image)\n#         print(type(image))\n        if self.transform:\n            image=self.transform(image=image)['image']\n        if self.iftest:\n            return image\n        labels=torch.tensor(np.argmax(self.df.iloc[idx,1:].values))\n#         labels=np.asarray(labels)\n#         labels=torch.from_numpy(labels.astype(np.int32))\n#         labels=labels.unsqueeze(-1)\n#         print(labels.shape)\n#         sample={'image':image,'labels':labels}\n        return (image,labels)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.606314Z","iopub.execute_input":"2022-09-14T15:35:19.606986Z","iopub.status.idle":"2022-09-14T15:35:19.627486Z","shell.execute_reply.started":"2022-09-14T15:35:19.606950Z","shell.execute_reply":"2022-09-14T15:35:19.625445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMSIZE=545\nIMSIZE=EfficientNet.get_image_size('efficientnet-b5')\nprint(IMSIZE)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.631140Z","iopub.execute_input":"2022-09-14T15:35:19.631422Z","iopub.status.idle":"2022-09-14T15:35:19.644038Z","shell.execute_reply.started":"2022-09-14T15:35:19.631397Z","shell.execute_reply":"2022-09-14T15:35:19.643103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(torchvision.__version__)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.645787Z","iopub.execute_input":"2022-09-14T15:35:19.646637Z","iopub.status.idle":"2022-09-14T15:35:19.653107Z","shell.execute_reply.started":"2022-09-14T15:35:19.646599Z","shell.execute_reply":"2022-09-14T15:35:19.651920Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset=CustomDataset(df=train_df,root_dir='../input/plant-pathology-2021-fgvc8/train_images/',\n                     transform=Compose([augmentations.geometric.resize.Resize(height=IMSIZE,width=IMSIZE,always_apply=True),\n                                                  HorizontalFlip(p=0.5),\n                                                  VerticalFlip(p=0.5),\n                                                  ShiftScaleRotate(rotate_limit=25.0,p=0.7),\n                                                  OneOf([Emboss(p=1),Sharpen(p=1),Blur(p=1)],p=0.5),\n                                                  PiecewiseAffine(p=0.5),\n                                                   Normalize((0.485,0.456,0.406),\n                                                                      (0.229,0.224,0.225),always_apply=True),\n                                                  ToTensorV2()\n                                                  ]))","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.658992Z","iopub.execute_input":"2022-09-14T15:35:19.659707Z","iopub.status.idle":"2022-09-14T15:35:19.667430Z","shell.execute_reply.started":"2022-09-14T15:35:19.659667Z","shell.execute_reply":"2022-09-14T15:35:19.666370Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"t_dataset=CustomDataset(df=train_df,root_dir='../input/plant-pathology-2021-fgvc8/train_images/',\n                     transform=Compose([augmentations.geometric.resize.Resize(height=IMSIZE,width=IMSIZE,always_apply=True),\n                                                  HorizontalFlip(p=0.5),\n                                                  VerticalFlip(p=0.5),\n                                                  ShiftScaleRotate(rotate_limit=25.0,p=0.7),\n                                                  OneOf([Emboss(p=1),Sharpen(p=1),Blur(p=1)],p=0.5),\n                                                  PiecewiseAffine(p=0.5),\n                                                   Normalize((0.485,0.456,0.406),\n                                                                      (0.229,0.224,0.225),always_apply=True),\n                                                  ToTensorV2()\n                                                  ]),iftest=True)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.669137Z","iopub.execute_input":"2022-09-14T15:35:19.670072Z","iopub.status.idle":"2022-09-14T15:35:19.681412Z","shell.execute_reply.started":"2022-09-14T15:35:19.670022Z","shell.execute_reply":"2022-09-14T15:35:19.680566Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_dataset=CustomDataset(df=test_df,root_dir='../input/plant-pathology-2021-fgvc8/test_images/',\n                     transform=Compose([augmentations.geometric.resize.Resize(height=IMSIZE,width=IMSIZE,always_apply=True),\n                                                  Normalize((0.485,0.456,0.406),\n                                                                      (0.229,0.224,0.225),always_apply=True),\n                                                    ToTensorV2()\n                                                  ]),iftest=True)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.684285Z","iopub.execute_input":"2022-09-14T15:35:19.685025Z","iopub.status.idle":"2022-09-14T15:35:19.692039Z","shell.execute_reply.started":"2022-09-14T15:35:19.684982Z","shell.execute_reply":"2022-09-14T15:35:19.691147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BATCH_SIZE=2\ntrain_loader=DataLoader(train_dataset,batch_size=BATCH_SIZE,shuffle=True,num_workers=2)\nt_loader=DataLoader(t_dataset,batch_size=BATCH_SIZE,shuffle=False,num_workers=2)\ntest_loader=DataLoader(test_dataset,batch_size=BATCH_SIZE,shuffle=False,num_workers=2)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.694702Z","iopub.execute_input":"2022-09-14T15:35:19.695608Z","iopub.status.idle":"2022-09-14T15:35:19.705613Z","shell.execute_reply.started":"2022-09-14T15:35:19.695572Z","shell.execute_reply":"2022-09-14T15:35:19.704612Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"use_cuda = torch.cuda.is_available()\nif use_cuda:\n    device='cuda:0'\nuse_tpu=False\nuse_device=True\nif use_tpu:\n    device='idk'","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.708892Z","iopub.execute_input":"2022-09-14T15:35:19.709171Z","iopub.status.idle":"2022-09-14T15:35:19.780077Z","shell.execute_reply.started":"2022-09-14T15:35:19.709148Z","shell.execute_reply":"2022-09-14T15:35:19.779020Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train(n_epochs,train_loader,valid_loader,model,optimizer,criterion,use_device,save_path,final_train=False,ifsched=False):\n    for epoch in range(1,n_epochs+1):\n        train_loss=0.0\n        valid_loss=0.0\n        labels_for_acc=[]\n        output_for_acc=[]\n        labels_for_accv=[]\n        output_for_accv=[]\n        model.train()\n        for batch_idx,(data,target) in enumerate(tqdm(train_loader)):\n            #print(batch_idx)\n#            print(type(data),type(target))\n            if use_device:\n                data,target=data.to(device),target.to(device)\n            optimizer.zero_grad()\n            output=model(data)\n            loss=criterion(output,target)\n            train_loss+=loss.item()*data.size(0)\n            loss.backward()\n            optimizer.step()\n            if ifsched:\n                    scheduler.step()\n            labels_for_acc=np.concatenate((labels_for_acc,target.cpu().numpy()),0)\n            output_for_acc=np.concatenate((output_for_acc,np.argmax(output.cpu().detach().numpy(),1)),0)\n        train_loss=train_loss/len(train_loader.dataset)\n        train_acc=accuracy_score(labels_for_acc,output_for_acc)\n        if not final_train:\n            with torch.no_grad():\n                model.eval()\n                for batch_idx,(data,target) in enumerate(valid_loader):\n                    if use_device:\n                        data,target=data.to(device),target.to(device)\n                    output=model(data)\n                    loss=criterion(output,target)\n                    valid_loss+=loss.item()*data.size(0)\n                    labels_for_accv=np.concatenate((labels_for_accv,target.cpu().numpy()),0)\n                    output_for_accv=np.concatenate((output_for_accv,np.argmax(output.cpu().detach().numpy(),1)),0)\n                valid_loss=valid_loss/len(valid_loader.dataset)\n                valid_acc=accuracy_score(labels_for_accv,output_for_accv)\n                print('Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f} \\tTrain Acc: {:.6f} \\tValidation Acc: {:.6f}'.format(\n                epoch, \n                train_loss,\n                valid_loss,\n                train_acc,\n                valid_acc\n                ))\n        if final_train:\n            print('Epoch: {} \\tTraining Loss: {:.6f} \\tTrain Acc: {:.6f} '.format(\n                epoch, \n                train_loss,\n                train_acc\n                ))\n        #return save_path","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.783708Z","iopub.execute_input":"2022-09-14T15:35:19.786080Z","iopub.status.idle":"2022-09-14T15:35:19.800812Z","shell.execute_reply.started":"2022-09-14T15:35:19.786042Z","shell.execute_reply":"2022-09-14T15:35:19.799822Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from efficientnet_pytorch import EfficientNet\nmodel_efficient=EfficientNet.from_pretrained('efficientnet-b7')","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:19.802630Z","iopub.execute_input":"2022-09-14T15:35:19.803397Z","iopub.status.idle":"2022-09-14T15:35:40.537577Z","shell.execute_reply.started":"2022-09-14T15:35:19.803355Z","shell.execute_reply":"2022-09-14T15:35:40.535406Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# for param in model_efficient.parameters():\n#     param.requires_gr\nad=False\n# print(model_transfer)\nmodel_efficient._fc=nn.Sequential(nn.Linear(model_efficient._fc.in_features,1000,bias=True),\n                                 nn.ReLU(),\n                                 nn.Dropout(p=0.5),\n                                 nn.Linear(1000,6,bias=True))\n# nn.init.kaiming_normal_(model_efficient._fc.weight, nonlinearity='relu')\nif use_device:\n    model_efficient = model_efficient.to(device)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:40.539174Z","iopub.execute_input":"2022-09-14T15:35:40.539833Z","iopub.status.idle":"2022-09-14T15:35:45.343126Z","shell.execute_reply.started":"2022-09-14T15:35:40.539787Z","shell.execute_reply":"2022-09-14T15:35:45.342009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"NEPOCHS=4\nprint(IMSIZE)\ncriterion_transfer = nn.CrossEntropyLoss()\n# learning_rate=5e-4*np.logspace(0,1.5,9)\n# learning_rate=learning_rate[2]\nlearning_rate=8e-4\noptimizer_transfer = optim.AdamW(model_efficient.parameters(),learning_rate,weight_decay=1e-3)\nnum_train_steps = int(len(train_dataset) / BATCH_SIZE * NEPOCHS)\nfrom transformers import get_cosine_schedule_with_warmup\nscheduler = get_cosine_schedule_with_warmup(optimizer_transfer, num_warmup_steps=len(train_dataset)/BATCH_SIZE*5, num_training_steps=num_train_steps)\n# optimizer_transfer = torch.optim.Adam(model_efficient.parameters())\n# scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer_transfer, 'max', patience = 3,verbose=True,min_lr=0.00001)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:45.344772Z","iopub.execute_input":"2022-09-14T15:35:45.345168Z","iopub.status.idle":"2022-09-14T15:35:45.459348Z","shell.execute_reply.started":"2022-09-14T15:35:45.345130Z","shell.execute_reply":"2022-09-14T15:35:45.458302Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train(NEPOCHS, train_loader,None, model_efficient, optimizer_transfer, criterion_transfer, use_device, 'model_transfer.pt',ifsched=True,final_train=True)","metadata":{"execution":{"iopub.status.busy":"2022-09-14T15:35:45.460770Z","iopub.execute_input":"2022-09-14T15:35:45.461137Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def test(model,test_loader,use_device):\n    preds_for_output=np.zeros((1,6))\n    with torch.no_grad():\n        model.eval()\n        for images in test_loader:\n            #print(type(images))\n            if use_device:\n                images=images.to(device)\n            preds=model(images)\n            preds_for_output=np.concatenate((preds_for_output,preds.cpu().detach().numpy()),0)\n    return preds_for_output\n        \n        \nnum_runs=2\nimport scipy\nsubs=[]\nfor i in range(num_runs):\n    out=test(model_efficient,t_loader,use_device)\n    output=pd.DataFrame(scipy.special.softmax(out,1),columns=['complex', 'frog_eye_leaf_spot', 'healthy', 'powdery_mildew','rust','scab'])\n    output.drop(0,inplace=True)\n    output.reset_index(drop=True,inplace=True)\n    subs.append(output)\n\nsub_eff=sum(subs)/num_runs","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub1=sub_eff.copy()\nsub1['image']=train_df.image\nsub1=sub1[['image','complex', 'frog_eye_leaf_spot', 'healthy', 'powdery_mildew','rust','scab']]\nsub1.to_csv('train_predicts.csv', index=False)\nsub1.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainx.to_csv('train_ground.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"classes = np.array([\n        'complex', \n        'frog_eye_leaf_spot', \n        'powdery_mildew', \n        'rust', \n        'scab'])\n\ndf_true = pd.read_csv('train_ground.csv', index_col='image').drop('healthy', axis=1)\n#print(df_true.head())\ndf_pred = pd.read_csv('train_predicts.csv', index_col='image').drop('healthy', axis=1)\n#print(df_pred.head())\n\n\ndf_true = df_true.reindex(df_pred.index)\n#print(df_true.head())\ny_true = df_true.values\ny_pred = df_pred.values\n\n'''\nrun evaluation for each threshold in [0, 1)\n'''\nthresholds = np.arange(.01, 1., .01)\nscores = []\n\nfor threshold in thresholds:\n    metric = tfa.metrics.F1Score(\n        num_classes=len(classes), \n        average=None, \n        threshold=threshold)\n    metric.update_state(y_true, y_pred)\n    scores.append(metric.result().numpy())\n    \ndf = pd.DataFrame(columns=classes, data=scores, index=pd.Index(thresholds, name='threshold'))\n\n'''\nfind maximum value for each class and the corresponding threshold\n'''\nthresholds = []\nscores = []\n\nfor x in classes:\n    thresholds.append(df[x].idxmax())\n    scores.append(df[x].max())\n    print(f'{x}: {df.loc[.5, x]:.4f} >>> {df.loc[thresholds[-1], x]:.4f} ({thresholds[-1]:.2f})')\n    #print(thresholds)\n    #print(scores)\nprint(f'\\nmean score: {df.loc[.5].mean():.4f} >>> {np.mean(scores):.4f}')\nprint(thresholds)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_runs=2\nimport scipy\nsubs=[]\nfor i in range(num_runs):\n    out=test(model_efficient,test_loader,use_device)\n    output=pd.DataFrame(scipy.special.softmax(out,1),columns=['complex', 'frog_eye_leaf_spot', 'healthy', 'powdery_mildew','rust','scab'])\n    output.drop(0,inplace=True)\n    output.reset_index(drop=True,inplace=True)\n    subs.append(output)\n\npredicts=[]\nsub_eff_test=sum(subs)/num_runs\nss=sub_eff_test.T\nss = ss.drop('healthy')\nprint(ss)\nfor i in ss:\n    predicts.append((list(ss[i])))\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#print(predicts)\n#print(thresholds)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.save(model_efficient.state_dict(), '/kaggle/working/weights.pth')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub1=sub_eff_test.copy()\nsub1['image']=test_df.image\nsub1=sub1[['image','complex', 'frog_eye_leaf_spot', 'healthy', 'powdery_mildew','rust','scab']]\nsub1.to_csv('testpredicted.csv', index=False)\nsub1.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nfor i in range(len(predicts)):\n    for j in range(len(thresholds)):\n        predicts[i][j] = predicts[i][j] > thresholds[j]\n    #print(predicts[i])\n    \npredicts=np.array(predicts)\n#print(predicts)\npredicts = predicts.astype('bool')\n#print(type(predicts))\nlabels = []\n\nfor i in range(len(predicts)):\n    labels.append(' '.join(classes[predicts[i]]))\n\nlabels = ['healthy' if ('healthy' in x or x == '') else x for x in labels]\ndf = pd.DataFrame({\n    'image': os.listdir('../input/plant-pathology-2021-fgvc8/test_images'),\n    'labels': labels})\n\ndf.to_csv('testsubmission.csv', index=False)\ndisplay(df.head())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}