{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"d078be3a","cell_type":"markdown","source":"## 1) Setup and environment-aware data paths","metadata":{}},{"id":"92e71cce","cell_type":"code","source":"from __future__ import annotations\n\nimport json\nimport subprocess\nimport sys\nfrom pathlib import Path\n\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import StratifiedGroupKFold\n\nROOT = Path.cwd().resolve()\nif not (ROOT / 'pyproject.toml').exists():\n    ROOT = ROOT.parent.resolve()\n\nLOCAL_DATA = ROOT / 'data' / 'raw'\nKAGGLE_DATA = Path('/kaggle/input/state-farm-distracted-driver-detection')\nDATA_ROOT = KAGGLE_DATA if KAGGLE_DATA.exists() else LOCAL_DATA\nTRAIN_CSV = DATA_ROOT / 'driver_imgs_list.csv'\nDATA_AVAILABLE = TRAIN_CSV.exists()\n\nprint(f'Project root: {ROOT}')\nprint(f'Data root: {DATA_ROOT}')\nprint(f'Data available: {DATA_AVAILABLE}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-12T13:02:53.289093Z","iopub.execute_input":"2026-06-12T13:02:53.289676Z","iopub.status.idle":"2026-06-12T13:02:54.419897Z","shell.execute_reply.started":"2026-06-12T13:02:53.289643Z","shell.execute_reply":"2026-06-12T13:02:54.419035Z"}},"outputs":[],"execution_count":null},{"id":"8d2e00f6","cell_type":"markdown","source":"## 2) Load metadata and sanity checks","metadata":{}},{"id":"4673098d","cell_type":"code","source":"if DATA_AVAILABLE:\n    meta = pd.read_csv(TRAIN_CSV)\n    meta['label'] = meta['classname'].str.replace('c', '', regex=False).astype(int)\nelse:\n    meta = pd.DataFrame(columns=['subject', 'classname', 'img', 'label'])\n    print('Competition files are not mounted in this environment; showing fallback-safe flow.')\nmeta.shape","metadata":{"execution":{"iopub.status.busy":"2026-06-12T13:03:11.338130Z","iopub.execute_input":"2026-06-12T13:03:11.338696Z","iopub.status.idle":"2026-06-12T13:03:11.347000Z","shell.execute_reply.started":"2026-06-12T13:03:11.338665Z","shell.execute_reply":"2026-06-12T13:03:11.346306Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"88e31869","cell_type":"code","source":"if DATA_AVAILABLE:\n    summary = {\n        'n_train_rows': int(len(meta)),\n        'n_unique_subjects': int(meta['subject'].nunique()),\n        'n_classes': int(meta['classname'].nunique()),\n        'n_test_images': int(len(list((DATA_ROOT / 'imgs' / 'test').glob('*.jpg')))),\n    }\nelse:\n    summary = {'n_train_rows': 0, 'n_unique_subjects': 0, 'n_classes': 0, 'n_test_images': 0}\nsummary","metadata":{"execution":{"iopub.status.busy":"2026-06-12T13:03:13.093247Z","iopub.execute_input":"2026-06-12T13:03:13.093911Z","iopub.status.idle":"2026-06-12T13:03:13.099836Z","shell.execute_reply.started":"2026-06-12T13:03:13.093881Z","shell.execute_reply":"2026-06-12T13:03:13.099154Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"4c61faf2","cell_type":"code","source":"if DATA_AVAILABLE:\n    class_counts = meta['classname'].value_counts().sort_index()\n    ax = class_counts.plot(kind='bar', figsize=(8, 3), title='Class counts in train set')\n    ax.set_xlabel('Class')\n    ax.set_ylabel('Count')\n    plt.tight_layout()\n    display(class_counts)\nelse:\n    print('Skipped class distribution plot (data unavailable).')","metadata":{"execution":{"iopub.status.busy":"2026-06-12T13:03:14.878273Z","iopub.execute_input":"2026-06-12T13:03:14.878546Z","iopub.status.idle":"2026-06-12T13:03:14.883428Z","shell.execute_reply.started":"2026-06-12T13:03:14.878522Z","shell.execute_reply":"2026-06-12T13:03:14.882658Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"2fff66a3","cell_type":"markdown","source":"## 3) Leakage-safe split strategy (grouped by driver)","metadata":{}},{"id":"bea0f167","cell_type":"code","source":"if DATA_AVAILABLE:\n    sgkf = StratifiedGroupKFold(n_splits=5, shuffle=True, random_state=42)\n    folds = []\n    for fold, (_, val_idx) in enumerate(sgkf.split(meta, y=meta['label'], groups=meta['subject'])):\n        fold_df = meta.iloc[val_idx]\n        folds.append({\n            'fold': fold,\n            'val_samples': int(len(val_idx)),\n            'val_subjects': int(fold_df['subject'].nunique()),\n            'val_classes': int(fold_df['classname'].nunique()),\n        })\n    pd.DataFrame(folds)\nelse:\n    print('Skipped fold table (data unavailable).')","metadata":{"execution":{"iopub.status.busy":"2026-06-12T13:03:21.498342Z","iopub.execute_input":"2026-06-12T13:03:21.498624Z","iopub.status.idle":"2026-06-12T13:03:21.504574Z","shell.execute_reply.started":"2026-06-12T13:03:21.498586Z","shell.execute_reply":"2026-06-12T13:03:21.503758Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"aa3a11d7","cell_type":"markdown","source":"## 4) Real local training artifacts","metadata":{}},{"id":"c2ad3b83","cell_type":"code","source":"summary_path = ROOT / 'artifacts' / 'metrics' / 'summary.json'\nif summary_path.exists():\n    run_summary = json.loads(summary_path.read_text())\nelse:\n    run_summary = {'note': 'summary.json not found in this runtime'}\nrun_summary","metadata":{"execution":{"iopub.status.busy":"2026-06-12T13:03:22.083033Z","iopub.execute_input":"2026-06-12T13:03:22.083317Z","iopub.status.idle":"2026-06-12T13:03:22.089124Z","shell.execute_reply.started":"2026-06-12T13:03:22.083295Z","shell.execute_reply":"2026-06-12T13:03:22.088439Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"1c6a89ad","cell_type":"code","source":"history_path = ROOT / 'artifacts' / 'metrics' / 'history.csv'\nif history_path.exists():\n    history = pd.read_csv(history_path)\n    display(history)\n    fig, axes = plt.subplots(1, 2, figsize=(10, 3))\n    history.plot(x='epoch', y='train_loss', marker='o', ax=axes[0], title='Train Loss')\n    history.plot(x='epoch', y='val_log_loss', marker='o', ax=axes[1], title='Validation Log-Loss')\n    for ax in axes:\n        ax.grid(alpha=0.3)\n    plt.tight_layout()\nelse:\n    print('history.csv not found in this runtime.')","metadata":{"execution":{"iopub.status.busy":"2026-06-12T13:03:22.443454Z","iopub.execute_input":"2026-06-12T13:03:22.444127Z","iopub.status.idle":"2026-06-12T13:03:22.449584Z","shell.execute_reply.started":"2026-06-12T13:03:22.444096Z","shell.execute_reply":"2026-06-12T13:03:22.448822Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"cf19000d","cell_type":"markdown","source":"## 5) Submission file validation","metadata":{}},{"id":"1c23e36b","cell_type":"code","source":"sub_path = ROOT / 'submissions' / 'submission_fold0.csv'\nif sub_path.exists():\n    submission = pd.read_csv(sub_path)\n    display(submission.head())\n    prob_cols = [f'c{i}' for i in range(10)]\n    display(submission[prob_cols].sum(axis=1).describe())\nelse:\n    print('submission_fold0.csv not found in this runtime.')","metadata":{"execution":{"iopub.status.busy":"2026-06-12T13:03:25.638822Z","iopub.execute_input":"2026-06-12T13:03:25.639651Z","iopub.status.idle":"2026-06-12T13:03:25.644975Z","shell.execute_reply.started":"2026-06-12T13:03:25.639574Z","shell.execute_reply":"2026-06-12T13:03:25.644159Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"6de742c1","cell_type":"markdown","source":"## 6) Kaggle submission evidence","metadata":{}},{"id":"18814259","cell_type":"code","source":"cmd = ['kaggle', 'competitions', 'submissions', '-c', 'state-farm-distracted-driver-detection']\nresult = subprocess.run(cmd, check=True, capture_output=True, text=True)\nprint(result.stdout)","metadata":{"execution":{"iopub.status.busy":"2026-06-12T13:03:25.988408Z","iopub.execute_input":"2026-06-12T13:03:25.989182Z","iopub.status.idle":"2026-06-12T13:03:27.571780Z","shell.execute_reply.started":"2026-06-12T13:03:25.989148Z","shell.execute_reply":"2026-06-12T13:03:27.571011Z"},"trusted":true},"outputs":[],"execution_count":null},{"id":"53e88427","cell_type":"markdown","source":"## 7) Optional retraining switch","metadata":{}},{"id":"6a81d48f","cell_type":"code","source":"RUN_FULL_PIPELINE = False\nif RUN_FULL_PIPELINE:\n    cmd = [sys.executable, 'scripts/run_pipeline.py']\n    subprocess.run(cmd, cwd=ROOT, check=True, text=True)\n    print('Pipeline completed.')\nelse:\n    print('Skipped retraining in notebook; artifacts are from real prior run.')","metadata":{"execution":{"iopub.execute_input":"2026-06-12T12:33:02.613248Z","iopub.status.busy":"2026-06-12T12:33:02.613116Z","iopub.status.idle":"2026-06-12T12:33:02.617529Z","shell.execute_reply":"2026-06-12T12:33:02.615947Z"}},"outputs":[],"execution_count":null}]}