{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"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"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":92399,"databundleVersionId":11038207,"sourceType":"competition"},{"sourceId":10873310,"sourceType":"datasetVersion","datasetId":6755742},{"sourceId":10956513,"sourceType":"datasetVersion","datasetId":6816118}],"dockerImageVersionId":30919,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport pylab\nimport imageio\nimport matplotlib.pyplot as plt\nimport gc\nfrom skimage.transform import resize\nimport sklearn\nfrom tqdm import tqdm\n\nfrom fastai.vision.all import *\nimport torch\nfrom torch.utils.data import Dataset\nimport torchvision\nimport torch.nn as nn\n\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:02.112022Z","iopub.execute_input":"2025-03-01T00:52:02.112307Z","iopub.status.idle":"2025-03-01T00:52:12.715159Z","shell.execute_reply.started":"2025-03-01T00:52:02.112286Z","shell.execute_reply":"2025-03-01T00:52:12.714291Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SEED = 777\nT = 64\nD = 4#2/0.8521975877123097,4/0.8522762446280044,8/0.8430938616430157,16/0.833909535266062\nS = 3\nBS = 16\nEPOCHS = 3\nFOLDS = [1,2,3,4,5]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:12.716219Z","iopub.execute_input":"2025-03-01T00:52:12.716426Z","iopub.status.idle":"2025-03-01T00:52:12.720288Z","shell.execute_reply.started":"2025-03-01T00:52:12.716408Z","shell.execute_reply":"2025-03-01T00:52:12.71956Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv('/kaggle/input/nexar-collision-prediction/train.csv')\ntrain.tail()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:12.72214Z","iopub.execute_input":"2025-03-01T00:52:12.722352Z","iopub.status.idle":"2025-03-01T00:52:12.759104Z","shell.execute_reply.started":"2025-03-01T00:52:12.722333Z","shell.execute_reply":"2025-03-01T00:52:12.758447Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_md = pd.read_csv('/kaggle/input/nexar-huggingface-data/huggingface_data.csv')\ntrain_md['id'] = train_md['file_name'].apply(lambda v:int(v[:-4]))\ntrain_md.tail()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = train.merge(train_md[['file_name','light_conditions','weather','scene','id']],left_on='id',right_on='id')\ntrain.tail()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train[['light_conditions','weather','scene','target']] = train[['light_conditions','weather','scene','target']].replace(np.nan,'NaN')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class clip_train_Dataset(Dataset):\n    def __init__(self, df):\n        self.df = df\n        self.df['mixup'] = True\n        for _,gb in self.df.groupby(['light_conditions','weather','scene','target']):\n            if len(gb) == 1:\n                self.df.loc[self.df['id']==gb['id'].values[0],'mixup'] = False\n        self.mixup = self.df[self.df['mixup']==True].reset_index(drop=True)\n        self.idx = 2*list(range(len(df)))\n        self.flip = len(df)*[0] + len(df)*[1]\n        mixup = int(.2*len(df))\n        self.idx = self.idx + mixup*[-1]\n        self.flip = self.flip + mixup*[-1]\n        self.randomrot = torchvision.transforms.RandomRotation(30, interpolation=torchvision.transforms.InterpolationMode.BILINEAR, expand=False, center=None, fill=0)\n\n    def __len__(self):\n        return len(self.idx)\n    \n    def __rowitem__(self,row,flip,x):\n        sample = str(int(row['id']))\n        sample = '0'*(5-len(sample)) + sample\n        vid = imageio.get_reader('/kaggle/input/nexar-256x256/train_resized/'+sample+'_256x256.mp4',  'ffmpeg')\n        md = vid.get_meta_data()\n        if row['target']:\n            end = np.rint(md['fps']*(row['time_of_event'] - 0.5 - x)).astype(int)\n            start = end - T*S\n            if start < 0:\n                clip = np.stack([vid.get_data(num) for num in range(0,end,S)])\n                clip = np.pad(clip, ((T-len(clip),0),(0,0),(0,0),(0,0)), 'constant')\n            else:\n                clip = np.stack([vid.get_data(num) for num in range(start,end,S)]) \n\n        else:\n            tts = np.rint(md['duration']*md['fps']).astype(int)\n            start = int(x*(tts - T*S))\n            clip = np.stack([vid.get_data(num) for num in range(start,start+T*S,S)])\n\n        clip = torch.as_tensor(np.stack(clip)).float().to(device)/255\n#       Flip\n        if flip: clip = clip.flip(-1)\n\n        return clip,torch.as_tensor(row['target']).float().to(device)\n\n    def __getitem__(self, idx):\n        \n        x = np.random.rand()\n        if self.idx[idx] == -1:\n            row1 = self.mixup.loc[np.random.randint(len(self.mixup))]\n            clip1,target = self.__rowitem__(row1,np.random.rand()<.5,x)\n            mixup = self.mixup[self.mixup['target']==row1['target']]\n            mixup = mixup[mixup['light_conditions']==row1['light_conditions']]\n            mixup = mixup[mixup['weather']==row1['weather']]\n            mixup = mixup[mixup['scene']==row1['scene']]\n            mixup = mixup[mixup['id']!=row1['id']].reset_index(drop=True)\n            if len(mixup) > 1:\n                row2 = mixup.loc[np.random.randint(len(mixup))]\n            else:\n                row2 = mixup.loc[0]\n            clip2,target = self.__rowitem__(row2,np.random.rand()<.5,x)\n            clip = torch.stack([clip1,clip2]).max(0)[0]#(clip1+clip2)/2\n        else:\n            clip,target = self.__rowitem__(self.df.loc[self.idx[idx]],self.flip[idx],x)        \n#       Random rotation\n        clip = nn.functional.pad(clip.permute(0,3,1,2),(56,56,56,56),'reflect')\n        clip = self.randomrot(clip)[...,56:-56,56:-56]\n#       Random crop\n        h = np.random.randint(32)\n        w = np.random.randint(32)\n        clip = clip[...,h:h+224,w:w+224]\n#       Gaussian Noise\n        clip += torch.normal(0,.025,(clip.shape[1],224,224),device=device)\n#       CONTRAST\n        clip *= np.random.normal(1,.1)\n#       BRIGTHNESS\n        clip += np.random.normal(0,.1)\n\n        return clip,target","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ds = clip_train_Dataset(train)\nlen(ds)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:12.77175Z","iopub.execute_input":"2025-03-01T00:52:12.772011Z","iopub.status.idle":"2025-03-01T00:52:12.785705Z","shell.execute_reply.started":"2025-03-01T00:52:12.771984Z","shell.execute_reply":"2025-03-01T00:52:12.785014Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"clip,target = ds.__getitem__(np.random.randint(len(ds)))\nprint(target)\nplt.imshow(clip[T//2].permute(1,2,0).cpu())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:12.786369Z","iopub.execute_input":"2025-03-01T00:52:12.78667Z","iopub.status.idle":"2025-03-01T00:52:14.230384Z","shell.execute_reply.started":"2025-03-01T00:52:12.78664Z","shell.execute_reply":"2025-03-01T00:52:14.2294Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"clip,target = ds.__getitem__(len(ds)-1)\nprint(target)\nplt.imshow(clip[T//2].permute(1,2,0).cpu())","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"del ds\ngc.collect()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:14.231626Z","iopub.execute_input":"2025-03-01T00:52:14.231896Z","iopub.status.idle":"2025-03-01T00:52:14.474999Z","shell.execute_reply.started":"2025-03-01T00:52:14.231873Z","shell.execute_reply":"2025-03-01T00:52:14.474237Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class clip_valid_Dataset(Dataset):\n    def __init__(self, df):\n        self.df = df\n        self.idx = list(range(len(df)))*3\n        self.tta = [0]*len(df) + [1]*len(df) + [2]*len(df)\n\n    def __len__(self):\n        return len(self.idx)\n\n    def __getitem__(self, idx):\n        \n        row = self.df.loc[self.idx[idx]]\n        sample = str(int(row['id']))\n        sample = '0'*(5-len(sample)) + sample\n        vid = imageio.get_reader('/kaggle/input/nexar-256x256/train_resized/'+sample+'_256x256.mp4',  'ffmpeg')\n        md = vid.get_meta_data()\n        if row['target']:\n            end = np.rint(md['fps']*(row['time_of_event'] - .5*(self.tta[idx] + 1))).astype(int)\n            start = end - T*S\n            if start < 0:\n                clip = np.stack([vid.get_data(num) for num in range(0,end,S)])\n                clip = np.pad(clip, ((T-len(clip),0),(0,0),(0,0),(0,0)), 'constant')\n            else:\n                clip = np.stack([vid.get_data(num) for num in range(start,end,S)])                \n\n        else:\n            tts = int(md['duration']*md['fps'])\n            step = (tts - T*S)//2\n            start = step*self.tta[idx]\n            clip = np.stack([vid.get_data(num) for num in range(start,start+T*S,S)])\n\n        clip = torch.as_tensor(np.stack(clip)).float().to(device).permute(0,3,1,2)/255\n\n        return clip,torch.as_tensor(row['target']).float().to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:14.47734Z","iopub.execute_input":"2025-03-01T00:52:14.477565Z","iopub.status.idle":"2025-03-01T00:52:14.493764Z","shell.execute_reply.started":"2025-03-01T00:52:14.477546Z","shell.execute_reply":"2025-03-01T00:52:14.492889Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ds = clip_valid_Dataset(train)\nlen(ds)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:14.495337Z","iopub.execute_input":"2025-03-01T00:52:14.495651Z","iopub.status.idle":"2025-03-01T00:52:14.506586Z","shell.execute_reply.started":"2025-03-01T00:52:14.495618Z","shell.execute_reply":"2025-03-01T00:52:14.505904Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"clip,target = ds.__getitem__(np.random.randint(len(ds)))\nprint(target)\nprint(clip.shape)\nplt.imshow(clip[T//2].permute(1,2,0).cpu())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:14.507301Z","iopub.execute_input":"2025-03-01T00:52:14.507534Z","iopub.status.idle":"2025-03-01T00:52:15.14338Z","shell.execute_reply.started":"2025-03-01T00:52:14.507514Z","shell.execute_reply":"2025-03-01T00:52:15.142394Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"del ds\ngc.collect()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:15.144324Z","iopub.execute_input":"2025-03-01T00:52:15.144582Z","iopub.status.idle":"2025-03-01T00:52:15.388686Z","shell.execute_reply.started":"2025-03-01T00:52:15.144559Z","shell.execute_reply":"2025-03-01T00:52:15.387983Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def seed_everything(seed):\n    random.seed(seed)\n    np.random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:15.389524Z","iopub.execute_input":"2025-03-01T00:52:15.38975Z","iopub.status.idle":"2025-03-01T00:52:15.401024Z","shell.execute_reply.started":"2025-03-01T00:52:15.389717Z","shell.execute_reply":"2025-03-01T00:52:15.400172Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"seed_everything(SEED)\npositives = train[train['target'] == 1].sample(frac=1)\nnegatives = train[train['target'] == 0].sample(frac=1)\npositives['fold'] = negatives['fold'] = [1]*150 + [2]*150 + [3]*150 + [4]*150 + [5]*150\ntrain = pd.concat([positives,negatives]).reset_index(drop=True)\ntrain.tail()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:15.401886Z","iopub.execute_input":"2025-03-01T00:52:15.402198Z","iopub.status.idle":"2025-03-01T00:52:15.435216Z","shell.execute_reply.started":"2025-03-01T00:52:15.402168Z","shell.execute_reply":"2025-03-01T00:52:15.434403Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision.models import resnet18\n\nclass myCNNGRU(nn.Module):\n    def __init__(self):\n        super().__init__()\n        # 2D Backbone\n        self.cnn = resnet18(weights=ResNet18_Weights.IMAGENET1K_V1)\n        self.cnn.fc = nn.Identity()\n        \n        # Temporal Model\n        self.gru = nn.GRU(input_size=512, hidden_size=128, bidirectional=True)\n        self.classifier = nn.Linear(256, 1)\n\n    def forward(self, x):\n        # x: [batch, frames, C, H, W]\n        batch_size, T = x.shape[:2]\n        x = x.view(-1, *x.shape[2:])  # Merge batch + time\n        x = self.cnn(x)  # [batch*T, 512]\n        x = x.view(batch_size, T, -1)  # Unmerge\n        x, _ = self.gru(x)  # [batch, T, 256]\n        x = x[:, -D:].mean(1)  # Last D timesteps\n        x = self.classifier(x)\n        return x.view(-1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:15.436107Z","iopub.execute_input":"2025-03-01T00:52:15.436397Z","iopub.status.idle":"2025-03-01T00:52:15.442292Z","shell.execute_reply.started":"2025-03-01T00:52:15.436368Z","shell.execute_reply":"2025-03-01T00:52:15.441418Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for f in FOLDS:\n    seed_everything(SEED)\n    model = torch.nn.DataParallel(myCNNGRU(), device_ids=[0,1])\n\n    train_df = train[train['fold'] != f].reset_index(drop=True)\n    valid_df = train[train['fold'] == f].reset_index(drop=True)\n\n    tds = clip_train_Dataset(train_df)\n    vds = clip_valid_Dataset(valid_df)\n    \n    tdl = torch.utils.data.DataLoader(tds, batch_size=BS, shuffle=True, drop_last=True)\n    vdl = torch.utils.data.DataLoader(vds, batch_size=BS, shuffle=False)\n\n    dls = DataLoaders(tdl,vdl)\n\n    learn = Learner(\n        dls,\n        model,\n        loss_func=nn.BCEWithLogitsLoss(),\n        cbs=[\n            ShowGraphCallback()\n        ]\n    )\n    learn.fit_one_cycle(EPOCHS, lr_max=2.5e-5)\n    torch.save(model,'myCNNGRU_'+str(f))\n\n    del model,train_df,valid_df,tds,vds,tdl,vdl,dls,learn","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T00:52:15.455863Z","iopub.execute_input":"2025-03-01T00:52:15.456084Z","execution_failed":"2025-03-01T00:52:51.945Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_t = []\ny_p = []\ny_s = []\nwith torch.no_grad():\n    for f in FOLDS:\n        model = torch.load('myCNNGRU_'+str(f))\n        valid_df = train[train['fold'] == f].reset_index(drop=True)\n        vds = clip_valid_Dataset(valid_df)\n        vdl = torch.utils.data.DataLoader(vds, batch_size=BS, shuffle=False)\n        for b in tqdm(vdl):\n            y_t = y_t + b[1].tolist()\n            y_pred = (model(b[0]).sigmoid() + model(b[0].flip(-1)).sigmoid())/2\n            y_s = y_s + y_pred.tolist()\n            y_p = y_p + (y_pred > .5).tolist()\n\n        del model,valid_df,vds,vdl\n        gc.collect()\n\nsklearn.metrics.confusion_matrix(y_t, y_p)","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-01T00:52:51.945Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport pandas.api.types\n\nimport sklearn.metrics\n\nclass ParticipantVisibleError(Exception):\n    pass\n\ndef score(solution: pd.DataFrame, submission: pd.DataFrame, group_column_name: str = \"group\") -> float:\n    '''\n    Mean of the Average Precision AP. AP is calculated for each grouped by wrapping\n    https://scikit-learn.org/stable/modules/generated/sklearn.metrics.average_precision_score.html\n    and then the mean of the APs of all grouped is computed.\n\n    AP summarizes a precision-recall curve as the weighted mean of precisions\n    achieved at each threshold, with the increase in recall from the previous\n    threshold used as the weight:\n\n    .. math::\n    \\text{AP} = \\sum_n (R_n - R_{n-1}) P_n\n\n    where :math:`P_n` and :math:`R_n` are the precision and recall at the nth\n    threshold [1]_. This implementation is not interpolated and is different\n    from computing the area under the precision-recall curve with the\n    trapezoidal rule, which uses linear interpolation and can be too\n    optimistic.\n\n    Note: this implementation is restricted to the binary classification task.\n\n    Parameters\n    ----------\n    solution : ndarray of shape (n_samples,) or (n_samples, n_classes)\n    True binary labels or binary label indicators.\n\n    submission : ndarray of shape (n_samples,) or (n_samples, n_classes)\n    Target scores, can either be probability estimates of the positive\n    class, confidence values, or non-thresholded measure of decisions\n    (as returned by :term:`decision_function` on some classifiers).\n\n\n    Examples\n    --------\n\n    >>> import pandas as pd\n    >>> import numpy as np\n    >>> y_true = np.array([1, 0, 0, 0] + [1,0,0,1] + [1,0,1,1])\n    >>> y_true = pd.DataFrame(y_true)\n    >>> y_true[\"id\"] = range(len(y_true))\n    >>> y_true[\"group\"] = [\"a\", \"a\", \"a\", \"a\", \"b\", \"b\", \"b\", \"b\", \"c\", \"c\", \"c\", \"c\"]\n    >>> y_pred = np.array([0.1, 0.4, 0.35, 0.8] * 3)\n    >>> y_pred = pd.DataFrame(y_pred)\n    >>> y_pred[\"id\"] = range(len(y_pred))\n    >>> score(y_true.copy(), y_pred.copy(), \"id\", \"group\")\n    0.6018518518518519\n    '''\n\n    if not group_column_name in solution.columns:\n        raise ParticipantVisibleError('Missing group column in solution')\n\n    group = solution[group_column_name]\n    del solution[group_column_name]\n    del submission[group_column_name]\n    groups = group.unique()\n    \n    if not((len(submission.columns) == 1) or (len(submission.columns) == len(solution.columns))):\n        raise ParticipantVisibleError(f'Invalid number of submission columns. Found {len(submission.columns)}')\n\n    if not pandas.api.types.is_numeric_dtype(submission.values):\n        bad_dtypes = {x: submission[x].dtype  for x in submission.columns if not pandas.api.types.is_numeric_dtype(submission[x])}\n        raise ParticipantVisibleError(f'Invalid submission data types found: {bad_dtypes}')\n\n    if submission.max().max() > 1 or submission.min().min() < 0:\n        raise ParticipantVisibleError('Submitted values were not valid probabilities')\n\n    solution = solution.values\n    submission = submission.values\n\n    score_result = np.mean([\n        sklearn.metrics.average_precision_score(solution[group == g], submission[group == g])\n        for g in groups\n    ])\n\n    return score_result","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-01T00:52:51.945Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame({\n    'group':([0]*300 + [1]*300 + [2]*300)*len(FOLDS),\n    'score':np.array(y_s)\n})\nsolution = pd.DataFrame({\n    'group':([0]*300 + [1]*300 + [2]*300)*len(FOLDS),\n    'score':np.array(y_t)\n})\nscore(solution,submission)","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-01T00:52:51.945Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class clip_test_Dataset(Dataset):\n    def __init__(self, df):\n        self.df = df\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        \n        row = self.df.loc[idx]\n        sample = str(int(row['id']))\n        sample = '0'*(5-len(sample)) + sample\n        vid = imageio.get_reader('/kaggle/input/nexar-256x256/test_resized/'+sample+'_256x256.mp4',  'ffmpeg')\n        md = vid.get_meta_data()\n        end = int(md['duration']*md['fps'])\n        start = end - T\n        if start < 0:\n            clip = np.stack([vid.get_data(num) for num in range(0,end,S)])\n            clip = np.pad(clip, ((T-len(clip),0),(0,0),(0,0),(0,0)), 'constant')\n        else:\n            clip = np.stack([vid.get_data(num) for num in range(start,end,S)])                \n\n        clip = torch.as_tensor(np.stack(clip)).float().to(device).permute(0,3,1,2)/255\n\n        return clip","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-01T00:52:51.946Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df = pd.read_csv('/kaggle/input/nexar-collision-prediction/test.csv')\ntest_df.head()","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-01T00:52:51.946Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"models = [torch.load('myCNNGRU_'+str(f)) for f in FOLDS]","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-01T00:52:51.946Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ds = clip_test_Dataset(test_df)\ndl = torch.utils.data.DataLoader(ds, batch_size=BS, shuffle=False)\nwith torch.no_grad():\n    score = []\n    for X in tqdm(dl):\n        y_pred = 0\n        for model in models:\n            y_pred += model(X).sigmoid() + model(X.flip(-1)).sigmoid()\n        score = score + (y_pred/(2*len(models))).tolist()","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-01T00:52:51.946Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df['score'] = score\ntest_df.to_csv('submission.csv',index=False)\ntest_df.tail()","metadata":{"trusted":true,"execution":{"execution_failed":"2025-03-01T00:52:51.946Z"}},"outputs":[],"execution_count":null}]}