{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"},{"sourceId":7392775,"sourceType":"datasetVersion","datasetId":4297782},{"sourceId":7447509,"sourceType":"datasetVersion","datasetId":4334995}],"dockerImageVersionId":30648,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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\n\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":"2024-03-12T05:55:33.049123Z","iopub.execute_input":"2024-03-12T05:55:33.049799Z","iopub.status.idle":"2024-03-12T05:55:33.443573Z","shell.execute_reply.started":"2024-03-12T05:55:33.049765Z","shell.execute_reply":"2024-03-12T05:55:33.442180Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import albumentations as A\nimport gc\nimport matplotlib.pyplot as plt\nimport math\nimport multiprocessing\nimport numpy as np\nimport os\nimport pandas as pd\nimport random\nimport time\nimport timm\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\n\nfrom albumentations.pytorch import ToTensorV2\nfrom glob import glob\nfrom torch.utils.data import DataLoader, Dataset\nfrom tqdm import tqdm\nfrom typing import Dict, List\n\nos.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0,1\"\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint('Using', torch.cuda.device_count(), 'GPU(s)')\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T05:55:33.445552Z","iopub.execute_input":"2024-03-12T05:55:33.446495Z","iopub.status.idle":"2024-03-12T05:55:43.326688Z","shell.execute_reply.started":"2024-03-12T05:55:33.446457Z","shell.execute_reply":"2024-03-12T05:55:43.325598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class config:\n    model = \"resnet50\"\n    epoch = 10\n    lr = 1\n    batchsize = 32\n    splits = 5\n    momentum = 0.9\n    MAX_GRAD_NORM = 1e7\n    WEIGHT_DECAY = 0.5\n    device = \"cpu\"\n    FOLDS=5\n    AMP= True\nclass paths:\n    preloadedeeg = \"/kaggle/input/brain-eeg-spectrograms/eeg_specs.npy\"\n    train_eeg_dir = \"/kaggle/input/hms-harmful-brain-activity-classification/train_eegs\"\n    train_spec_dir = \"/kaggle/input/hms-harmful-brain-activity-classification/train_spectrograms\"\n    train_csv = \"/kaggle/input/hms-harmful-brain-activity-classification/train.csv\"\n    test_csv = \"/kaggle/input/hms-harmful-brain-activity-classification/test.csv\"\n    test_eeg = \"/kaggle/input/hms-harmful-brain-activity-classification/test_eegs\"\n    test_spec = \"/kaggle/input/hms-harmful-brain-activity-classification/test_spectrograms\"\n    out = \"/kaggle/working/\"","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:39:49.849151Z","iopub.execute_input":"2024-03-12T07:39:49.849573Z","iopub.status.idle":"2024-03-12T07:39:49.857149Z","shell.execute_reply.started":"2024-03-12T07:39:49.849524Z","shell.execute_reply":"2024-03-12T07:39:49.856107Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(paths.train_csv)\ntargets = df.columns[-6:]\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T05:55:43.336702Z","iopub.execute_input":"2024-03-12T05:55:43.337033Z","iopub.status.idle":"2024-03-12T05:55:43.605446Z","shell.execute_reply.started":"2024-03-12T05:55:43.337004Z","shell.execute_reply":"2024-03-12T05:55:43.604237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"targets","metadata":{"execution":{"iopub.status.busy":"2024-03-12T05:55:43.608519Z","iopub.execute_input":"2024-03-12T05:55:43.608968Z","iopub.status.idle":"2024-03-12T05:55:43.616843Z","shell.execute_reply.started":"2024-03-12T05:55:43.608930Z","shell.execute_reply":"2024-03-12T05:55:43.615709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = df.groupby('eeg_id')[['spectrogram_id','spectrogram_label_offset_seconds']].agg({\n    'spectrogram_id':'first',\n    'spectrogram_label_offset_seconds':'min'\n})\ntrain_df.columns = ['spectogram_id','min']\n\naux = df.groupby('eeg_id')[['spectrogram_id','spectrogram_label_offset_seconds']].agg({\n    'spectrogram_label_offset_seconds':'max'\n})\ntrain_df['max'] = aux\n\naux = df.groupby('eeg_id')[['patient_id']].agg('first')\ntrain_df['patient_id'] = aux\n\naux = df.groupby('eeg_id')[targets].agg('sum')\nfor label in targets:\n    train_df[label] = aux[label].values\n    \ny_data = train_df[targets].values\ny_data = y_data / y_data.sum(axis=1,keepdims=True)\ntrain_df[targets] = y_data\n\naux = df.groupby('eeg_id')[['expert_consensus']].agg('first')\ntrain_df['target'] = aux\n\ntrain_df = train_df.reset_index()\nprint('Train non-overlapp eeg_id shape:', train_df.shape )\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-03-12T05:55:43.618337Z","iopub.execute_input":"2024-03-12T05:55:43.618700Z","iopub.status.idle":"2024-03-12T05:55:43.726788Z","shell.execute_reply.started":"2024-03-12T05:55:43.618666Z","shell.execute_reply":"2024-03-12T05:55:43.725673Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"spectrograms = np.load('/kaggle/input/brain-spectrograms/specs.npy',allow_pickle=True).item()\neegs = np.load(paths.preloadedeeg,allow_pickle = True).item()\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T05:55:43.727932Z","iopub.execute_input":"2024-03-12T05:55:43.728259Z","iopub.status.idle":"2024-03-12T05:57:52.483743Z","shell.execute_reply.started":"2024-03-12T05:55:43.728213Z","shell.execute_reply":"2024-03-12T05:57:52.482828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import KFold, GroupKFold\ngfold = GroupKFold(n_splits = config.splits)\nfor fold,(trainindex,validationindex) in enumerate(gfold.split(train_df,train_df[\"target\"],train_df[\"patient_id\"])):\n    train_df.loc[validationindex,\"fold\"] = int(fold)\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T05:57:52.485590Z","iopub.execute_input":"2024-03-12T05:57:52.486019Z","iopub.status.idle":"2024-03-12T05:57:52.517139Z","shell.execute_reply.started":"2024-03-12T05:57:52.485982Z","shell.execute_reply":"2024-03-12T05:57:52.516317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ntrain_df","metadata":{"execution":{"iopub.status.busy":"2024-03-12T05:57:52.518525Z","iopub.execute_input":"2024-03-12T05:57:52.519332Z","iopub.status.idle":"2024-03-12T05:57:52.551448Z","shell.execute_reply.started":"2024-03-12T05:57:52.519291Z","shell.execute_reply":"2024-03-12T05:57:52.550092Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomDataset():\n    def __init__(self,traindf,config,mode:str=\"train\",specs:dict[int,np.ndarray]=spectrograms,eegs:dict[int,np.ndarray]=eegs):\n        self.traindf = traindf\n        self.specs = specs\n        self.eeg = eegs\n        self.mode = mode\n    def __len__(self):\n        return len(self.traindf)\n    def __getitem__(self,idx):\n        X = np.zeros((128, 256, 8), dtype='float32')\n        y = np.zeros(6, dtype='float32')\n        img = np.ones((128,256), dtype='float32')\n        row = self.traindf.iloc[idx]\n        if self.mode=='test': \n            r = 0\n        else: \n            r = int((row['min'] + row['max']) // 4)\n            \n        for region in range(4):\n            img = self.specs[row.spectogram_id][r:r+300, region*100:(region+1)*100].T\n            \n            # Log transform spectogram\n            img = np.clip(img, np.exp(-4), np.exp(8))\n            img = np.log(img)\n\n            # Standarize per image\n            ep = 1e-6\n            mu = np.nanmean(img.flatten())\n            std = np.nanstd(img.flatten())\n            img = (img-mu)/(std+ep)\n            img = np.nan_to_num(img, nan=0.0)\n            X[14:-14, :, region] = img[:, 22:-22] / 2.0\n            img = self.eeg[row.eeg_id]\n            X[:, :, 4:] = img\n        \n        X = torch.tensor(X)\n        spectograms = [X[:, :, i:i+1] for i in range(4)]\n        spectograms = torch.cat(spectograms, dim=0)\n        \n        # === Get EEG spectograms ===\n        eegs = [X[:, :, i:i+1] for i in range(4,8)]\n        eegs = torch.cat(eegs, dim=0)\n        \n        # === Reshape (512,512,3) ===\n        x = torch.cat([spectograms, eegs], dim=1)\n        x = torch.cat([x,x,x], dim=2)\n        x = x.permute(2, 0, 1)\n        if self.mode != 'test':\n            y = row[targets].values.astype(np.float32)            \n            \n        return {\"data\":x,\n                \"target\":y}\n        ","metadata":{"execution":{"iopub.status.busy":"2024-03-12T06:16:43.328025Z","iopub.execute_input":"2024-03-12T06:16:43.328900Z","iopub.status.idle":"2024-03-12T06:16:43.347061Z","shell.execute_reply.started":"2024-03-12T06:16:43.328862Z","shell.execute_reply":"2024-03-12T06:16:43.346094Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"customdataset = CustomDataset(train_df,config)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T06:16:43.517451Z","iopub.execute_input":"2024-03-12T06:16:43.517882Z","iopub.status.idle":"2024-03-12T06:16:43.522712Z","shell.execute_reply.started":"2024-03-12T06:16:43.517848Z","shell.execute_reply":"2024-03-12T06:16:43.521652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"customdataset[100][\"data\"].shape","metadata":{"execution":{"iopub.status.busy":"2024-03-12T06:16:43.712481Z","iopub.execute_input":"2024-03-12T06:16:43.712926Z","iopub.status.idle":"2024-03-12T06:16:43.730942Z","shell.execute_reply.started":"2024-03-12T06:16:43.712892Z","shell.execute_reply":"2024-03-12T06:16:43.729828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader\ntrainloader = DataLoader(customdataset,batch_size = config.batchsize)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T06:16:43.889339Z","iopub.execute_input":"2024-03-12T06:16:43.889753Z","iopub.status.idle":"2024-03-12T06:16:43.894898Z","shell.execute_reply.started":"2024-03-12T06:16:43.889723Z","shell.execute_reply":"2024-03-12T06:16:43.893946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import timm","metadata":{"execution":{"iopub.status.busy":"2024-03-12T06:16:44.091374Z","iopub.execute_input":"2024-03-12T06:16:44.091729Z","iopub.status.idle":"2024-03-12T06:16:44.096052Z","shell.execute_reply.started":"2024-03-12T06:16:44.091703Z","shell.execute_reply":"2024-03-12T06:16:44.095153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchvision.transforms import transforms\ntras = transforms.Compose([\n    transforms.Resize((224,224))\n])","metadata":{"execution":{"iopub.status.busy":"2024-03-12T06:16:44.444318Z","iopub.execute_input":"2024-03-12T06:16:44.444795Z","iopub.status.idle":"2024-03-12T06:16:44.450851Z","shell.execute_reply.started":"2024-03-12T06:16:44.444758Z","shell.execute_reply":"2024-03-12T06:16:44.449686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchvision.models as models\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T06:16:44.680650Z","iopub.execute_input":"2024-03-12T06:16:44.681088Z","iopub.status.idle":"2024-03-12T06:16:44.685724Z","shell.execute_reply.started":"2024-03-12T06:16:44.681038Z","shell.execute_reply":"2024-03-12T06:16:44.684595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Custommodel(nn.Module):\n    def __init__(self,config,numclass:int=6):\n        super(Custommodel,self).__init__()\n        self.model = timm.create_model(\n            config.model,\n            pretrained = True,\n            drop_rate = 0.5\n            \n        )\n        in_features = self.model.fc.out_features\n        self.freeze_layers()\n        self.fc = nn.Sequential(\n            nn.Dropout(p=0.5),\n            nn.ReLU(),\n            nn.Linear(in_features = in_features,out_features = numclass)\n        )\n    def freeze_layers(self):\n        num_layers_to_freeze = 10\n        #the reset has 61 layer out of which I am freezing the top 6 ones\n        for i, param in enumerate(self.model.parameters()):\n            if i < num_layers_to_freeze:\n                param.requires_grad = False\n\n    def forward(self,x):\n        x = self.model(x)\n        x = self.fc(x)\n        #x = self.customlayer(x)\n        return x\n        ","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:39:58.708181Z","iopub.execute_input":"2024-03-12T07:39:58.708657Z","iopub.status.idle":"2024-03-12T07:39:58.717774Z","shell.execute_reply.started":"2024-03-12T07:39:58.708602Z","shell.execute_reply":"2024-03-12T07:39:58.716677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = Custommodel(config)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:39:59.073488Z","iopub.execute_input":"2024-03-12T07:39:59.074450Z","iopub.status.idle":"2024-03-12T07:40:00.744022Z","shell.execute_reply.started":"2024-03-12T07:39:59.074399Z","shell.execute_reply":"2024-03-12T07:40:00.742948Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**The resne model has 61 layers  and in order to prevent the overfitting i am freezing the top 6 layer by making them require grad = False so now their parameters wont be upadated because of gradient descent**","metadata":{}},{"cell_type":"code","source":"for name, param in model.named_parameters():\n    print(f'{name}: requires_grad={param.requires_grad}')\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:40:03.359610Z","iopub.execute_input":"2024-03-12T07:40:03.360010Z","iopub.status.idle":"2024-03-12T07:40:03.368526Z","shell.execute_reply.started":"2024-03-12T07:40:03.359977Z","shell.execute_reply":"2024-03-12T07:40:03.367292Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom  = Custommodel(config)\ncustom(torch.randn(size = (1,3,224,224)))","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:40:03.580424Z","iopub.execute_input":"2024-03-12T07:40:03.581245Z","iopub.status.idle":"2024-03-12T07:40:04.325874Z","shell.execute_reply.started":"2024-03-12T07:40:03.581211Z","shell.execute_reply":"2024-03-12T07:40:04.324736Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"criterion = torch.nn.KLDivLoss(reduction=\"mean\")\nfrom torch.optim.lr_scheduler import OneCycleLR\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:40:04.327862Z","iopub.execute_input":"2024-03-12T07:40:04.328603Z","iopub.status.idle":"2024-03-12T07:40:04.333647Z","shell.execute_reply.started":"2024-03-12T07:40:04.328565Z","shell.execute_reply":"2024-03-12T07:40:04.332586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def trainer(model,trainloader,optimizer,criterion,device):\n  model.train()\n  iterationloss = 0\n  counter = 0\n  for data in tqdm(trainloader):\n    message = data['data'].to(device)\n    target = data['target'].to(device).squeeze()\n    optimizer.zero_grad()\n    out = model(message)\n    loss = criterion(F.log_softmax(out, dim=1), target)\n    loss.backward()\n    optimizer.step()\n    iterationloss+=loss.item()*message.shape[0]\n    counter+=message.shape[0]\n  return iterationloss/counter","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:40:04.334905Z","iopub.execute_input":"2024-03-12T07:40:04.335368Z","iopub.status.idle":"2024-03-12T07:40:04.349308Z","shell.execute_reply.started":"2024-03-12T07:40:04.335336Z","shell.execute_reply":"2024-03-12T07:40:04.348345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def tester(model,testloader,criterion,device):\n  model.eval()\n  iterationloss = 0\n  counter = 0\n  for data in testloader:\n    message = data['data'].to(device)\n    target = data['target'].to(device).squeeze()\n    with torch.no_grad():\n      out = model(message)\n      loss = criterion(F.log_softmax(out, dim=1), target)\n      iterationloss+=loss*message.shape[0]\n      #print(loss)  \n    counter+=message.shape[0]\n  return float(iterationloss)/float(counter)\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:40:04.351336Z","iopub.execute_input":"2024-03-12T07:40:04.351955Z","iopub.status.idle":"2024-03-12T07:40:04.359477Z","shell.execute_reply.started":"2024-03-12T07:40:04.351913Z","shell.execute_reply":"2024-03-12T07:40:04.358587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def trainepoch(fold,train_loss,val_loss):\n    traindf = train_df[train_df[\"fold\"]!=fold].reset_index(drop = True)\n    validdf = train_df[train_df[\"fold\"]==fold].reset_index(drop = True)\n    \n    traindataset = CustomDataset(traindf,config,mode = \"train\")\n    validdataset = CustomDataset(validdf,config,mode = \"train\")\n    \n    trainloader = DataLoader(traindataset,batch_size = config.batchsize)\n    validloader = DataLoader(validdataset,batch_size = config.batchsize)\n    \n    model = Custommodel(config)\n    model.to(device)\n    \n    optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=config.WEIGHT_DECAY)\n    \n    scheduler = OneCycleLR(\n        optimizer,\n        max_lr=1e-3,\n        epochs=config.epoch,\n        steps_per_epoch=len(trainloader),\n        pct_start=0.1,\n        anneal_strategy=\"cos\",\n        final_div_factor=100,\n    )\n    \n    criterion = torch.nn.KLDivLoss(reduction=\"batchmean\")\n    bestloss = np.inf\n    \n    bestloss = np.inf\n    for i in (range(10)):\n        print(\"-\"*120)\n        print(\"Began iteration no.\",i+1)\n        print(\":\"*50,\"=\"*20,\":\"*50)\n        trainloss = trainer(model,trainloader,optimizer,criterion,device)\n        testloss = tester(model,validloader,criterion,device)\n        train_loss.append(trainloss)\n        val_loss.append(testloss)\n        print(\"train loss = \",trainloss)\n        print(\"val loss=\",testloss)\n        print(\"=\"*80,\"\\n\")\n        if testloss<bestloss:\n            bestloss = testloss\n            dic = {\n            'model': model.state_dict()\n            }\n            torch.save(dic,'./Bestmodel.model'+str(fold))\n            print(\"Improved and saved the model\\n\")\n        print(\"=\"*100)\n","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:40:04.560817Z","iopub.execute_input":"2024-03-12T07:40:04.561535Z","iopub.status.idle":"2024-03-12T07:40:04.574410Z","shell.execute_reply.started":"2024-03-12T07:40:04.561504Z","shell.execute_reply":"2024-03-12T07:40:04.573214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainlist = []\nvalidlist = []\nfor fold in range(config.FOLDS):\n    if fold in [0, 1, 2, 3, 4]:\n        print(\"fold = \",fold)\n        trainepoch(fold,trainlist,validlist)","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:40:04.897076Z","iopub.execute_input":"2024-03-12T07:40:04.897982Z","iopub.status.idle":"2024-03-12T07:40:07.060204Z","shell.execute_reply.started":"2024-03-12T07:40:04.897948Z","shell.execute_reply":"2024-03-12T07:40:07.057988Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cus = CustomDataset(train_df,config,transform)\ncus[0][\"data\"]","metadata":{"execution":{"iopub.status.busy":"2024-03-12T07:40:07.061799Z","iopub.status.idle":"2024-03-12T07:40:07.062421Z","shell.execute_reply.started":"2024-03-12T07:40:07.062130Z","shell.execute_reply":"2024-03-12T07:40:07.062155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"timm.list_models()","metadata":{"execution":{"iopub.status.busy":"2024-03-11T20:40:09.152541Z","iopub.status.idle":"2024-03-11T20:40:09.152891Z","shell.execute_reply.started":"2024-03-11T20:40:09.152727Z","shell.execute_reply":"2024-03-11T20:40:09.152741Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}