{"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":[{"sourceId":5048,"databundleVersionId":868335,"sourceType":"competition"}],"dockerImageVersionId":31234,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# ===============================\n# Imports\n# ===============================\nimport os\nimport random\nfrom glob import glob\nfrom tqdm import tqdm\n\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\n\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms, models\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:30.858853Z","iopub.execute_input":"2026-01-02T05:43:30.859484Z","iopub.status.idle":"2026-01-02T05:43:41.663271Z","shell.execute_reply.started":"2026-01-02T05:43:30.859454Z","shell.execute_reply":"2026-01-02T05:43:41.662708Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===============================\n# Config\n# ===============================\nDATA_DIR = \"/kaggle/input/state-farm-distracted-driver-detection\"\nTRAIN_DIR = os.path.join(DATA_DIR, \"imgs/train\")\nTEST_DIR  = os.path.join(DATA_DIR, \"imgs/test\")\n\nIMG_SIZE = 224\nBATCH_SIZE = 32\nEPOCHS = 10\nLR = 2e-4\nNUM_CLASSES = 10\nSEED = 42\n\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(\"Using device:\", DEVICE)\n\n# ===============================\n# Reproducibility\n# ===============================\nrandom.seed(SEED)\nnp.random.seed(SEED)\ntorch.manual_seed(SEED)\nif DEVICE == \"cuda\":\n    torch.cuda.manual_seed_all(SEED)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:41.664641Z","iopub.execute_input":"2026-01-02T05:43:41.665008Z","iopub.status.idle":"2026-01-02T05:43:41.751893Z","shell.execute_reply.started":"2026-01-02T05:43:41.664982Z","shell.execute_reply":"2026-01-02T05:43:41.751214Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# List class folders\nclasses = sorted(os.listdir(TRAIN_DIR))\nprint(\"Classes:\", classes)\n\n# Count images per class\nfor cls in classes:\n    print(cls, \":\", len(os.listdir(os.path.join(TRAIN_DIR, cls))))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:41.752872Z","iopub.execute_input":"2026-01-02T05:43:41.753524Z","iopub.status.idle":"2026-01-02T05:43:41.995364Z","shell.execute_reply.started":"2026-01-02T05:43:41.753488Z","shell.execute_reply":"2026-01-02T05:43:41.994580Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"filepaths = []\nlabels = []\n\nfor idx, cls in enumerate(classes):\n    imgs = glob(os.path.join(TRAIN_DIR, cls, \"*.jpg\"))\n    filepaths.extend(imgs)\n    labels.extend([idx] * len(imgs))\n\ndf = pd.DataFrame({\n    \"filepath\": filepaths,\n    \"label\": labels\n})\n\nprint(\"Total images:\", len(df))\ndf.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:41.996354Z","iopub.execute_input":"2026-01-02T05:43:41.996618Z","iopub.status.idle":"2026-01-02T05:43:42.065555Z","shell.execute_reply.started":"2026-01-02T05:43:41.996598Z","shell.execute_reply":"2026-01-02T05:43:42.064896Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df, val_df = train_test_split(\n    df,\n    test_size=0.2,\n    stratify=df[\"label\"],\n    random_state=SEED\n)\n\nprint(\"Train:\", len(train_df), \"Validation:\", len(val_df))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:42.067338Z","iopub.execute_input":"2026-01-02T05:43:42.067629Z","iopub.status.idle":"2026-01-02T05:43:42.088927Z","shell.execute_reply.started":"2026-01-02T05:43:42.067608Z","shell.execute_reply":"2026-01-02T05:43:42.088343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class DriverDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        img = Image.open(self.df.loc[idx, \"filepath\"]).convert(\"RGB\")\n        label = self.df.loc[idx, \"label\"]\n\n        if self.transform:\n            img = self.transform(img)\n\n        return img, label\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:42.089685Z","iopub.execute_input":"2026-01-02T05:43:42.089945Z","iopub.status.idle":"2026-01-02T05:43:42.094860Z","shell.execute_reply.started":"2026-01-02T05:43:42.089907Z","shell.execute_reply":"2026-01-02T05:43:42.094132Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_transform = transforms.Compose([\n    transforms.RandomResizedCrop(IMG_SIZE, scale=(0.7, 1.0)),\n    transforms.RandomHorizontalFlip(),\n    transforms.ColorJitter(0.2, 0.2, 0.2),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406],\n                         [0.229, 0.224, 0.225]),\n])\n\nval_transform = transforms.Compose([\n    transforms.Resize(256),\n    transforms.CenterCrop(IMG_SIZE),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406],\n                         [0.229, 0.224, 0.225]),\n])\n\ntrain_ds = DriverDataset(train_df, train_transform)\nval_ds   = DriverDataset(val_df, val_transform)\n\ntrain_loader = DataLoader(train_ds, batch_size=BATCH_SIZE,\n                          shuffle=True, num_workers=2)\nval_loader   = DataLoader(val_ds, batch_size=BATCH_SIZE,\n                          shuffle=False, num_workers=2)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:42.095826Z","iopub.execute_input":"2026-01-02T05:43:42.096344Z","iopub.status.idle":"2026-01-02T05:43:42.111982Z","shell.execute_reply.started":"2026-01-02T05:43:42.096322Z","shell.execute_reply":"2026-01-02T05:43:42.111325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = models.resnet50(pretrained=True)\n\n# Replace final layer\nmodel.fc = nn.Linear(model.fc.in_features, NUM_CLASSES)\nmodel = model.to(DEVICE)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.AdamW(model.parameters(), lr=LR)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=EPOCHS)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:42.112661Z","iopub.execute_input":"2026-01-02T05:43:42.112936Z","iopub.status.idle":"2026-01-02T05:43:43.674590Z","shell.execute_reply.started":"2026-01-02T05:43:42.112907Z","shell.execute_reply":"2026-01-02T05:43:43.673991Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_epoch(model, loader):\n    model.train()\n    losses, preds, targets = [], [], []\n\n    for imgs, labels in tqdm(loader):\n        imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n\n        optimizer.zero_grad()\n        outputs = model(imgs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        losses.append(loss.item())\n        preds.extend(outputs.argmax(1).cpu().numpy())\n        targets.extend(labels.cpu().numpy())\n\n    return np.mean(losses), accuracy_score(targets, preds)\n\n\ndef val_epoch(model, loader):\n    model.eval()\n    losses, preds, targets = [], [], []\n\n    with torch.no_grad():\n        for imgs, labels in tqdm(loader):\n            imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n            outputs = model(imgs)\n            loss = criterion(outputs, labels)\n\n            losses.append(loss.item())\n            preds.extend(outputs.argmax(1).cpu().numpy())\n            targets.extend(labels.cpu().numpy())\n\n    return np.mean(losses), accuracy_score(targets, preds)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:43.675651Z","iopub.execute_input":"2026-01-02T05:43:43.675975Z","iopub.status.idle":"2026-01-02T05:43:43.683696Z","shell.execute_reply.started":"2026-01-02T05:43:43.675944Z","shell.execute_reply":"2026-01-02T05:43:43.683020Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"best_acc = 0\n\nfor epoch in range(EPOCHS):\n    print(f\"\\nEpoch {epoch+1}/{EPOCHS}\")\n\n    train_loss, train_acc = train_epoch(model, train_loader)\n    val_loss, val_acc = val_epoch(model, val_loader)\n\n    scheduler.step()\n\n    print(f\"Train Loss: {train_loss:.4f} | Acc: {train_acc:.4f}\")\n    print(f\"Val   Loss: {val_loss:.4f} | Acc: {val_acc:.4f}\")\n\n    if val_acc > best_acc:\n        best_acc = val_acc\n        torch.save(model.state_dict(), \"best_model.pth\")\n        print(\"✅ Best model saved\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T05:43:43.684508Z","iopub.execute_input":"2026-01-02T05:43:43.684716Z","iopub.status.idle":"2026-01-02T06:22:14.999474Z","shell.execute_reply.started":"2026-01-02T05:43:43.684695Z","shell.execute_reply":"2026-01-02T06:22:14.998521Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn.functional as F\n\nmodel.load_state_dict(torch.load(\"best_model.pth\"))\nmodel.eval()\n\ntest_images = sorted(glob(os.path.join(TEST_DIR, \"*.jpg\")))\n\nrows = []\n\nwith torch.no_grad():\n    for img_path in tqdm(test_images):\n        img = Image.open(img_path).convert(\"RGB\")\n        img = val_transform(img).unsqueeze(0).to(DEVICE)\n\n        outputs = model(img)\n        probs = F.softmax(outputs, dim=1).cpu().numpy()[0]\n\n        row = {\n            \"img\": os.path.basename(img_path)\n        }\n\n        for i in range(10):\n            row[f\"c{i}\"] = probs[i]\n\n        rows.append(row)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T06:22:15.001047Z","iopub.execute_input":"2026-01-02T06:22:15.001379Z","iopub.status.idle":"2026-01-02T06:50:09.774816Z","shell.execute_reply.started":"2026-01-02T06:22:15.001351Z","shell.execute_reply":"2026-01-02T06:50:09.774172Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create submission dataframe\nsubmission = pd.DataFrame(rows)\n\n# Ensure correct column order\nsubmission = submission[\n    [\"img\", \"c0\", \"c1\", \"c2\", \"c3\", \"c4\", \"c5\", \"c6\", \"c7\", \"c8\", \"c9\"]\n]\n\nsubmission.to_csv(\"submission.csv\", index=False)\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-02T06:50:09.775829Z","iopub.execute_input":"2026-01-02T06:50:09.776086Z","iopub.status.idle":"2026-01-02T06:50:10.916010Z","shell.execute_reply.started":"2026-01-02T06:50:09.776063Z","shell.execute_reply":"2026-01-02T06:50:10.915470Z"}},"outputs":[],"execution_count":null}]}