{"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":151114859,"sourceType":"kernelVersion"}],"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-05T10:04:49.516956Z","iopub.execute_input":"2023-11-05T10:04:49.517546Z","iopub.status.idle":"2023-11-05T10:05:01.181622Z","shell.execute_reply.started":"2023-11-05T10:04:49.517511Z","shell.execute_reply":"2023-11-05T10:05:01.180683Z"},"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-05T10:05:07.517421Z","iopub.execute_input":"2023-11-05T10:05:07.518158Z","iopub.status.idle":"2023-11-05T10:05:11.240507Z","shell.execute_reply.started":"2023-11-05T10:05:07.518123Z","shell.execute_reply":"2023-11-05T10:05:11.239538Z"},"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-05T10:05:18.462107Z","iopub.execute_input":"2023-11-05T10:05:18.462607Z","iopub.status.idle":"2023-11-05T10:05:18.467545Z","shell.execute_reply.started":"2023-11-05T10:05:18.462576Z","shell.execute_reply":"2023-11-05T10:05:18.466526Z"},"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-05T10:05:19.178183Z","iopub.execute_input":"2023-11-05T10:05:19.179094Z","iopub.status.idle":"2023-11-05T10:05:20.123462Z","shell.execute_reply.started":"2023-11-05T10:05:19.179059Z","shell.execute_reply":"2023-11-05T10:05:20.122303Z"},"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-05T10:05:23.415787Z","iopub.execute_input":"2023-11-05T10:05:23.416742Z","iopub.status.idle":"2023-11-05T10:05:23.6641Z","shell.execute_reply.started":"2023-11-05T10:05:23.416704Z","shell.execute_reply":"2023-11-05T10:05:23.663175Z"},"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-05T10:06:08.646103Z","iopub.execute_input":"2023-11-05T10:06:08.646507Z","iopub.status.idle":"2023-11-05T10:06:08.65307Z","shell.execute_reply.started":"2023-11-05T10:06:08.646478Z","shell.execute_reply":"2023-11-05T10:06:08.651985Z"},"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-05T10:06:08.96171Z","iopub.execute_input":"2023-11-05T10:06:08.962081Z","iopub.status.idle":"2023-11-05T10:06:08.970314Z","shell.execute_reply.started":"2023-11-05T10:06:08.962053Z","shell.execute_reply":"2023-11-05T10:06:08.969318Z"},"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=20, minute=30, tzinfo=timezone.utc)\n    lower_bound = upper_bound + timedelta(hours=-24) # 8:30pm 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-05T10:09:20.862542Z","iopub.execute_input":"2023-11-05T10:09:20.863176Z","iopub.status.idle":"2023-11-05T10:09:21.585872Z","shell.execute_reply.started":"2023-11-05T10:09:20.863144Z","shell.execute_reply":"2023-11-05T10:09:21.584942Z"},"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-05T10:09:31.403936Z","iopub.execute_input":"2023-11-05T10:09:31.404841Z","iopub.status.idle":"2023-11-05T10:09:31.422115Z","shell.execute_reply.started":"2023-11-05T10:09:31.404802Z","shell.execute_reply":"2023-11-05T10:09:31.420814Z"},"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    transforms.append(T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]))\n    return T.Compose(transforms)","metadata":{"execution":{"iopub.status.busy":"2023-11-05T10:09:54.777633Z","iopub.execute_input":"2023-11-05T10:09:54.778603Z","iopub.status.idle":"2023-11-05T10:09:54.784208Z","shell.execute_reply.started":"2023-11-05T10:09:54.778557Z","shell.execute_reply":"2023-11-05T10:09:54.782974Z"},"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-05T10:09:57.579195Z","iopub.execute_input":"2023-11-05T10:09:57.580055Z","iopub.status.idle":"2023-11-05T10:09:57.585096Z","shell.execute_reply.started":"2023-11-05T10:09:57.580009Z","shell.execute_reply":"2023-11-05T10:09:57.583832Z"},"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-05T10:10:00.486718Z","iopub.execute_input":"2023-11-05T10:10:00.487487Z","iopub.status.idle":"2023-11-05T10:10:00.528272Z","shell.execute_reply.started":"2023-11-05T10:10:00.48745Z","shell.execute_reply":"2023-11-05T10:10:00.52732Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = 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-05T10:10:19.315146Z","iopub.execute_input":"2023-11-05T10:10:19.31551Z","iopub.status.idle":"2023-11-05T10:10:20.000314Z","shell.execute_reply.started":"2023-11-05T10:10:19.315477Z","shell.execute_reply":"2023-11-05T10:10:19.999231Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"weights = torch.load(\"/kaggle/input/d-s-s-faster-r-cnn-modeling/m12_4.pth\", map_location=device)\nmodel.load_state_dict(weights)","metadata":{"execution":{"iopub.status.busy":"2023-11-05T10:10:20.002142Z","iopub.execute_input":"2023-11-05T10:10:20.002437Z","iopub.status.idle":"2023-11-05T10:10:25.26001Z","shell.execute_reply.started":"2023-11-05T10:10:20.002412Z","shell.execute_reply":"2023-11-05T10:10:25.258952Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.to(device);","metadata":{"execution":{"iopub.status.busy":"2023-11-05T10:10:25.26151Z","iopub.execute_input":"2023-11-05T10:10:25.261805Z","iopub.status.idle":"2023-11-05T10:10:25.328268Z","shell.execute_reply.started":"2023-11-05T10:10:25.261779Z","shell.execute_reply":"2023-11-05T10:10:25.327265Z"},"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-05T10:10:38.726771Z","iopub.execute_input":"2023-11-05T10:10:38.727488Z","iopub.status.idle":"2023-11-05T10:10:38.733199Z","shell.execute_reply.started":"2023-11-05T10:10:38.727454Z","shell.execute_reply":"2023-11-05T10:10:38.732135Z"},"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 # All images have width 1,440px.\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-05T10:15:00.567501Z","iopub.execute_input":"2023-11-05T10:15:00.568211Z","iopub.status.idle":"2023-11-05T10:15:00.583304Z","shell.execute_reply.started":"2023-11-05T10:15:00.568175Z","shell.execute_reply":"2023-11-05T10:15:00.582242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df = get_submission_df()\nsubmission_df","metadata":{"execution":{"iopub.status.busy":"2023-11-05T10:15:01.747003Z","iopub.execute_input":"2023-11-05T10:15:01.747679Z","iopub.status.idle":"2023-11-05T10:15:01.920534Z","shell.execute_reply.started":"2023-11-05T10:15:01.747646Z","shell.execute_reply":"2023-11-05T10:15:01.919573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!rm -rf /kaggle/working/images","metadata":{"execution":{"iopub.status.busy":"2023-11-05T10:15:24.496124Z","iopub.execute_input":"2023-11-05T10:15:24.496496Z","iopub.status.idle":"2023-11-05T10:15:25.478617Z","shell.execute_reply.started":"2023-11-05T10:15:24.496463Z","shell.execute_reply":"2023-11-05T10:15:25.477271Z"},"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-05T10:15:25.480716Z","iopub.execute_input":"2023-11-05T10:15:25.481061Z","iopub.status.idle":"2023-11-05T10:15:25.49549Z","shell.execute_reply.started":"2023-11-05T10:15:25.481032Z","shell.execute_reply":"2023-11-05T10:15:25.494404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}