{"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":"none","dataSources":[{"sourceType":"competition","sourceId":92399,"databundleVersionId":11038207},{"sourceType":"modelInstanceVersion","sourceId":365098,"databundleVersionId":12082787,"modelInstanceId":300194,"modelId":320755},{"sourceType":"modelInstanceVersion","sourceId":367071,"databundleVersionId":12098164,"modelInstanceId":300194,"modelId":320755},{"sourceType":"modelInstanceVersion","sourceId":360939,"databundleVersionId":12051184,"modelInstanceId":300194,"modelId":320755},{"sourceType":"modelInstanceVersion","sourceId":365484,"databundleVersionId":12085825,"modelInstanceId":300194,"modelId":320755},{"sourceType":"modelInstanceVersion","sourceId":361353,"databundleVersionId":12053669,"modelInstanceId":300194,"modelId":320755},{"sourceType":"modelInstanceVersion","sourceId":364227,"databundleVersionId":12075625,"modelInstanceId":300194,"modelId":320755},{"sourceType":"modelInstanceVersion","sourceId":366343,"databundleVersionId":12092667,"modelInstanceId":300194,"modelId":320755}],"dockerImageVersionId":30918,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Imports","metadata":{}},{"cell_type":"code","source":"import os\nimport json\nimport cv2\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom torch.utils.data import Subset\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nimport torchvision.transforms.functional as TF\nimport torch.nn.functional as F\nfrom torch.utils.data import random_split\nimport time","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:10:55.294498Z","iopub.execute_input":"2025-05-01T05:10:55.294884Z","iopub.status.idle":"2025-05-01T05:11:03.673669Z","shell.execute_reply.started":"2025-05-01T05:10:55.294844Z","shell.execute_reply":"2025-05-01T05:11:03.672679Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# set the device to GPU if available, otherwise use CPU\ndevice = (\n    torch.device(f\"cuda:{torch.cuda.current_device()}\")\n    if torch.cuda.is_available()\n    else \"cpu\"\n)\ntorch.set_default_device(device)\nprint(f\"Using device: {device}\")\nif device != \"cpu\":\n    print(f\"Device name: {torch.cuda.get_device_name()}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:11:03.674983Z","iopub.execute_input":"2025-05-01T05:11:03.675446Z","iopub.status.idle":"2025-05-01T05:11:03.684666Z","shell.execute_reply.started":"2025-05-01T05:11:03.675416Z","shell.execute_reply":"2025-05-01T05:11:03.683324Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Create Dataset","metadata":{}},{"cell_type":"code","source":"class CrashDataset(Dataset):\n  def __init__(self, csv_file, video_dir, transform=False):\n        self.data = pd.read_csv(csv_file)\n        self.video_dir = video_dir\n        self.transform = transform\n        self.jitter_params = (0.2, 0.2, 0.2, 0.1)\n  def __len__(self):\n    return len(self.data)\n\n  def __getitem__(self, idx):\n    row = self.data.iloc[idx]\n    video_id = int(row['id'])\n    target = int(row['target'])\n    video_path = os.path.join(self.video_dir, f\"{video_id:05d}.mp4\")\n\n    if target == 1:\n      event_time = row['time_of_event']\n      event_time = float(event_time)\n      start_frame = int(max(0, event_time*30 - 150))\n    else:\n      start_frame = 0\n\n    video_tensor = self.extract_frames(video_path, start_frame)\n    return video_tensor, torch.tensor(target, dtype = torch.float32)\n\n  def extract_frames(self, video_path, start_frame):\n    cap = cv2.VideoCapture(video_path)\n\n    frames = []\n    frame_interval = 3\n    cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)\n\n    brightness, contrast, saturation, hue = self.jitter_params\n      \n    b = torch.empty(1).uniform_(1 - brightness, 1 + brightness).item()\n    c = torch.empty(1).uniform_(1 - contrast, 1 + contrast).item()\n    s = torch.empty(1).uniform_(1 - saturation, 1 + saturation).item()\n    h = torch.empty(1).uniform_(-hue, hue).item()\n\n    # Flip decision\n    do_flip = torch.rand(1) < 0.5\n\n\n    angle =  -10 + 20 * torch.rand(1).item()\n\n    i, j, h_crop, w_crop = transforms.RandomCrop.get_params(\n        torch.zeros(3, 144, 256), output_size=(129, 230)\n    )\n      \n    for idx in range(151):\n      ret, frame = cap.read()\n      if not ret:\n        break\n      if (idx + 1) % frame_interval == 0:\n        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n        frame = cv2.resize(frame, (256, 144))\n        frame_tensor = TF.to_tensor(frame)\n        if self.transform:\n            # Crop\n            frame_tensor = TF.crop(frame_tensor, i, j, h_crop, w_crop)\n            # Rotate\n            frame_tensor = TF.rotate(frame_tensor, angle)\n            # Resize\n            frame_tensor = TF.resize(frame_tensor, (112, 112))\n            # Flip\n            if do_flip:\n                frame_tensor = TF.hflip(frame_tensor)\n            # Color jitter\n            frame_tensor = TF.adjust_brightness(frame_tensor, b)\n            frame_tensor = TF.adjust_contrast(frame_tensor, c)\n            frame_tensor = TF.adjust_saturation(frame_tensor, s)\n            frame_tensor = TF.adjust_hue(frame_tensor, h)\n        else:\n            frame_tensor = TF.resize(frame_tensor, (112, 112))\n        frames.append(frame_tensor)\n    cap.release()\n\n    return torch.stack(frames);","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:11:03.686387Z","iopub.execute_input":"2025-05-01T05:11:03.686756Z","iopub.status.idle":"2025-05-01T05:11:03.711030Z","shell.execute_reply.started":"2025-05-01T05:11:03.686712Z","shell.execute_reply":"2025-05-01T05:11:03.709451Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_csv = '/kaggle/input/nexar-collision-prediction/train.csv'\nvideo_dir = '/kaggle/input/nexar-collision-prediction/train'\n\ndataset = CrashDataset(train_csv, video_dir)\n\ntrain_size = int(0.8 * len(dataset))\nval_size = len(dataset) - train_size\n\nsplit_file = '/kaggle/input/augcrash/pytorch/default/1/train_val_split.json'\n\ntry:\n    # Try to load the existing split indices\n    with open(split_file, 'r') as f:\n        split_data = json.load(f)\n    train_indices = split_data['train']\n    val_indices = split_data['val']\n    print(\"Split Loaded\")\nexcept FileNotFoundError:\n    # Perform the split and save indices if the split file doesn't exist\n    train_indices, val_indices = random_split(range(len(dataset)), [train_size, val_size])\n\n    # Save the split indices to a file\n    with open('train_val_split.json', 'w') as f:\n        json.dump({'train': train_indices.indices, 'val': val_indices.indices}, f)\n    print(\"Split Created\")\n\n\ntrain_dataset = Subset(CrashDataset(train_csv, video_dir, transform=True), train_indices)\nval_dataset = Subset(CrashDataset(train_csv, video_dir, transform=False), val_indices)\n\n\nbatch_size = 16\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:11:03.712829Z","iopub.execute_input":"2025-05-01T05:11:03.713238Z","iopub.status.idle":"2025-05-01T05:11:03.761294Z","shell.execute_reply.started":"2025-05-01T05:11:03.713204Z","shell.execute_reply":"2025-05-01T05:11:03.759848Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_tensor = train_dataset[3][0]\nprint(sample_tensor.shape)\n#print(len(train_dataset))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:11:03.762417Z","iopub.execute_input":"2025-05-01T05:11:03.762726Z","iopub.status.idle":"2025-05-01T05:11:05.063559Z","shell.execute_reply.started":"2025-05-01T05:11:03.762698Z","shell.execute_reply":"2025-05-01T05:11:05.062021Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def display_video(tensor):\n    # Loop through all frames\n    for i in range(tensor.size(0)):  # 50 frames in the video\n        frame = tensor[i]  # Get the i-th frame\n        frame = frame.permute(1, 2, 0).numpy()  # Convert to a NumPy array\n        frame = np.clip(frame, 0, 1)  # Ensure pixel values are in [0, 1]\n        \n        plt.imshow(frame)  # Display the frame\n        plt.title(f\"Frame {i+1}\")\n        plt.axis('off')  # Turn off axis\n        plt.pause(0.1)  # Pause to simulate video playback, adjust the time for speed\n        plt.clf()  # Clear the figure to avoid overlapping frames\n\n# Example usage:\n# Assuming `video_tensor` is a tensor of shape (50, 3, 112, 112)\ndisplay_video(val_dataset[2][0])","metadata":{"trusted":true,"_kg_hide-input":false,"execution":{"iopub.status.busy":"2025-05-01T05:11:05.064900Z","iopub.execute_input":"2025-05-01T05:11:05.065325Z","iopub.status.idle":"2025-05-01T05:11:17.123516Z","shell.execute_reply.started":"2025-05-01T05:11:05.065293Z","shell.execute_reply":"2025-05-01T05:11:17.122406Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Create Model","metadata":{}},{"cell_type":"code","source":"class CrashModel(nn.Module):\n    def __init__(self):\n        super(CrashModel, self).__init__()\n        self.conv1 = nn.Conv3d(3, 32, kernel_size=(3,5,5), stride=1, padding=(1,2,2))\n        self.gn1 = nn.GroupNorm(8, 32)\n        # [B, 32, 25, 56, 56]\n\n        self.conv2 = nn.Conv3d(32, 64, kernel_size=3, stride=1, padding=1)\n        self.gn2 = nn.GroupNorm(8, 64)\n        # [B, 64, 12, 28, 28]\n\n        self.conv3 = nn.Conv3d(64, 128, kernel_size=(3,3,3), stride=1, padding=1)\n        self.gn3 = nn.GroupNorm(8, 128)\n        # [B, 128, 6, 14, 14]\n\n        self.conv4 = nn.Conv3d(128, 256, kernel_size=3, stride=1, padding=1)\n        self.gn4 = nn.GroupNorm(8, 256)\n\n        \n        self.pool = nn.MaxPool3d(kernel_size=(2,2,2), stride=(2,2,2))\n\n        self.dropout3d = nn.Dropout3d(0.05)\n        \n        self.global_pool = nn.AdaptiveAvgPool3d((1, 1, 1))  # [B, 256, 1, 1, 1]\n        self.fc = nn.Linear(256, 1)  # [B, 1]\n\n    def forward(self, x):\n        x = F.relu(self.gn1(self.conv1(x)))\n        x = self.pool(x)\n\n        x = F.relu(self.gn2(self.conv2(x)))\n        x = self.pool(x)\n\n        x = F.relu(self.gn3(self.conv3(x)))\n        x = self.pool(x)\n\n        x = F.relu(self.gn4(self.conv4(x)))\n        x = self.dropout3d(x)\n        x = self.global_pool(x)\n        \n        x = x.view(x.size(0), -1)  # [B, 256]\n        x = self.fc(x)  # [B, 1]\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:11:17.124692Z","iopub.execute_input":"2025-05-01T05:11:17.125131Z","iopub.status.idle":"2025-05-01T05:11:17.135957Z","shell.execute_reply.started":"2025-05-01T05:11:17.125062Z","shell.execute_reply":"2025-05-01T05:11:17.134701Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = CrashModel()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:11:17.138573Z","iopub.execute_input":"2025-05-01T05:11:17.138924Z","iopub.status.idle":"2025-05-01T05:11:17.171477Z","shell.execute_reply.started":"2025-05-01T05:11:17.138884Z","shell.execute_reply":"2025-05-01T05:11:17.170208Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_the_model():\n    learning_rate = 0.0001\n    num_epochs = 10\n    criterion = nn.BCEWithLogitsLoss()\n    #optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)\n    optimizer = torch.optim.AdamW(model.parameters(), lr=learning_rate, weight_decay=1e-2)\n\n    print(f\"Number of samples: {len(train_dataset)}\")\n    print(f\"Batch Size: {batch_size}\")\n    print(f\"Shape of each sample: [50, 3, 112, 112]\")\n    print(f\"Number of epochs: {num_epochs}\")\n    print(f\"Learning rate: {learning_rate}\")\n    print(f\"Loss function: Binary Cross Entropy\")\n    print(f\"Optimizer: Adam\")\n    print(f\"Number of parameters: {sum(p.numel() for p in model.parameters())}\")\n    \n    start_time = time.time()\n    for epoch in range(num_epochs):\n        model.train()\n        running_loss = 0.0\n        batch = 0\n        train_correct = 0\n        train_total = 0\n        for inputs, targets in train_loader:\n            print(f\"Batch {batch}, Running Loss: {running_loss:.4f}, Elapsed time: {time.time() - start_time:.2f} seconds\")\n            batch += 1\n            # [B, 50, C, H, W]\n            # [B, C, T, H, W]\n            inputs = inputs.permute(0, 2, 1, 3, 4).to(device)  # [B, 3, 50, H, W]\n            targets = targets.to(device).unsqueeze(1).float()    # [B, 1]\n    \n            optimizer.zero_grad()\n            outputs = model(inputs)  # Forward pass, outputs shape: [B, 1]\n            loss = criterion(outputs, targets)\n            loss.backward()\n            optimizer.step()\n\n            running_loss += loss.item()\n\n            preds = (torch.sigmoid(outputs) >= 0.5).float()  # [B, 1]\n            train_correct += (preds == targets).sum().item()\n            train_total += targets.size(0)\n            \n        avg_loss = running_loss / len(train_loader)\n        train_accuracy = train_correct / train_total\n\n        model.eval()\n        val_loss = 0.0\n        val_correct = 0\n        val_total = 0\n        with torch.no_grad():\n            for inputs, targets in val_loader:\n                # Rearrange inputs similarly as in training: [B, 50, H, W, C] -> [B, 3, 50, H, W]\n                inputs = inputs.permute(0, 2, 1, 3, 4).to(device)\n                targets = targets.to(device).unsqueeze(1).float()\n                outputs = model(inputs)\n                loss = criterion(outputs, targets)\n                val_loss += loss.item()\n\n                preds = (torch.sigmoid(outputs) >= 0.5).float()\n                val_correct += (preds == targets).sum().item()\n                val_total += targets.size(0)\n        \n        avg_val_loss = val_loss / len(val_loader)\n        val_accuracy = val_correct / val_total\n\n        print(f\"Epoch {epoch+1}/{num_epochs}, Train Loss: {avg_loss:.4f}, Train Accuracy: {train_accuracy:.4f}, Validation Loss: {avg_val_loss:.4f}, Validation Accuracy: {val_accuracy}, Elapsed time: {time.time() - start_time:.2f} seconds\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:11:17.173169Z","iopub.execute_input":"2025-05-01T05:11:17.173496Z","iopub.status.idle":"2025-05-01T05:11:17.187222Z","shell.execute_reply.started":"2025-05-01T05:11:17.173470Z","shell.execute_reply":"2025-05-01T05:11:17.185509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_path = \"/kaggle/input/augcrash/pytorch/default/11/augModel8.pth\"\nmodel.load_state_dict(torch.load(model_path, map_location=device))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:11:17.188404Z","iopub.execute_input":"2025-05-01T05:11:17.188777Z","iopub.status.idle":"2025-05-01T05:11:17.283872Z","shell.execute_reply.started":"2025-05-01T05:11:17.188746Z","shell.execute_reply":"2025-05-01T05:11:17.282825Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_the_model()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T05:11:17.284940Z","iopub.execute_input":"2025-05-01T05:11:17.285269Z","iopub.status.idle":"2025-05-01T13:56:42.398227Z","shell.execute_reply.started":"2025-05-01T05:11:17.285240Z","shell.execute_reply":"2025-05-01T13:56:42.387154Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), \"augModel9.pth\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T13:56:53.890833Z","iopub.execute_input":"2025-05-01T13:56:53.891427Z","iopub.status.idle":"2025-05-01T13:56:53.958524Z","shell.execute_reply.started":"2025-05-01T13:56:53.891356Z","shell.execute_reply":"2025-05-01T13:56:53.956429Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Submission Stuff","metadata":{}},{"cell_type":"code","source":"class TestDataset(Dataset):\n  def __init__(self, csv_file, video_dir):\n        self.data = pd.read_csv(csv_file)\n        self.video_dir = video_dir\n        \n  def __len__(self):\n    return len(self.data)\n\n  def __getitem__(self, idx):\n    row = self.data.iloc[idx]\n    video_id = int(row['id'])\n    vid = f\"{video_id:05d}.mp4\"\n    video_path = os.path.join(self.video_dir, vid)\n\n    \n    video_tensor = self.extract_frames(video_path)\n    return vid, video_tensor\n\n  def extract_frames(self, video_path):\n    cap = cv2.VideoCapture(video_path)\n    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n\n    frames = []\n    frame_interval = 3\n    cap.set(cv2.CAP_PROP_POS_FRAMES, total_frames - 150)\n      \n    for idx in range(150):\n      ret, frame = cap.read()\n      if not ret:\n        break\n      if (idx + 1) % frame_interval == 0:\n        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n        frame = cv2.resize(frame, (112, 112))\n        frame_tensor = TF.to_tensor(frame)\n        frames.append(frame_tensor)\n    cap.release()\n    return torch.stack(frames);","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T13:56:42.405869Z","iopub.status.idle":"2025-05-01T13:56:42.406496Z","shell.execute_reply":"2025-05-01T13:56:42.406258Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\ntest_csv = '/kaggle/input/nexar-collision-prediction/test.csv'\ntest_video_dir = '/kaggle/input/nexar-collision-prediction/test'\ntest_set = TestDataset(test_csv, test_video_dir)\n\nprint(len(test_set))\n# Assuming `video_tensor` is a tensor of shape (50, 3, 112, 112)\ndisplay_video(test_set[334][1])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T13:56:42.408136Z","iopub.status.idle":"2025-05-01T13:56:42.408747Z","shell.execute_reply":"2025-05-01T13:56:42.408543Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.eval()\npredictions = []\nnum = 0\nwith torch.no_grad():\n    for vid_id, video in test_set:\n        video = video.unsqueeze(0).permute(0, 2, 1, 3, 4).to(next(model.parameters()).device)  # Add batch dim, move to model's device\n        output = model(video)\n        prob = torch.sigmoid(output).item()\n        predictions.append((vid_id, prob))\n        num += 1\n        print(f\"Processed {num} videos\")\n\n# Save to CSV\ndf = pd.DataFrame(predictions, columns=['id', 'prediction'])\ndf.to_csv('predictions.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T13:56:42.410629Z","iopub.status.idle":"2025-05-01T13:56:42.411269Z","shell.execute_reply":"2025-05-01T13:56:42.411004Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.DataFrame(predictions, columns=['id', 'score'])\ndf.to_csv('submission.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T13:56:42.413178Z","iopub.status.idle":"2025-05-01T13:56:42.413702Z","shell.execute_reply":"2025-05-01T13:56:42.413487Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['id'] = df['id'].str.replace('.mp4', '', regex=False)\ndf.to_csv('submission1.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-01T13:56:42.415151Z","iopub.status.idle":"2025-05-01T13:56:42.415731Z","shell.execute_reply":"2025-05-01T13:56:42.415509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_the_model():\n  learning_rate = 0.001\n  num_epochs = 10\n  criterion = nn.CrossEntropyLoss()\n  optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)\n\n  for epoch in range(num_epochs):\n    model.train()\n    running_train_loss = 0.0\n    for inputs, targets in train_loader:\n      optimizer.zero_grad()\n      outputs = model(inputs)\n      loss = criterion(outputs, targets)\n      loss.backward()\n      optimizer.step()\n      running_train_loss += loss.item()\n    avg_train_loss = running_train_loss / len(train_loader)\n\n    running_test_loss = 0.0\n    with torch.no_grad():\n      for inputs, targets in test_loader:\n        outputs = model(inputs)\n        loss = criterion(outputs, targets)\n        running_test_loss += loss.item()\n    avg_test_loss = running_test_loss / len(test_loader)\n    print(f\"Epoch {epoch + 1}/{num_epochs}, Train Loss: {avg_train_loss:.4f}, Test Loss: {avg_test_loss:.4f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}