{"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"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":53666,"databundleVersionId":6589269,"sourceType":"competition"},{"sourceId":6919113,"sourceType":"datasetVersion","datasetId":3913135}],"dockerImageVersionId":30559,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip show torchvision","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:18.026817Z","iopub.execute_input":"2023-11-17T06:00:18.027182Z","iopub.status.idle":"2023-11-17T06:00:29.068013Z","shell.execute_reply.started":"2023-11-17T06:00:18.027147Z","shell.execute_reply":"2023-11-17T06:00:29.066869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nfrom pathlib import Path\nimport numpy as np\nimport pandas as pd\nfrom datetime import datetime, timezone, timedelta\nimport matplotlib.pyplot as plt\nimport matplotlib\nmatplotlib.use(\"Agg\")\nimport torch\nimport torchvision\nfrom torchvision.io import read_image\nfrom torchvision.transforms import v2 as T\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:31.979975Z","iopub.execute_input":"2023-11-17T06:00:31.980651Z","iopub.status.idle":"2023-11-17T06:00:31.986946Z","shell.execute_reply.started":"2023-11-17T06:00:31.980601Z","shell.execute_reply":"2023-11-17T06:00:31.985946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Object detection data prep","metadata":{}},{"cell_type":"code","source":"working_folder = Path(\"/kaggle/working/\")\nimages_folder = working_folder/\"images\"\nimages_folder.mkdir()","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:35.387307Z","iopub.execute_input":"2023-11-17T06:00:35.388035Z","iopub.status.idle":"2023-11-17T06:00:35.392590Z","shell.execute_reply.started":"2023-11-17T06:00:35.388002Z","shell.execute_reply":"2023-11-17T06:00:35.391691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_folder = Path(\"/kaggle/input/child-mind-institute-detect-sleep-states\")\n!ls {data_folder}","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:38.406107Z","iopub.execute_input":"2023-11-17T06:00:38.406480Z","iopub.status.idle":"2023-11-17T06:00:39.379554Z","shell.execute_reply.started":"2023-11-17T06:00:38.406451Z","shell.execute_reply":"2023-11-17T06:00:39.378036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_series = pd.read_parquet(data_folder/\"test_series.parquet\")\ntest_series","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:40.972422Z","iopub.execute_input":"2023-11-17T06:00:40.972833Z","iopub.status.idle":"2023-11-17T06:00:41.205461Z","shell.execute_reply.started":"2023-11-17T06:00:40.972796Z","shell.execute_reply":"2023-11-17T06:00:41.204497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_series['large_enmo'] = test_series['enmo'] > 0.1506","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:44.078421Z","iopub.execute_input":"2023-11-17T06:00:44.078833Z","iopub.status.idle":"2023-11-17T06:00:44.084738Z","shell.execute_reply.started":"2023-11-17T06:00:44.078800Z","shell.execute_reply":"2023-11-17T06:00:44.083698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"series_ids = test_series['series_id'].unique()\nlen(series_ids)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:45.995443Z","iopub.execute_input":"2023-11-17T06:00:45.996237Z","iopub.status.idle":"2023-11-17T06:00:46.004046Z","shell.execute_reply.started":"2023-11-17T06:00:45.996201Z","shell.execute_reply":"2023-11-17T06:00:46.002946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"window_properties = []\nfor i in range(len(series_ids)):\n    print(\"i:\", i)\n    print(\"series_id:\", series_ids[i])\n    series = test_series.loc[test_series['series_id'] == series_ids[i]].reset_index(drop=True)\n    series['color'] = [\"blue\" if large_enmo else \"green\" for large_enmo in series['large_enmo']]\n    series['timestamp'] = pd.to_datetime(series['timestamp'])\n    series['timestamp_utc'] = series['timestamp'].map(lambda timestamp: timestamp.astimezone(timezone.utc))\n    series['anglez_radians'] = (np.pi / 180) * series['anglez']\n    series['cos_anglez'] = np.cos(series['anglez_radians'])\n    series['enmo'] = np.clip(series['enmo'], 0, 1)\n    min_date_utc = series['timestamp_utc'].dt.date.min()\n    max_date_utc = series['timestamp_utc'].dt.date.max()\n    series_24_hour_windows = {}    \n    upper_bound = datetime(year=min_date_utc.year, month=min_date_utc.month, day=min_date_utc.day, hour=17, tzinfo=timezone.utc)\n    lower_bound = upper_bound + timedelta(hours=-24) # 5pm UTC on the previous day.\n    while lower_bound < series['timestamp_utc'].max():\n        window_df = series.loc[(series['timestamp_utc'] >= lower_bound) & (series['timestamp_utc'] < upper_bound)].reset_index(drop=True)\n        if len(window_df) > 0:\n            series_24_hour_windows[upper_bound.isoformat()[:-6]] = window_df\n        upper_bound += timedelta(hours=24)\n        lower_bound += timedelta(hours=24)\n    \n    windows = list(series_24_hour_windows.keys())\n    num_steps_cumulative = 0\n    for window_idx, window in enumerate(windows):        \n        fig = plt.figure(figsize=(14.4, 4))  # (width, height) in inches\n        plt.plot(series_24_hour_windows[window]['timestamp_utc'], series_24_hour_windows[window]['cos_anglez'], color=\"red\")\n        plt.scatter(series_24_hour_windows[window]['timestamp_utc'], series_24_hour_windows[window]['enmo'], color=series_24_hour_windows[window]['color'], s=1)\n        ax = plt.gca()\n        ax.spines['top'].set_visible(False)\n        ax.spines['right'].set_visible(False)\n        ax.spines['bottom'].set_visible(False)\n        ax.spines['left'].set_visible(False)\n        ax.set_xticks([])\n        ax.set_yticks([])\n        plt.margins(0, 0)\n        plt.subplots_adjust(left=0, right=1, top=1, bottom=0)\n        plt.savefig(images_folder/f\"{series_ids[i]}_{window}.jpg\", bbox_inches=\"tight\", pad_inches=0)\n        plt.clf()\n        plt.cla()\n        plt.close()\n\n        min_ts_window = series_24_hour_windows[window]['timestamp_utc'].min()\n        max_ts_window = series_24_hour_windows[window]['timestamp_utc'].max()\n        num_steps_window = (max_ts_window - min_ts_window).total_seconds() / 5 + 1\n        num_steps_cumulative += num_steps_window\n        window_properties.append({\n            'series_id': series_ids[i], \n            'image_name': f\"{series_ids[i]}_{window}.jpg\", \n            'idx_in_series': window_idx, \n            'num_steps_window': num_steps_window, \n            'num_steps_cumulative': num_steps_cumulative\n        })","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:49.617428Z","iopub.execute_input":"2023-11-17T06:00:49.618146Z","iopub.status.idle":"2023-11-17T06:00:50.318193Z","shell.execute_reply.started":"2023-11-17T06:00:49.618112Z","shell.execute_reply":"2023-11-17T06:00:50.317415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"window_properties_df = pd.DataFrame(window_properties)\nwindow_properties_df","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:54.021370Z","iopub.execute_input":"2023-11-17T06:00:54.021766Z","iopub.status.idle":"2023-11-17T06:00:54.035775Z","shell.execute_reply.started":"2023-11-17T06:00:54.021734Z","shell.execute_reply":"2023-11-17T06:00:54.034656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Transforms","metadata":{}},{"cell_type":"code","source":"def get_transforms():\n    transforms = []\n    transforms.append(T.ConvertDtype(torch.float))\n    return T.Compose(transforms)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:00:57.241844Z","iopub.execute_input":"2023-11-17T06:00:57.242510Z","iopub.status.idle":"2023-11-17T06:00:57.247242Z","shell.execute_reply.started":"2023-11-17T06:00:57.242478Z","shell.execute_reply":"2023-11-17T06:00:57.246095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"From the <a href=\"https://pytorch.org/vision/0.15/generated/torchvision.transforms.v2.ConvertDtype.html\" target=\"_blank\">documentation</a>:\n\n> Convert input image or video to the given `dtype` and scale the values accordingly.","metadata":{}},{"cell_type":"code","source":"eval_transforms = get_transforms()","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:00.261471Z","iopub.execute_input":"2023-11-17T06:01:00.262198Z","iopub.status.idle":"2023-11-17T06:01:00.266512Z","shell.execute_reply.started":"2023-11-17T06:01:00.262163Z","shell.execute_reply":"2023-11-17T06:01:00.265561Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Instantiating the model","metadata":{}},{"cell_type":"code","source":"device = torch.device(\"cuda\") if torch.cuda.is_available() else torch.device(\"cpu\")\ndevice","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:04.019221Z","iopub.execute_input":"2023-11-17T06:01:04.019874Z","iopub.status.idle":"2023-11-17T06:01:04.059130Z","shell.execute_reply.started":"2023-11-17T06:01:04.019841Z","shell.execute_reply":"2023-11-17T06:01:04.058197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load an object detection model pre-trained on COCO:\nmodel = torchvision.models.detection.fasterrcnn_resnet50_fpn(weights=None, weights_backbone=None, max_size=1440)\n# Replace the classifier with a new one, that has num_classes which is user-defined:\nnum_classes = 3 # 2 classes ('onset' & 'wakeup') + the 'background' class\n# Get the number of input features for the box classifier:\nin_features = model.roi_heads.box_predictor.cls_score.in_features\n# Replace the pre-trained box predictor head with a new one:\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:07.774073Z","iopub.execute_input":"2023-11-17T06:01:07.774993Z","iopub.status.idle":"2023-11-17T06:01:08.472072Z","shell.execute_reply.started":"2023-11-17T06:01:07.774958Z","shell.execute_reply":"2023-11-17T06:01:08.471208Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"weights = torch.load(\"/kaggle/input/c-m-i-d-s-s-extra-data/m1_4.pth\", map_location=device)\nmodel.load_state_dict(weights)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:11.157852Z","iopub.execute_input":"2023-11-17T06:01:11.158219Z","iopub.status.idle":"2023-11-17T06:01:16.095800Z","shell.execute_reply.started":"2023-11-17T06:01:11.158182Z","shell.execute_reply":"2023-11-17T06:01:16.094546Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.to(device);","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:18.194190Z","iopub.execute_input":"2023-11-17T06:01:18.195131Z","iopub.status.idle":"2023-11-17T06:01:18.260441Z","shell.execute_reply.started":"2023-11-17T06:01:18.195097Z","shell.execute_reply":"2023-11-17T06:01:18.259693Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"model.eval()\nthresh = 0.0 # Tune this.\nreverse_label_mapping = {1: \"onset\", 2: \"wakeup\"}","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:21.167618Z","iopub.execute_input":"2023-11-17T06:01:21.168581Z","iopub.status.idle":"2023-11-17T06:01:21.174719Z","shell.execute_reply.started":"2023-11-17T06:01:21.168544Z","shell.execute_reply":"2023-11-17T06:01:21.173395Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_submission_df():\n    all_test_preds = []\n    for i, series_id in enumerate(series_ids): # i is the index of the series.\n        series_rows = window_properties_df.loc[window_properties_df['series_id'] == series_id].reset_index(drop=True)\n        for j in range(len(series_rows)): # j is the index of the image (within the series).\n            image_name = series_rows['image_name'][j]\n            image_path = os.path.join(images_folder, image_name)\n            image = read_image(image_path)\n            with torch.no_grad():\n                x = eval_transforms(image)\n                x = x.to(device)\n                predictions = model([x])\n            pred = predictions[0]\n            \n            # Postprocessing: remove 'narrow' boxes as these are false positives.\n            pred_widths = pred['boxes'][:, 2] - pred['boxes'][:, 0]\n            pred['boxes'] = pred['boxes'][pred_widths > 10]\n            pred['labels'] = pred['labels'][pred_widths > 10]\n            pred['scores'] = pred['scores'][pred_widths > 10]\n            \n            pred['boxes'] = pred['boxes'][pred['scores'] > thresh]\n            pred['labels'] = pred['labels'][pred['scores'] > thresh]\n            pred['scores'] = pred['scores'][pred['scores'] > thresh]\n            \n            if len(pred['labels']) == 0:\n                continue\n            else:\n                pred_x = (pred['boxes'][:, 0] + pred['boxes'][:, 2]) / 2\n                pred_labels = [reverse_label_mapping[l.item()] for l in pred['labels']]\n                num_steps_window = series_rows['num_steps_window'][j]\n                if j == 0:\n                    prev_num_steps_cumulative = 0\n                else:\n                    prev_num_steps_cumulative = series_rows['num_steps_cumulative'][j - 1]            \n                for k in range(len(pred_labels)): # k is the index of the bounding box (within the image).\n                    event = {}\n                    step_in_window = (pred_x[k] / 1440) * num_steps_window\n                    step_in_series = int(prev_num_steps_cumulative + step_in_window)\n                    event['series_id'] = series_id\n                    event['step'] = step_in_series\n                    event['event'] = pred_labels[k]\n                    event['score'] = pred['scores'][k].item()\n                    all_test_preds.append(event)          \n    if len(all_test_preds) > 0:\n        submission_df = pd.DataFrame(all_test_preds)\n        submission_df = submission_df.sort_values(by=['series_id', 'step']).reset_index(drop=True)\n        submission_df['row_id'] = np.arange(len(submission_df))\n        submission_df = submission_df[['row_id', 'series_id', 'step', 'event', 'score']]\n    else:\n        submission_df = pd.DataFrame({'row_id': [], 'series_id': [], 'step': [], 'event': [], 'score': []})\n    return submission_df","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:23.662505Z","iopub.execute_input":"2023-11-17T06:01:23.663508Z","iopub.status.idle":"2023-11-17T06:01:23.681696Z","shell.execute_reply.started":"2023-11-17T06:01:23.663472Z","shell.execute_reply":"2023-11-17T06:01:23.680681Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df = get_submission_df()\nsubmission_df","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:31.163999Z","iopub.execute_input":"2023-11-17T06:01:31.164672Z","iopub.status.idle":"2023-11-17T06:01:36.117428Z","shell.execute_reply.started":"2023-11-17T06:01:31.164632Z","shell.execute_reply":"2023-11-17T06:01:36.116462Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!rm -rf /kaggle/working/images","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:38.747538Z","iopub.execute_input":"2023-11-17T06:01:38.748382Z","iopub.status.idle":"2023-11-17T06:01:39.732758Z","shell.execute_reply.started":"2023-11-17T06:01:38.748348Z","shell.execute_reply":"2023-11-17T06:01:39.731506Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2023-11-17T06:01:41.501270Z","iopub.execute_input":"2023-11-17T06:01:41.502105Z","iopub.status.idle":"2023-11-17T06:01:41.513443Z","shell.execute_reply.started":"2023-11-17T06:01:41.502068Z","shell.execute_reply":"2023-11-17T06:01:41.512568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}