{"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":"9426bb2e-3e52-4a7a-a653-a5e28b8e56bf","cell_type":"markdown","source":"# RSNA Knee — DINOv2 + UniMed target-wise blend\nAttach the competition, the existing `rsna-knee-v2` dataset used for the 0.883 submission, and the new `rsna-unimed-blend-v4` dataset. Select a GPU, turn Internet off, then run all cells.","metadata":{}},{"id":"c3766a83-0704-4bef-b7f7-e1ed027e82bd","cell_type":"code","source":"from pathlib import Path\nimport os\nimport subprocess\nimport sys\nimport torch\n\nassert torch.cuda.is_available(), 'Settings > Accelerator must be set to GPU'\ninput_root = Path('/kaggle/input')\n\ndef exactly_one(paths, label):\n    values = sorted(set(Path(path) for path in paths))\n    assert len(values) == 1, f'{label}: expected one, found {values}'\n    return values[0]\n\ncompetition_roots = [p for p in [*input_root.glob('competitions/*'), *input_root.iterdir()]\n                     if p.is_dir() and (p / 'test.csv').is_file()\n                     and (p / 'sample_submission.csv').is_file()\n                     and (p / 'test_series.csv').is_file()\n                     and (p / 'test_series').is_dir()]\ncompetition_root = exactly_one(competition_roots, 'competition root')\nasset_roots = [p for p in input_root.glob('datasets/*/*') if p.is_dir()]\nasset_roots += [p for p in input_root.iterdir()\n                if p.is_dir() and p.name not in {'competitions', 'datasets'}\n                and p != competition_root]\nasset_roots = sorted(set(asset_roots))\nprint('Private dataset roots:', asset_roots, flush=True)\n\ndef find_assets(pattern):\n    return [path for root in asset_roots for path in root.rglob(pattern)]\n\nblend_script = exactly_one(find_assets('kaggle_blend_inference.py'), 'blend code')\ncode_root = blend_script.parents[1]\ndino_config = exactly_one(find_assets('dinov2s_336_llm.yaml'), 'DINO config')\nmst_config = exactly_one(find_assets('unimed_mst_v4.yaml'), 'MST config')\nweights = exactly_one(find_assets('targetwise_blend_unimed_mst_v4.json'), 'blend weights')\ndino_backbone = exactly_one(\n    [p.parent for p in find_assets('model.safetensors')\n     if (p.parent / 'config.json').is_file()], 'DINO backbone')\ndino_checkpoints = exactly_one(\n    [p for p in find_assets('rsna-checkpoints')\n     if len(list(p.glob('fold_*_best.pt'))) == 5], 'DINO checkpoints')\nmst_checkpoints = exactly_one(\n    [p for p in find_assets('rsna-unimed-checkpoints')\n     if len(list(p.glob('fold_*_best.pt'))) == 5], 'MST checkpoints')\nunimed_checkpoint = exactly_one(find_assets('visual_state.pt'), 'UniMed visual checkpoint')\n\npaths = {\n    'competition': competition_root, 'code': code_root,\n    'dino_config': dino_config, 'dino_checkpoints': dino_checkpoints,\n    'dino_backbone': dino_backbone, 'mst_config': mst_config,\n    'mst_checkpoints': mst_checkpoints, 'unimed_checkpoint': unimed_checkpoint,\n    'weights': weights,\n}\nprint('GPU:', torch.cuda.get_device_name(0))\nfor name, path in paths.items(): print(f'{name:20s} {path}')\n\nenv = os.environ.copy()\nenv.update({'HF_HUB_OFFLINE': '1', 'TRANSFORMERS_OFFLINE': '1', 'USE_TF': '0'})\ncommand = [\n    sys.executable, '-m', 'scripts.kaggle_blend_inference',\n    '--competition-root', str(competition_root),\n    '--dino-config', str(dino_config),\n    '--dino-checkpoint-dir', str(dino_checkpoints),\n    '--dino-backbone-dir', str(dino_backbone),\n    '--mst-config', str(mst_config),\n    '--mst-checkpoint-dir', str(mst_checkpoints),\n    '--unimed-checkpoint', str(unimed_checkpoint),\n    '--weights', str(weights),\n    '--workers', '4',\n]\nsubprocess.run(command, cwd=code_root, env=env, check=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-23T19:29:32.77232Z","iopub.execute_input":"2026-08-23T19:29:32.772941Z","iopub.status.idle":"2026-08-23T19:30:17.647988Z","shell.execute_reply.started":"2026-08-23T19:29:32.772909Z","shell.execute_reply":"2026-08-23T19:30:17.647041Z"}},"outputs":[],"execution_count":null},{"id":"4d310559-d04f-4ae5-92ea-3e42fab478a1","cell_type":"code","source":"import numpy as np\nimport pandas as pd\nsubmission = pd.read_csv('/kaggle/working/submission.csv')\nsample = pd.read_csv(competition_root / 'sample_submission.csv')\nassert submission.columns.tolist() == sample.columns.tolist()\nassert submission.iloc[:, 0].astype(str).tolist() == sample.iloc[:, 0].astype(str).tolist()\nassert np.isfinite(submission.iloc[:, 1:].to_numpy()).all()\nassert submission.iloc[:, 1:].to_numpy().min() >= 0\nassert submission.iloc[:, 1:].to_numpy().max() <= 1\nprint('submission valid:', submission.shape)\ndisplay(submission.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-23T19:30:17.649784Z","iopub.execute_input":"2026-08-23T19:30:17.650494Z","iopub.status.idle":"2026-08-23T19:30:17.674334Z","shell.execute_reply.started":"2026-08-23T19:30:17.650471Z","shell.execute_reply":"2026-08-23T19:30:17.673434Z"}},"outputs":[],"execution_count":null}]}