{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":127283,"databundleVersionId":15634477}],"dockerImageVersionId":31287,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install timm opencv-python seaborn -q\n\nimport os\nimport cv2\nimport torch\nimport timm\nimport yaml\nimport json\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nimport torch.nn as nn\nimport torchvision.transforms as T\nfrom torch.utils.data import Dataset, DataLoader\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nplt.style.use(\"ggplot\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:33.287892Z","iopub.execute_input":"2026-02-20T07:31:33.288358Z","iopub.status.idle":"2026-02-20T07:31:51.011897Z","shell.execute_reply.started":"2026-02-20T07:31:33.288335Z","shell.execute_reply":"2026-02-20T07:31:51.011050Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_ROOT = \"/kaggle/input/accident\"\nSIM_ROOT = os.path.join(DATA_ROOT, \"sim_dataset\")\n\nVIDEOS_ROOT = os.path.join(SIM_ROOT, \"videos\")\nANNOT_ROOT = os.path.join(SIM_ROOT, \"video_annotations\")\nLABELS_PATH = os.path.join(SIM_ROOT, \"labels.csv\")\nTEST_METADATA = os.path.join(DATA_ROOT, \"test_metadata.csv\")\n\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(\"Device:\", DEVICE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:51.013976Z","iopub.execute_input":"2026-02-20T07:31:51.014505Z","iopub.status.idle":"2026-02-20T07:31:51.272519Z","shell.execute_reply.started":"2026-02-20T07:31:51.014476Z","shell.execute_reply":"2026-02-20T07:31:51.271732Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels_df = pd.read_csv(LABELS_PATH)\n\nplt.figure(figsize=(8,5))\nsns.countplot(data=labels_df, x=\"type\")\nplt.title(\"Synthetic Accident Type Distribution\")\nplt.xticks(rotation=30)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:51.273541Z","iopub.execute_input":"2026-02-20T07:31:51.273932Z","iopub.status.idle":"2026-02-20T07:31:51.533219Z","shell.execute_reply.started":"2026-02-20T07:31:51.273907Z","shell.execute_reply":"2026-02-20T07:31:51.532536Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_video(path, max_frames=64, resize=(224,224)):\n    cap = cv2.VideoCapture(path)\n    frames = []\n    \n    while True:\n        ret, frame = cap.read()\n        if not ret:\n            break\n        \n        frame = cv2.resize(frame, resize)\n        frames.append(frame)\n        \n        if len(frames) >= max_frames:\n            break\n    \n    cap.release()\n    return frames","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:51.534185Z","iopub.execute_input":"2026-02-20T07:31:51.534494Z","iopub.status.idle":"2026-02-20T07:31:51.539063Z","shell.execute_reply.started":"2026-02-20T07:31:51.534461Z","shell.execute_reply":"2026-02-20T07:31:51.538339Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def compute_flow(prev, next):\n    prev_gray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)\n    next_gray = cv2.cvtColor(next, cv2.COLOR_BGR2GRAY)\n\n    flow = cv2.calcOpticalFlowFarneback(\n        prev_gray, next_gray,\n        None,\n        0.5, 3, 15, 3, 5, 1.2, 0\n    )\n\n    return flow","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:51.540084Z","iopub.execute_input":"2026-02-20T07:31:51.540334Z","iopub.status.idle":"2026-02-20T07:31:51.551163Z","shell.execute_reply.started":"2026-02-20T07:31:51.540313Z","shell.execute_reply":"2026-02-20T07:31:51.550518Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def show_sample_video(video_path, max_frames=6):\n    frames = load_video(video_path, max_frames=max_frames)\n    \n    plt.figure(figsize=(15,4))\n    for i, frame in enumerate(frames):\n        plt.subplot(1, len(frames), i+1)\n        plt.imshow(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))\n        plt.axis(\"off\")\n        plt.title(f\"Frame {i}\")\n    plt.show()\n\nsample_video = os.path.join(SIM_ROOT, labels_df.iloc[0][\"rgb_path\"])\nshow_sample_video(sample_video)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:51.551930Z","iopub.execute_input":"2026-02-20T07:31:51.552218Z","iopub.status.idle":"2026-02-20T07:31:52.035915Z","shell.execute_reply.started":"2026-02-20T07:31:51.552197Z","shell.execute_reply":"2026-02-20T07:31:52.035161Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def visualize_flow(prev, next):\n    flow = compute_flow(prev, next)\n    magnitude = np.sqrt(flow[...,0]**2 + flow[...,1]**2)\n    \n    plt.figure(figsize=(10,4))\n    \n    plt.subplot(1,3,1)\n    plt.imshow(cv2.cvtColor(prev, cv2.COLOR_BGR2RGB))\n    plt.title(\"Prev Frame\")\n    plt.axis(\"off\")\n    \n    plt.subplot(1,3,2)\n    plt.imshow(cv2.cvtColor(next, cv2.COLOR_BGR2RGB))\n    plt.title(\"Next Frame\")\n    plt.axis(\"off\")\n    \n    plt.subplot(1,3,3)\n    plt.imshow(magnitude, cmap=\"jet\")\n    plt.title(\"Flow Magnitude\")\n    plt.axis(\"off\")\n    \n    plt.show()\n\nframes = load_video(sample_video, max_frames=3)\nvisualize_flow(frames[0], frames[1])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:52.038448Z","iopub.execute_input":"2026-02-20T07:31:52.038730Z","iopub.status.idle":"2026-02-20T07:31:52.331435Z","shell.execute_reply.started":"2026-02-20T07:31:52.038705Z","shell.execute_reply":"2026-02-20T07:31:52.330877Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SyntheticAccidentDataset(Dataset):\n    def __init__(self, df, max_frames=64):\n        self.df = df\n        self.max_frames = max_frames\n        \n        self.transform = T.Compose([\n            T.ToTensor(),\n            T.Normalize([0.5]*3, [0.5]*3)\n        ])\n        \n        self.type_map = {\n            \"head-on\": 0,\n            \"rear-end\": 1,\n            \"sideswipe\": 2,\n            \"single\": 3,\n            \"t-bone\": 4\n        }\n    \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        video_path = os.path.join(SIM_ROOT, row[\"rgb_path\"])\n        \n        frames = load_video(video_path, self.max_frames)\n        \n        imgs, flows = [], []\n        \n        for i in range(len(frames)):\n            imgs.append(self.transform(frames[i]))\n            \n            if i > 0:\n                flow = compute_flow(frames[i-1], frames[i])\n                flow = torch.from_numpy(flow).permute(2,0,1).float()\n            else:\n                flow = torch.zeros(2,224,224)\n            \n            flows.append(flow)\n        \n        imgs = torch.stack(imgs)\n        flows = torch.stack(flows)\n        \n        accident_frame = int(row[\"accident_frame\"])\n        labels = torch.zeros(len(frames))\n        labels[min(accident_frame, len(frames)-1):] = 1.0\n        \n        accident_type = self.type_map[row[\"type\"]]\n        \n        return imgs, flows, labels, accident_type","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:52.332277Z","iopub.execute_input":"2026-02-20T07:31:52.332556Z","iopub.status.idle":"2026-02-20T07:31:52.340210Z","shell.execute_reply.started":"2026-02-20T07:31:52.332525Z","shell.execute_reply":"2026-02-20T07:31:52.339602Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AccidentModel(nn.Module):\n    def __init__(self, d_model=512):\n        super().__init__()\n        \n        self.rgb_backbone = timm.create_model(\n            \"resnet18\",\n            pretrained=True,\n            num_classes=0\n        )\n        \n        self.flow_backbone = timm.create_model(\n            \"resnet18\",\n            pretrained=True,\n            in_chans=2,\n            num_classes=0\n        )\n        \n        self.proj = nn.Linear(1024, d_model)\n        \n        encoder_layer = nn.TransformerEncoderLayer(\n            d_model=d_model,\n            nhead=8,\n            batch_first=True\n        )\n        \n        self.transformer = nn.TransformerEncoder(\n            encoder_layer,\n            num_layers=4\n        )\n        \n        self.frame_classifier = nn.Linear(d_model, 1)\n        self.type_classifier = nn.Linear(d_model, 5)\n    \n    def forward(self, imgs, flows):\n        B, T, C, H, W = imgs.shape\n        \n        imgs = imgs.view(B*T, C, H, W)\n        flows = flows.view(B*T, 2, H, W)\n        \n        rgb_feat = self.rgb_backbone(imgs)\n        flow_feat = self.flow_backbone(flows)\n        \n        feat = torch.cat([rgb_feat, flow_feat], dim=1)\n        feat = self.proj(feat)\n        feat = feat.view(B, T, -1)\n        \n        temporal_feat = self.transformer(feat)\n        \n        frame_logits = self.frame_classifier(temporal_feat).squeeze(-1)\n        video_feat = temporal_feat.mean(dim=1)\n        type_logits = self.type_classifier(video_feat)\n        \n        return frame_logits, type_logits","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:52.341157Z","iopub.execute_input":"2026-02-20T07:31:52.341415Z","iopub.status.idle":"2026-02-20T07:31:52.358599Z","shell.execute_reply.started":"2026-02-20T07:31:52.341395Z","shell.execute_reply":"2026-02-20T07:31:52.357788Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset = SyntheticAccidentDataset(labels_df)\nloader = DataLoader(dataset, batch_size=2, shuffle=True)\n\nmodel = AccidentModel().to(DEVICE)\n\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n\nbce_loss = nn.BCEWithLogitsLoss()\nce_loss = nn.CrossEntropyLoss()\n\nloss_history = []","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:52.359746Z","iopub.execute_input":"2026-02-20T07:31:52.360088Z","iopub.status.idle":"2026-02-20T07:31:54.029491Z","shell.execute_reply.started":"2026-02-20T07:31:52.360059Z","shell.execute_reply":"2026-02-20T07:31:54.028576Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in range(5):\n    model.train()\n    total_loss = 0\n    \n    for imgs, flows, frame_labels, type_labels in tqdm(loader):\n        \n        imgs = imgs.to(DEVICE)\n        flows = flows.to(DEVICE)\n        frame_labels = frame_labels.to(DEVICE)\n        type_labels = type_labels.to(DEVICE)\n        \n        frame_logits, type_logits = model(imgs, flows)\n        \n        loss_frame = bce_loss(frame_logits, frame_labels)\n        loss_type = ce_loss(type_logits, type_labels)\n        \n        loss = loss_frame + 0.3 * loss_type\n        \n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        \n        total_loss += loss.item()\n    \n    epoch_loss = total_loss/len(loader)\n    loss_history.append(epoch_loss)\n    \n    print(f\"Epoch {epoch} Loss: {epoch_loss}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-20T07:31:54.030537Z","iopub.execute_input":"2026-02-20T07:31:54.030816Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(7,5))\nplt.plot(loss_history)\nplt.title(\"Training Loss Curve\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def visualize_prediction(video_path):\n    model.eval()\n    \n    frames = load_video(video_path, max_frames=64)\n    imgs, flows = [], []\n    \n    transform = dataset.transform\n    \n    for i in range(len(frames)):\n        imgs.append(transform(frames[i]))\n        \n        if i > 0:\n            flow = compute_flow(frames[i-1], frames[i])\n            flow = torch.from_numpy(flow).permute(2,0,1).float()\n        else:\n            flow = torch.zeros(2,224,224)\n        \n        flows.append(flow)\n    \n    imgs = torch.stack(imgs).unsqueeze(0).to(DEVICE)\n    flows = torch.stack(flows).unsqueeze(0).to(DEVICE)\n    \n    with torch.no_grad():\n        frame_logits, _ = model(imgs, flows)\n        probs = torch.sigmoid(frame_logits).squeeze().cpu().numpy()\n    \n    plt.figure(figsize=(12,4))\n    plt.plot(probs)\n    plt.title(\"Frame-level Accident Probability\")\n    plt.xlabel(\"Frame Index\")\n    plt.ylabel(\"Probability\")\n    plt.show()\n\nvisualize_prediction(sample_video)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df = pd.read_csv(TEST_METADATA)\n\ndef predict_video(path):\n    frames = load_video(path, max_frames=64)\n    \n    imgs, flows = [], []\n    transform = dataset.transform\n    \n    for i in range(len(frames)):\n        imgs.append(transform(frames[i]))\n        \n        if i > 0:\n            flow = compute_flow(frames[i-1], frames[i])\n            flow = torch.from_numpy(flow).permute(2,0,1).float()\n        else:\n            flow = torch.zeros(2,224,224)\n        \n        flows.append(flow)\n    \n    imgs = torch.stack(imgs).unsqueeze(0).to(DEVICE)\n    flows = torch.stack(flows).unsqueeze(0).to(DEVICE)\n    \n    with torch.no_grad():\n        frame_logits, _ = model(imgs, flows)\n        probs = torch.sigmoid(frame_logits)\n    \n    return float(probs.max().cpu())","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = []\n\nfor path in tqdm(test_df[\"path\"]):\n    full_path = os.path.join(DATA_ROOT, path)\n    score = predict_video(full_path)\n    predictions.append(score)\n\nsubmission = pd.DataFrame({\n    \"path\": test_df[\"path\"],\n    \"score\": predictions\n})\n\nsubmission.to_csv(\"submission.csv\", index=False)\nsubmission.head()","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}