{"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":"markdown","source":"# Analyse des données","metadata":{}},{"cell_type":"code","source":"# paths\n\nTEST_DIR = '/kaggle/input/nfl-player-contact-detection/test'\nTRAIN_DIR = '/kaggle/input/nfl-player-contact-detection/train'\n\nTEST_BASELINE_HELMETS = '/kaggle/input/nfl-player-contact-detection/test_baseline_helmets.csv'\nTRAIN_BASELINE_HELMETS = '/kaggle/input/nfl-player-contact-detection/train_baseline_helmets.csv'\n\nTEST_PLAYER_TRACKING = '/kaggle/input/nfl-player-contact-detection/test_player_tracking.csv'\nTRAIN_PLAYER_TRACKING = '/kaggle/input/nfl-player-contact-detection/train_player_tracking.csv'\n\nTEST_VIDEO_METADATA = '/kaggle/input/nfl-player-contact-detection/test_video_metadata.csv'\nTRAIN_VIDEO_METADATA = '/kaggle/input/nfl-player-contact-detection/train_video_metadata.csv'\n\nTRAIN_LABELS = '/kaggle/input/nfl-player-contact-detection/train_labels.csv'\nSAMPLE_SUBMISSION = '/kaggle/input/nfl-player-contact-detection/sample_submission.csv'","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:15.723852Z","iopub.execute_input":"2023-02-02T17:19:15.724824Z","iopub.status.idle":"2023-02-02T17:19:15.731388Z","shell.execute_reply.started":"2023-02-02T17:19:15.724768Z","shell.execute_reply":"2023-02-02T17:19:15.730221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Imports","metadata":{"_kg_hide-input":false,"_kg_hide-output":true}},{"cell_type":"code","source":"import sys\nsys.path.append('/kaggle/input/fasteda')","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:15.733738Z","iopub.execute_input":"2023-02-02T17:19:15.734466Z","iopub.status.idle":"2023-02-02T17:19:15.742834Z","shell.execute_reply.started":"2023-02-02T17:19:15.734428Z","shell.execute_reply":"2023-02-02T17:19:15.741899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# from fasteda import fast_eda\n# import pandas as pd","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:15.746865Z","iopub.execute_input":"2023-02-02T17:19:15.747148Z","iopub.status.idle":"2023-02-02T17:19:15.753902Z","shell.execute_reply.started":"2023-02-02T17:19:15.747123Z","shell.execute_reply":"2023-02-02T17:19:15.752940Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# players_df = pd.read_csv(TRAIN_PLAYER_TRACKING, parse_dates=[\"datetime\"])\n# helmets_df = pd.read_csv(TRAIN_BASELINE_HELMETS)\n# labels_df = pd.read_csv(TRAIN_LABELS, parse_dates=[\"datetime\"])\n# video_metadata_df = pd.read_csv(TEST_VIDEO_METADATA, parse_dates=[\"start_time\", \"end_time\", \"snap_time\"])","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:15.755573Z","iopub.execute_input":"2023-02-02T17:19:15.756358Z","iopub.status.idle":"2023-02-02T17:19:15.764472Z","shell.execute_reply.started":"2023-02-02T17:19:15.756320Z","shell.execute_reply":"2023-02-02T17:19:15.763562Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Données joueurs","metadata":{}},{"cell_type":"code","source":"# players_df.nunique()","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:15.768222Z","iopub.execute_input":"2023-02-02T17:19:15.768490Z","iopub.status.idle":"2023-02-02T17:19:15.774531Z","shell.execute_reply.started":"2023-02-02T17:19:15.768466Z","shell.execute_reply":"2023-02-02T17:19:15.773527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# fast_eda(players_df.drop([\"datetime\"], axis=1))","metadata":{"_kg_hide-output":false,"_kg_hide-input":false,"scrolled":true,"execution":{"iopub.status.busy":"2023-02-02T17:19:15.775560Z","iopub.execute_input":"2023-02-02T17:19:15.775804Z","iopub.status.idle":"2023-02-02T17:19:15.784540Z","shell.execute_reply.started":"2023-02-02T17:19:15.775776Z","shell.execute_reply":"2023-02-02T17:19:15.783727Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Données casques","metadata":{}},{"cell_type":"code","source":"# fast_eda(helmets_df)","metadata":{"_kg_hide-output":true,"scrolled":true,"execution":{"iopub.status.busy":"2023-02-02T17:19:15.786381Z","iopub.execute_input":"2023-02-02T17:19:15.786722Z","iopub.status.idle":"2023-02-02T17:19:15.793643Z","shell.execute_reply.started":"2023-02-02T17:19:15.786689Z","shell.execute_reply":"2023-02-02T17:19:15.792665Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Données vidéos","metadata":{}},{"cell_type":"code","source":"# fast_eda(video_metadata_df)\n# video_metadata_df.nunique()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2023-02-02T17:19:15.795197Z","iopub.execute_input":"2023-02-02T17:19:15.795919Z","iopub.status.idle":"2023-02-02T17:19:15.803391Z","shell.execute_reply.started":"2023-02-02T17:19:15.795882Z","shell.execute_reply":"2023-02-02T17:19:15.802497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Données label","metadata":{}},{"cell_type":"code","source":"# fast_eda(labels_df.drop([\"datetime\"], axis=1))","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2023-02-02T17:19:15.805061Z","iopub.execute_input":"2023-02-02T17:19:15.805457Z","iopub.status.idle":"2023-02-02T17:19:15.814115Z","shell.execute_reply.started":"2023-02-02T17:19:15.805420Z","shell.execute_reply":"2023-02-02T17:19:15.813313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Terrain","metadata":{}},{"cell_type":"code","source":"import matplotlib.patches as patches\nimport matplotlib.pylab as plt\n\ndef create_football_field(\n    linenumbers=True,\n    endzones=True,\n    figsize=(12, 6.33),\n    line_color=\"black\",\n    field_color=\"white\",\n    ez_color=None,\n    ax=None,\n    return_fig=False,\n):\n    \"\"\"\n    Function that plots the football field for viewing plays.\n    Allows for showing or hiding endzones.\n    \"\"\"\n\n    if ez_color is None:\n        ez_color = field_color\n\n    rect = patches.Rectangle(\n        (0, 0),\n        120,\n        53.3,\n        linewidth=0.1,\n        edgecolor=\"r\",\n        facecolor=field_color,\n        zorder=0,\n    )\n\n    if ax is None:\n        fig, ax = plt.subplots(1, figsize=figsize)\n    ax.add_patch(rect)\n    ax.plot([10, 10, 10, 20, 20, 30, 30, 40, 40, 50, 50, 60, 60, 70, 70, 80,\n              80, 90, 90, 100, 100, 110, 110, 120, 0, 0, 120, 120],\n             [0, 0, 53.3, 53.3, 0, 0, 53.3, 53.3, 0, 0, 53.3, 53.3, 0, 0, 53.3,\n              53.3, 0, 0, 53.3, 53.3, 0, 0, 53.3, 53.3, 53.3, 0, 0, 53.3],\n             color=line_color)\n    \n    # Endzones\n    if endzones:\n        ez1 = patches.Rectangle(\n            (0, 0),\n            10,\n            53.3,\n            linewidth=0.1,\n            edgecolor=line_color,\n            facecolor=ez_color,\n            alpha=0.6,\n            zorder=0,\n        )\n        ez2 = patches.Rectangle(\n            (110, 0),\n            10,\n            53.3,\n            linewidth=0.1,\n            edgecolor=line_color,\n            facecolor=ez_color,\n            alpha=0.6,\n            zorder=0,\n        )\n        ax.add_patch(ez1)\n        ax.add_patch(ez2)\n\n    ax.axis(\"off\")\n    if linenumbers:\n        for x in range(20, 110, 10):\n            numb = x\n            if x > 50:\n                numb = 120 - x\n            ax.text(\n                x,\n                5,\n                str(numb - 10),\n                horizontalalignment=\"center\",\n                fontsize=20,  # fontname='Arial',\n                color=line_color,\n            )\n            ax.text(\n                x - 0.95,\n                53.3 - 5,\n                str(numb - 10),\n                horizontalalignment=\"center\",\n                fontsize=20,  # fontname='Arial',\n                color=line_color,\n                rotation=180,\n            )\n    if endzones:\n        hash_range = range(11, 110)\n    else:\n        hash_range = range(1, 120)\n\n    for x in hash_range:\n        ax.plot([x, x], [0.4, 0.7], color=line_color)\n        ax.plot([x, x], [53.0, 52.5], color=line_color)\n        ax.plot([x, x], [22.91, 23.57], color=line_color)\n        ax.plot([x, x], [29.73, 30.39], color=line_color)\n\n    border = patches.Rectangle(\n        (-5, -5),\n        120 + 10,\n        53.3 + 10,\n        linewidth=0.1,\n        edgecolor=\"orange\",\n        facecolor=line_color,\n        alpha=0,\n        zorder=0,\n    )\n    ax.add_patch(border)\n    ax.set_xlim((-5, 125))\n    ax.set_ylim((-5, 53.3 + 5))\n\n    if return_fig:\n        return fig, ax\n    else:\n        return ax","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:15.857729Z","iopub.execute_input":"2023-02-02T17:19:15.858455Z","iopub.status.idle":"2023-02-02T17:19:15.880458Z","shell.execute_reply.started":"2023-02-02T17:19:15.858411Z","shell.execute_reply":"2023-02-02T17:19:15.879448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# game_play = \"58168_003392\"\n# example_tracks = players_df.query(\"game_play == @game_play and step == 0\")\n# ax = create_football_field()\n# for team, d in example_tracks.groupby(\"team\"):\n#     ax.scatter(\n#         d[\"x_position\"],\n#         d[\"y_position\"],\n#         label=team,\n#         s=65,\n#         lw=1,\n#         edgecolors=\"black\",\n#         zorder=5,\n#     )\n# ax.legend().remove()\n# ax.set_title(f\"Tracking data for {game_play}: at step 0\", fontsize=15)\n# plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:15.882825Z","iopub.execute_input":"2023-02-02T17:19:15.883271Z","iopub.status.idle":"2023-02-02T17:19:15.891337Z","shell.execute_reply.started":"2023-02-02T17:19:15.883228Z","shell.execute_reply":"2023-02-02T17:19:15.890341Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Vidéos","metadata":{}},{"cell_type":"code","source":"def join_helmets_contact(game_play, labels, helmets, meta, view=\"Sideline\", fps=59.94):\n    \"\"\"\n    Joins helmets and labels for a given game_play. Results can be used for visualizing labels.\n    Returns a dataframe with the joint dataframe, duplicating rows if multiple contacts occur.\n    \"\"\"\n    gp_labs = labels.query(\"game_play == @game_play\").copy()\n    gp_helms = helmets.query(\"game_play == @game_play\").copy()\n\n    start_time = meta.query(\"game_play == @game_play and view == @view\")[\n        \"start_time\"\n    ].values[0]\n\n    gp_helms[\"datetime\"] = (\n        pd.to_timedelta(gp_helms[\"frame\"] * (1 / fps), unit=\"s\") + start_time\n    )\n    gp_helms[\"datetime\"] = pd.to_datetime(gp_helms[\"datetime\"], utc=True)\n    gp_helms[\"datetime_ngs\"] = (\n        pd.DatetimeIndex(gp_helms[\"datetime\"] + pd.to_timedelta(50, \"ms\"))\n        .floor(\"100ms\")\n        .values\n    )\n    gp_helms[\"datetime_ngs\"] = pd.to_datetime(gp_helms[\"datetime_ngs\"], utc=True)\n\n    gp_labs[\"datetime_ngs\"] = pd.to_datetime(gp_labs[\"datetime\"], utc=True)\n\n    gp = gp_helms.merge(\n        gp_labs.query(\"contact == 1\")[\n            [\"datetime_ngs\", \"nfl_player_id_1\", \"nfl_player_id_2\", \"contact_id\"]\n        ],\n        left_on=[\"datetime_ngs\", \"nfl_player_id\"],\n        right_on=[\"datetime_ngs\", \"nfl_player_id_1\"],\n        how=\"left\",\n    )\n    del gp_helms, gp_labs\n    return gp","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:15.893188Z","iopub.execute_input":"2023-02-02T17:19:15.893669Z","iopub.status.idle":"2023-02-02T17:19:15.904601Z","shell.execute_reply.started":"2023-02-02T17:19:15.893634Z","shell.execute_reply":"2023-02-02T17:19:15.903564Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport cv2\nimport subprocess\nfrom IPython.display import Video, display\nimport pandas as pd\nimport numpy as np\n\n\ndef video_with_contact(video_path: str, baseline_boxes: pd.DataFrame, verbose=True) -> str:\n    \"\"\"\n    Annotates a video with baseline model boxes.\n    Helmet boxes are colored based on the contact label.\n    \"\"\"\n    VIDEO_CODEC = \"MP4V\"\n    HELMET_COLOR = (0, 0, 0)  # Black\n    video_name = os.path.basename(video_path)\n    if verbose:\n        print(f\"Running for {video_name}\")\n    baseline_boxes = baseline_boxes.copy()\n\n    vidcap = cv2.VideoCapture(video_path)\n    fps = vidcap.get(cv2.CAP_PROP_FPS)\n    width = int(vidcap.get(cv2.CAP_PROP_FRAME_WIDTH))\n    height = int(vidcap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n    output_path = \"contact_\" + video_name\n    tmp_output_path = \"tmp_\" + output_path\n    output_video = cv2.VideoWriter(tmp_output_path, cv2.VideoWriter_fourcc(*VIDEO_CODEC), fps, (width, height))\n    frame = 0\n    while True:\n        it_worked, img = vidcap.read()\n        if not it_worked:\n            break\n        # We need to add 1 to the frame count to match the label frame index\n        # that starts at 1\n        frame += 1\n\n        # Let's add a frame index to the video so we can track where we are\n        img_name = video_name.replace('.mp4','')\n        cv2.putText(img, img_name, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, HELMET_COLOR, thickness=1)        \n        cv2.putText(img, str(frame), (1280 - 90, 720 - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, HELMET_COLOR, thickness=1)\n\n        # Now, add the boxes\n        boxes = baseline_boxes.query(\"video == @video_name and frame == @frame\")\n        contact_players = boxes.dropna(subset=[\"nfl_player_id_2\"]).query(\n            'nfl_player_id_2 != \"G\"'\n        )\n        contact_ids = (\n            contact_players[\"nfl_player_id_1\"].astype(\"int\").values.tolist()\n            + contact_players[\"nfl_player_id_2\"].astype(\"int\").values.tolist()\n        )\n        for box in boxes.itertuples(index=False):\n\n            if box.nfl_player_id_2 == \"G\":\n                box_color = (0, 0, 255)  # Red\n                box_thickness = 2\n            elif int(box.nfl_player_id) in contact_ids:\n                box_color = (0, 255, 0)  # green\n                box_thickness = 2\n                # Add line between players in contact\n                if not np.isnan(float(box.nfl_player_id_2)):\n                    player2 = int(box.nfl_player_id_2)\n                    player2_row = boxes.query(\"nfl_player_id == @player2\")\n                    if len(player2_row) == 0:\n                        # Player 2 is not in view\n                        continue\n                    p1 = (box.left + int(box.width / 2), box.top + int(box.height / 2))\n                    p2 = (\n                        player2_row.left.values[0] + int(player2_row.width.values[0] / 2),\n                        player2_row.top.values[0] + int(player2_row.height.values[0] / 2),\n                    )\n                    cv2.line(img, p1, p2, color=(255, 0, 0), thickness=2)\n\n            else:\n                box_color = HELMET_COLOR\n                box_thickness = 1\n\n            # Draw lines between two boxes\n\n            cv2.rectangle(img, (box.left, box.top), (box.left + box.width, box.top + box.height), box_color, thickness=box_thickness)\n            cv2.putText(img, box.player_label, (box.left + 1, max(0, box.top - 20)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, HELMET_COLOR, thickness=1)\n\n        output_video.write(img)\n    output_video.release()\n    # Not all browsers support the codec, we will re-load the file at tmp_output_path\n    # and convert to a codec that is more broadly readable using ffmpeg\n    if os.path.exists(output_path):\n        os.remove(output_path)\n    subprocess.run(\"ffmpeg -i {} -crf 18 -preset veryfast -hide_banner -loglevel error -vcodec libx264 {}\".format(tmp_output_path, output_path).split(\" \"))\n    os.remove(tmp_output_path)\n    \n    del tmp_output_path, output_video, boxes, contact_players, contact_ids\n\n    return output_path","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:15.906456Z","iopub.execute_input":"2023-02-02T17:19:15.906847Z","iopub.status.idle":"2023-02-02T17:19:16.089031Z","shell.execute_reply.started":"2023-02-02T17:19:15.906814Z","shell.execute_reply":"2023-02-02T17:19:16.088088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# game_play = \"58172_003247\"\n# gp = join_helmets_contact(game_play, labels_df, helmets_df, video_metadata_df)\n\n# example_video = f\"../input/nfl-player-contact-detection/train/{game_play}_Sideline.mp4\"\n# output_video = video_with_contact(example_video, gp)\n\n# frac = 0.65  # scaling factor for display\n# display(Video(data=output_video, embed=True, height=int(720 * frac), width=int(1280 * frac)))\n# import gc\n# del example_video, output_video, gp, game_play, players_df, helmets_df, labels_df, video_metadata_df\n# gc.collect()","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:16.092130Z","iopub.execute_input":"2023-02-02T17:19:16.092491Z","iopub.status.idle":"2023-02-02T17:19:16.096942Z","shell.execute_reply.started":"2023-02-02T17:19:16.092456Z","shell.execute_reply":"2023-02-02T17:19:16.095834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Modélisation","metadata":{}},{"cell_type":"code","source":"import os\nimport sys\nsys.path.append('/kaggle/input/timm-0-6-9/pytorch-image-models-master')\nimport glob\nimport numpy as np\nimport pandas as pd\nimport random\nimport math\nimport gc\nimport cv2\nfrom tqdm import tqdm\nimport time\nfrom functools import lru_cache\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.cuda.amp import autocast, GradScaler\nimport timm\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import matthews_corrcoef","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:16.098681Z","iopub.execute_input":"2023-02-02T17:19:16.099125Z","iopub.status.idle":"2023-02-02T17:19:20.904280Z","shell.execute_reply.started":"2023-02-02T17:19:16.099090Z","shell.execute_reply":"2023-02-02T17:19:20.903206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"CFG = {\n    'seed': 42,\n    'model': 'resnet50',\n    'img_size': 256,\n    'epochs': 10,\n    'train_bs': 100, \n    'valid_bs': 64,\n    'lr': 1e-3, \n    'weight_decay': 1e-6,\n    'num_workers': 2\n}","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:20.906259Z","iopub.execute_input":"2023-02-02T17:19:20.906646Z","iopub.status.idle":"2023-02-02T17:19:20.914170Z","shell.execute_reply.started":"2023-02-02T17:19:20.906610Z","shell.execute_reply":"2023-02-02T17:19:20.912060Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n\nseed_everything(CFG['seed'])\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:20.915848Z","iopub.execute_input":"2023-02-02T17:19:20.916261Z","iopub.status.idle":"2023-02-02T17:19:20.993201Z","shell.execute_reply.started":"2023-02-02T17:19:20.916226Z","shell.execute_reply":"2023-02-02T17:19:20.992241Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def expand_contact_id(df):\n    \"\"\"\n    Splits out contact_id into seperate columns.\n    \"\"\"\n    df[\"game_play\"] = df[\"contact_id\"].str[:12]\n    df[\"step\"] = df[\"contact_id\"].str.split(\"_\").str[-3].astype(\"int\")\n    df[\"nfl_player_id_1\"] = df[\"contact_id\"].str.split(\"_\").str[-2]\n    df[\"nfl_player_id_2\"] = df[\"contact_id\"].str.split(\"_\").str[-1]\n    return df\n\nlabels = expand_contact_id(pd.read_csv(\"/kaggle/input/nfl-player-contact-detection/sample_submission.csv\"))\n\ntest_tracking = pd.read_csv(\"/kaggle/input/nfl-player-contact-detection/test_player_tracking.csv\")\n\ntest_helmets = pd.read_csv(\"/kaggle/input/nfl-player-contact-detection/test_baseline_helmets.csv\")\n\ntest_video_metadata = pd.read_csv(\"/kaggle/input/nfl-player-contact-detection/test_video_metadata.csv\")","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:20.994800Z","iopub.execute_input":"2023-02-02T17:19:20.995489Z","iopub.status.idle":"2023-02-02T17:19:21.728728Z","shell.execute_reply.started":"2023-02-02T17:19:20.995452Z","shell.execute_reply":"2023-02-02T17:19:21.727799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir -p ../work/frames\n\nfor video in tqdm(test_helmets.video.unique()):\n    if 'Endzone2' not in video:\n        !ffmpeg -i /kaggle/input/nfl-player-contact-detection/test/{video} -q:v 2 -f image2 /kaggle/work/frames/{video}_%04d.jpg -hide_banner -loglevel error","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:19:21.729946Z","iopub.execute_input":"2023-02-02T17:19:21.730325Z","iopub.status.idle":"2023-02-02T17:20:08.975584Z","shell.execute_reply.started":"2023-02-02T17:19:21.730291Z","shell.execute_reply":"2023-02-02T17:20:08.974315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_features(df, tr_tracking, merge_col=\"step\", use_cols=[\"x_position\", \"y_position\"]):\n    output_cols = []\n    df_combo = (\n        df.astype({\"nfl_player_id_1\": \"str\"})\n        .merge(\n            tr_tracking.astype({\"nfl_player_id\": \"str\"})[\n                [\"game_play\", merge_col, \"nfl_player_id\",] + use_cols\n            ],\n            left_on=[\"game_play\", merge_col, \"nfl_player_id_1\"],\n            right_on=[\"game_play\", merge_col, \"nfl_player_id\"],\n            how=\"left\",\n        )\n        .rename(columns={c: c+\"_1\" for c in use_cols})\n        .drop(\"nfl_player_id\", axis=1)\n        .merge(\n            tr_tracking.astype({\"nfl_player_id\": \"str\"})[\n                [\"game_play\", merge_col, \"nfl_player_id\"] + use_cols\n            ],\n            left_on=[\"game_play\", merge_col, \"nfl_player_id_2\"],\n            right_on=[\"game_play\", merge_col, \"nfl_player_id\"],\n            how=\"left\",\n        )\n        .drop(\"nfl_player_id\", axis=1)\n        .rename(columns={c: c+\"_2\" for c in use_cols})\n        .sort_values([\"game_play\", merge_col, \"nfl_player_id_1\", \"nfl_player_id_2\"])\n        .reset_index(drop=True)\n    )\n    output_cols += [c+\"_1\" for c in use_cols]\n    output_cols += [c+\"_2\" for c in use_cols]\n    \n    if (\"x_position\" in use_cols) & (\"y_position\" in use_cols):\n        index = df_combo['x_position_2'].notnull()\n        \n        distance_arr = np.full(len(index), np.nan)\n        tmp_distance_arr = np.sqrt(\n            np.square(df_combo.loc[index, \"x_position_1\"] - df_combo.loc[index, \"x_position_2\"])\n            + np.square(df_combo.loc[index, \"y_position_1\"]- df_combo.loc[index, \"y_position_2\"])\n        )\n        \n        distance_arr[index] = tmp_distance_arr\n        df_combo['distance'] = distance_arr\n        output_cols += [\"distance\"]\n        \n    df_combo['G_flug'] = (df_combo['nfl_player_id_2']==\"G\")\n    output_cols += [\"G_flug\"]\n    return df_combo, output_cols\n\n\nuse_cols = [\n    'x_position', 'y_position', 'speed', 'distance',\n    'direction', 'orientation', 'acceleration', 'sa'\n]\n\ntest, feature_cols = create_features(labels, test_tracking, use_cols=use_cols)\ntest\n","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:08.978055Z","iopub.execute_input":"2023-02-02T17:20:08.978454Z","iopub.status.idle":"2023-02-02T17:20:09.270040Z","shell.execute_reply.started":"2023-02-02T17:20:08.978413Z","shell.execute_reply":"2023-02-02T17:20:09.268917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train, feature_cols = create_features(labels, train_tracking, use_cols=use_cols)\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_filtered = test.query('not distance>2').reset_index(drop=True)\ntest_filtered['frame'] = (test_filtered['step']/10*59.94+5*59.94).astype('int')+1\ntest_filtered","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:09.271704Z","iopub.execute_input":"2023-02-02T17:20:09.272101Z","iopub.status.idle":"2023-02-02T17:20:09.321625Z","shell.execute_reply.started":"2023-02-02T17:20:09.272064Z","shell.execute_reply":"2023-02-02T17:20:09.320542Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_filtered = train.query('not distance>2').reset_index(drop=True)\ntrain_filtered['frame'] = (test_filtered['step']/10*59.94+5*59.94).astype('int')+1\ntrain_filtered","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del test, labels, test_tracking\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:09.323340Z","iopub.execute_input":"2023-02-02T17:20:09.323761Z","iopub.status.idle":"2023-02-02T17:20:09.566583Z","shell.execute_reply.started":"2023-02-02T17:20:09.323721Z","shell.execute_reply":"2023-02-02T17:20:09.565155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_aug = A.Compose([\n    A.HorizontalFlip(p=0.5),\n    A.ShiftScaleRotate(p=0.5),\n    A.RandomBrightnessContrast(brightness_limit=(-0.1, 0.1), contrast_limit=(-0.1, 0.1), p=0.5),\n    A.Normalize(mean=[0.], std=[1.]),\n    ToTensorV2()\n])\n\nvalid_aug = A.Compose([\n    A.Normalize(mean=[0.], std=[1.]),\n    ToTensorV2()\n])","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:09.575772Z","iopub.execute_input":"2023-02-02T17:20:09.576624Z","iopub.status.idle":"2023-02-02T17:20:09.774942Z","shell.execute_reply.started":"2023-02-02T17:20:09.576577Z","shell.execute_reply":"2023-02-02T17:20:09.773293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"video2helmets = {}\ntest_helmets_new = test_helmets.set_index('video')\nfor video in tqdm(test_helmets.video.unique()):\n    video2helmets[video] = test_helmets_new.loc[video].reset_index(drop=True)\n    \ndel test_helmets, test_helmets_new\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:09.778017Z","iopub.execute_input":"2023-02-02T17:20:09.779156Z","iopub.status.idle":"2023-02-02T17:20:09.966440Z","shell.execute_reply.started":"2023-02-02T17:20:09.779103Z","shell.execute_reply":"2023-02-02T17:20:09.962827Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"video2frames = {}\n\nfor game_play in tqdm(test_video_metadata.game_play.unique()):\n    for view in ['Endzone', 'Sideline']:\n        video = game_play + f'_{view}.mp4'\n        video2frames[video] = max(list(map(lambda x:int(x.split('_')[-1].split('.')[0]), \\\n                                           glob.glob(f'/kaggle/work/frames/{video}*'))))","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:09.969220Z","iopub.execute_input":"2023-02-02T17:20:09.970098Z","iopub.status.idle":"2023-02-02T17:20:10.016277Z","shell.execute_reply.started":"2023-02-02T17:20:09.970053Z","shell.execute_reply":"2023-02-02T17:20:10.015171Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MyDataset(Dataset):\n    def __init__(self, df, aug=valid_aug, mode='train'):\n        self.df = df\n        self.frame = df.frame.values\n        self.feature = df[feature_cols].fillna(-1).values\n        self.players = df[['nfl_player_id_1','nfl_player_id_2']].values\n        self.game_play = df.game_play.values\n        self.aug = aug\n        self.mode = mode\n        \n    def __len__(self):\n        return len(self.df)\n    \n    # @lru_cache(1024)\n    # def read_img(self, path):\n    #     return cv2.imread(path, 0)\n   \n    def __getitem__(self, idx):   \n        window = 24\n        frame = self.frame[idx]\n        \n        if self.mode == 'train':\n            frame = frame + random.randint(-6, 6)\n\n        players = []\n        for p in self.players[idx]:\n            if p == 'G':\n                players.append(p)\n            else:\n                players.append(int(p))\n        \n        imgs = []\n        for view in ['Endzone', 'Sideline']:\n            video = self.game_play[idx] + f'_{view}.mp4'\n\n            tmp = video2helmets[video]\n#             tmp = tmp.query('@frame-@window<=frame<=@frame+@window')\n            tmp[tmp['frame'].between(frame-window, frame+window)]\n            tmp = tmp[tmp.nfl_player_id.isin(players)]#.sort_values(['nfl_player_id', 'frame'])\n            tmp_frames = tmp.frame.values\n            tmp = tmp.groupby('frame')[['left','width','top','height']].mean()\n#0.002s\n\n            bboxes = []\n            for f in range(frame-window, frame+window+1, 1):\n                if f in tmp_frames:\n                    x, w, y, h = tmp.loc[f][['left','width','top','height']]\n                    bboxes.append([x, w, y, h])\n                else:\n                    bboxes.append([np.nan, np.nan, np.nan, np.nan])\n            bboxes = pd.DataFrame(bboxes).interpolate(limit_direction='both').values\n            bboxes = bboxes[::4]\n\n            if bboxes.sum() > 0:\n                flag = 1\n            else:\n                flag = 0\n#0.03s\n                    \n            for i, f in enumerate(range(frame-window, frame+window+1, 4)):\n                img_new = np.zeros((256, 256), dtype=np.float32)\n\n                if flag == 1 and f <= video2frames[video]:\n                    img = cv2.imread(f'/kaggle/work/frames/{video}_{f:04d}.jpg', 0)\n\n                    x, w, y, h = bboxes[i]\n\n                    img = img[int(y+h/2)-128:int(y+h/2)+128,int(x+w/2)-128:int(x+w/2)+128].copy()\n                    img_new[:img.shape[0], :img.shape[1]] = img\n                    \n                imgs.append(img_new)\n#0.06s\n                \n        feature = np.float32(self.feature[idx])\n\n        img = np.array(imgs).transpose(1, 2, 0)    \n        img = self.aug(image=img)[\"image\"]\n        label = np.float32(self.df.contact.values[idx])\n\n        return img, feature, label","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:10.017884Z","iopub.execute_input":"2023-02-02T17:20:10.018467Z","iopub.status.idle":"2023-02-02T17:20:10.036327Z","shell.execute_reply.started":"2023-02-02T17:20:10.018428Z","shell.execute_reply":"2023-02-02T17:20:10.035318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img, feature, label = MyDataset(test_filtered, valid_aug, 'test')[0]\nplt.imshow(img.permute(1,2,0)[:,:,0])\nplt.show()\nimg.shape, feature, label","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:10.037870Z","iopub.execute_input":"2023-02-02T17:20:10.038330Z","iopub.status.idle":"2023-02-02T17:20:10.491503Z","shell.execute_reply.started":"2023-02-02T17:20:10.038295Z","shell.execute_reply":"2023-02-02T17:20:10.490587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Model(nn.Module):\n    def __init__(self):\n        super(Model, self).__init__()\n        self.backbone = timm.create_model(CFG['model'], pretrained=False, num_classes=500, in_chans=13)\n        self.mlp = nn.Sequential(\n            nn.Linear(18, 64),\n            nn.LayerNorm(64),\n            nn.ReLU(),\n            nn.Dropout(0.2),\n            # nn.Linear(64, 64),\n            # nn.LayerNorm(64),\n            # nn.ReLU(),\n            # nn.Dropout(0.2)\n        )\n        self.fc = nn.Linear(64+500*2, 1)\n\n    def forward(self, img, feature):\n        b, c, h, w = img.shape\n        img = img.reshape(b*2, c//2, h, w)\n        img = self.backbone(img).reshape(b, -1)\n        feature = self.mlp(feature)\n        y = self.fc(torch.cat([img, feature], dim=1))\n\n        return y, img","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:10.492571Z","iopub.execute_input":"2023-02-02T17:20:10.493749Z","iopub.status.idle":"2023-02-02T17:20:10.503021Z","shell.execute_reply.started":"2023-02-02T17:20:10.493708Z","shell.execute_reply":"2023-02-02T17:20:10.502018Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_set = MyDataset(test_filtered, valid_aug, 'test')\ntest_loader = DataLoader(test_set, batch_size=CFG['valid_bs'], shuffle=False, num_workers=CFG['num_workers'], pin_memory=True)\n\ntrain_set = MyDataset(train_filtered, valid_aug, 'test')\ntrain_loader = DataLoader(train_set, batch_size=CFG['valid_bs'], shuffle=False, num_workers=CFG['num_workers'], pin_memory=True)\n\nmodel = Model().to(device)\nmodel.load_state_dict(torch.load('/kaggle/input/nfl-exp1/resnet50_fold0.pt'))\n\nmodel.eval()\n    \ny_pred = []\nwith torch.no_grad():\n    tk = tqdm(test_loader, total=len(test_loader))\n    for step, batch in enumerate(tk):\n        if(step % 4 != 3):\n            img, feature, label = [x.to(device) for x in batch]\n            output1 = model(img, feature).squeeze(-1)\n            output2 = model(img.flip(-1), feature).squeeze(-1)\n            \n            y_pred.extend(0.2*(output1.sigmoid().cpu().numpy()) + 0.8*(output2.sigmoid().cpu().numpy()))\n        else:\n            img, feature, label = [x.to(device) for x in batch]\n            output = model(img.flip(-1), feature).squeeze(-1)\n            y_pred.extend(output.sigmoid().cpu().numpy())    \n\ny_pred = np.array(y_pred)","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:20:10.504585Z","iopub.execute_input":"2023-02-02T17:20:10.505393Z","iopub.status.idle":"2023-02-02T17:36:37.382095Z","shell.execute_reply.started":"2023-02-02T17:20:10.505357Z","shell.execute_reply":"2023-02-02T17:36:37.381060Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"th = 0.29\n\ntest_filtered['contact'] = (y_pred >= th).astype('int')\n\nsub = pd.read_csv('/kaggle/input/nfl-player-contact-detection/sample_submission.csv')\n\nsub = sub.drop(\"contact\", axis=1).merge(test_filtered[['contact_id', 'contact']], how='left', on='contact_id')\nsub['contact'] = sub['contact'].fillna(0).astype('int')\n\nsub[[\"contact_id\", \"contact\"]].to_csv(\"submission.csv\", index=False)\n\nsub.head()","metadata":{"execution":{"iopub.status.busy":"2023-02-02T17:36:37.386572Z","iopub.execute_input":"2023-02-02T17:36:37.389206Z","iopub.status.idle":"2023-02-02T17:36:37.607284Z","shell.execute_reply.started":"2023-02-02T17:36:37.389166Z","shell.execute_reply":"2023-02-02T17:36:37.606418Z"},"trusted":true},"execution_count":null,"outputs":[]}]}