{"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":"3001d7ce","cell_type":"markdown","source":"# RSNA Knee — MaxSpan Raptor + Independent DINOv3 Ensemble\n\nNotebook 3 combines two genuinely different MRI model families:\n\n- **MaxSpan Raptor CoAtNet** — a stronger successor to our `0.924` baseline;\n  its publisher reports `0.928` as a single model.\n- **Five-fold DINOv3 ViT-S/16** — an independently trained model with six\n  plane/contrast slots and a study-level token-attention head.\n\nThe final prediction is a **target-wise rank blend: 90% Raptor + 10% DINOv3**.\nThis weight is frozen before submission. It is deliberately conservative because\nno verified Raptor out-of-fold predictions are available; we will not sweep blend\nweights against the public leaderboard.\n\nSafety is staged: a chance file is written first, then a complete Raptor-only file,\nand only a fully completed DINOv3 run can atomically replace it with the blend.\nPartial independent predictions are never mixed into a submission.\n\n### Attribution and licenses\n\n- Raptor inference is adapted from Dread Development's Apache-2.0 notebook\n  [Knee MRI: twelve findings from a single model](https://www.kaggle.com/code/dreaddevelopment/knee-mri-twelve-findings-from-a-single-model).\n  The [MaxSpan checkpoint dataset](https://www.kaggle.com/datasets/dreaddevelopment/raptor-knee-maxspan)\n  is CC0.\n- The DINOv3 implementation is adapted from Mattia Angeli's public notebook\n  [Bend the Knee to DINOv3 (ensembled)](https://www.kaggle.com/code/mattiaangeli/bend-the-knee-to-dinov3-ensembled).\n  We use only the independently trained five-fold DINOv3 member—not its later\n  public-leaderboard-tuned ensemble. The\n  [checkpoint dataset](https://www.kaggle.com/datasets/mattiaangeli/knee-mri-fold-weights)\n  is CC0; the underlying pretrained architecture retains Meta's\n  [DINOv3 license](https://huggingface.co/timm/vit_small_patch16_dinov3.lvd1689m).\n- Adapted Apache-2.0 implementation portions retain their original attribution.\n\nMedical note: this is a competition model, not a clinical diagnostic system.\n","metadata":{}},{"id":"9734a572","cell_type":"markdown","source":"## 1. Attach inputs before running\n\nKeep the competition input and add these two public datasets using **Add Input**:\n\n1. `dreaddevelopment/raptor-knee-maxspan`\n   - Required file: `raptor_ft_coatnet_v5_full_swa.pt`\n2. `mattiaangeli/knee-mri-fold-weights`\n   - Title: **knee mri fold weights**\n   - Required files: `m_f0.pt` through `m_f4.pt`\n\nSelect **GPU T4 x2** and keep **Internet off**. MaxSpan runs first on GPU 0;\nDINOv3 then splits its five folds across both GPUs when two are available.\n","metadata":{}},{"id":"13ed3f6f","cell_type":"code","source":"from __future__ import annotations\n\nfrom concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor, as_completed\nfrom pathlib import Path\nimport gc\nimport glob\nimport hashlib\nimport importlib.metadata\nimport json\nimport os\nimport re\nimport subprocess\nimport sys\nimport time\nimport warnings\n\nos.environ.setdefault(\"HF_HUB_OFFLINE\", \"1\")\nos.environ.setdefault(\"TRANSFORMERS_OFFLINE\", \"1\")\nos.environ.setdefault(\"HF_HUB_DISABLE_TELEMETRY\", \"1\")\nfor _thread_var in (\"OMP_NUM_THREADS\", \"OPENBLAS_NUM_THREADS\", \"MKL_NUM_THREADS\"):\n    os.environ.setdefault(_thread_var, \"4\")\n\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_modality_lut\nfrom scipy.stats import rankdata, spearmanr\n# DINOv3 support was added to recent timm releases. The checkpoint dataset ships\n# the exact offline wheel used by its publisher, so Internet can remain disabled.\ndef _ensure_compatible_timm():\n    try:\n        installed = importlib.metadata.version(\"timm\")\n    except importlib.metadata.PackageNotFoundError:\n        installed = \"missing\"\n    if installed == \"1.0.22\":\n        return installed\n    candidates = [\n        Path(\"/kaggle/input/datasets/mattiaangeli/knee-mri-fold-weights/timm-1.0.22-py3-none-any.whl\"),\n        Path(\"/kaggle/input/knee-mri-fold-weights/timm-1.0.22-py3-none-any.whl\"),\n    ]\n    for dataset_root in (\n        Path(\"/kaggle/input/datasets/mattiaangeli/knee-mri-fold-weights\"),\n        Path(\"/kaggle/input/knee-mri-fold-weights\"),\n    ):\n        if dataset_root.is_dir():\n            candidates.extend(dataset_root.rglob(\"timm-1.0.22-py3-none-any.whl\"))\n    input_root = Path(\"/kaggle/input\")\n    if input_root.is_dir():\n        candidates.extend(input_root.glob(\"datasets/*/*/timm-1.0.22-py3-none-any.whl\"))\n        candidates.extend(input_root.glob(\"*/timm-1.0.22-py3-none-any.whl\"))\n    wheel = next((path for path in candidates if path.is_file()), None)\n    if wheel is not None:\n        subprocess.run(\n            [sys.executable, \"-m\", \"pip\", \"install\", \"--no-deps\", \"--quiet\", str(wheel)],\n            check=True,\n        )\n        return \"1.0.22 (offline wheel)\"\n    return installed\n\n\nTIMM_BOOTSTRAP = _ensure_compatible_timm()\nimport timm\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nwarnings.filterwarnings(\"ignore\", category=UserWarning, module=\"pydicom\")\ncv2.setNumThreads(1)\ntorch.backends.cudnn.benchmark = True\ntorch.backends.cuda.matmul.allow_tf32 = True\n\nNOTEBOOK_START = time.time()\nLABELS = [\n    \"ACL\", \"MCL\", \"Medial Meniscus\", \"Lateral Meniscus\",\n    \"Medial OA\", \"Lateral OA\", \"PF OA\", \"Effusion\",\n    \"Synovitis\", \"Baker's\", \"Contusion\", \"Fracture\",\n]\nRAPTOR_BLEND_WEIGHT = 0.90\nDINO_BLEND_WEIGHT = 0.10\nDINO_START_LATEST_SECONDS = 6.25 * 3600\nDINO_HARD_STOP_SECONDS = 8.0 * 3600\n\nWORK = Path(\"/kaggle/working\")\nOUTPUT_PATH = WORK / \"submission.csv\"\nRAPTOR_SUBMISSION_PATH = WORK / \"submission_raptor_maxspan.csv\"\nDINO_SUBMISSION_PATH = WORK / \"submission_dinov3.csv\"\nRAPTOR_RAW_PATH = WORK / \"raw_predictions_raptor_maxspan.csv\"\nDINO_RAW_PATH = WORK / \"raw_predictions_dinov3.csv\"\nDIAGNOSTIC_PATH = WORK / \"ensemble_diagnostics.csv\"\nMANIFEST_PATH = WORK / \"ensemble_manifest.json\"\nFAILURE_PATH = WORK / \"inference_failures.csv\"\nWORK.mkdir(parents=True, exist_ok=True)\n\n\ndef find_competition_root():\n    candidates = [\n        Path(\"/kaggle/input/competitions/rsna-knee-abnormality-detection\"),\n        Path(\"/kaggle/input/rsna-knee-abnormality-detection\"),\n    ]\n    input_root = Path(\"/kaggle/input\")\n    if input_root.is_dir():\n        candidates.extend(path.parent for pattern in (\"*/test.csv\", \"*/*/test.csv\")\n                          for path in input_root.glob(pattern))\n    for candidate in candidates:\n        required = all((candidate / name).is_file() for name in (\n            \"test.csv\", \"test_series.csv\", \"sample_submission.csv\"\n        ))\n        has_images = (candidate / \"test_series\").is_dir() or (candidate / \"test_images\").is_dir()\n        if required and has_images:\n            return candidate\n    raise FileNotFoundError(\"Attach the RSNA Knee Abnormality Detection competition input.\")\n\n\ndef first_existing(candidates):\n    for candidate in candidates:\n        if candidate.exists():\n            return candidate\n    return None\n\n\ndef find_external_file(filename, direct_paths):\n    hit = first_existing([Path(path) for path in direct_paths])\n    if hit is not None:\n        return hit\n    input_root = Path(\"/kaggle/input\")\n    if not input_root.is_dir():\n        return None\n    search_roots = []\n    datasets_root = input_root / \"datasets\"\n    if datasets_root.is_dir():\n        search_roots.extend(path for owner in datasets_root.iterdir() if owner.is_dir()\n                            for path in owner.iterdir() if path.is_dir())\n    search_roots.extend(path for path in input_root.iterdir()\n                        if path.is_dir() and path.name not in {\"competitions\", \"datasets\"})\n    for directory in sorted(set(search_roots)):\n        found = next(directory.rglob(filename), None)\n        if found is not None:\n            return found\n    return None\n\n\ndef find_dino_checkpoint_directory():\n    direct = [\n        Path(\"/kaggle/input/datasets/mattiaangeli/knee-mri-fold-weights\"),\n        Path(\"/kaggle/input/knee-mri-fold-weights\"),\n    ]\n    for directory in direct:\n        if len(list(directory.glob(\"m_f*.pt\"))) >= 5:\n            return directory\n    first = find_external_file(\"m_f0.pt\", [])\n    return first.parent if first is not None else None\n\n\ndef atomic_write_csv(frame, path):\n    temporary = path.with_name(path.name + \".tmp\")\n    frame.to_csv(temporary, index=False)\n    os.replace(temporary, path)\n\n\ndef atomic_write_json(payload, path):\n    temporary = path.with_name(path.name + \".tmp\")\n    with open(temporary, \"w\", encoding=\"utf-8\") as stream:\n        json.dump(payload, stream, indent=2, sort_keys=True)\n    os.replace(temporary, path)\n\n\ndef sha256_file(path, block_size=8 * 1024 * 1024):\n    digest = hashlib.sha256()\n    with open(path, \"rb\") as stream:\n        for block in iter(lambda: stream.read(block_size), b\"\"):\n            digest.update(block)\n    return digest.hexdigest()\n\n\ndef safe_sha256_file(path):\n    try:\n        return sha256_file(path)\n    except Exception as error:\n        print(f\"Optional SHA-256 audit failed for {path}: {type(error).__name__}: {error}\")\n        return None\n\n\ndef optional_write_csv(frame, path):\n    try:\n        atomic_write_csv(frame, path)\n        return True\n    except Exception as error:\n        print(f\"Optional audit write failed for {path}: {type(error).__name__}: {error}\")\n        return False\n\n\ndef optional_write_json(payload, path):\n    try:\n        atomic_write_json(payload, path)\n        return True\n    except Exception as error:\n        print(f\"Optional audit write failed for {path}: {type(error).__name__}: {error}\")\n        return False\n\n\ndef validate_submission(frame, expected_ids, expected_columns):\n    assert frame.columns.tolist() == expected_columns, \"Submission column order is wrong.\"\n    assert frame[\"StudyInstanceUID\"].astype(str).tolist() == list(expected_ids), (\n        \"Submission study IDs or order do not match test.csv.\"\n    )\n    assert frame[\"StudyInstanceUID\"].is_unique, \"Duplicate study IDs found.\"\n    values = frame[LABELS].to_numpy(dtype=np.float64)\n    assert np.isfinite(values).all(), \"Submission contains NaN or infinity.\"\n    assert ((values >= 0) & (values <= 1)).all(), \"Submission values must be in [0, 1].\"\n    return frame\n\n\ndef rank_available(raw, availability):\n    \"\"\"Target-wise average midranks. Constant/nonfinite targets are unavailable.\"\"\"\n    raw = np.asarray(raw, dtype=np.float64)\n    availability = np.asarray(availability, dtype=bool) & np.isfinite(raw)\n    ranks = np.full(raw.shape, np.nan, dtype=np.float64)\n    ranked_ok = np.zeros(raw.shape, dtype=bool)\n    for target_index in range(raw.shape[1]):\n        valid = availability[:, target_index]\n        count = int(valid.sum())\n        if count < 2:\n            continue\n        values = raw[valid, target_index]\n        if float(np.ptp(values)) <= 1e-12:\n            continue\n        ranks[valid, target_index] = (rankdata(values, method=\"average\") - 1.0) / (count - 1.0)\n        ranked_ok[valid, target_index] = True\n    return ranks, ranked_ok\n\n\ndef frame_from_rank(ranks, availability, study_ids):\n    values = np.where(availability & np.isfinite(ranks), ranks, 0.5)\n    frame = pd.DataFrame(values, columns=LABELS)\n    frame.insert(0, \"StudyInstanceUID\", list(study_ids))\n    return frame\n\n\nROOT = find_competition_root()\nTEST = pd.read_csv(ROOT / \"test.csv\", dtype={\"StudyInstanceUID\": \"string\"})\nTEST_SERIES = pd.read_csv(\n    ROOT / \"test_series.csv\",\n    dtype={\"StudyInstanceUID\": \"string\", \"SeriesInstanceUID\": \"string\"},\n)\nTEST_SERIES = TEST_SERIES.loc[:, ~TEST_SERIES.columns.duplicated()].copy()\nTEST_IDS = TEST[\"StudyInstanceUID\"].astype(str).tolist()\nSAMPLE = pd.read_csv(ROOT / \"sample_submission.csv\", dtype={\"StudyInstanceUID\": \"string\"})\nassert SAMPLE.columns.tolist() == [\"StudyInstanceUID\", *LABELS]\nassert SAMPLE[\"StudyInstanceUID\"].astype(str).tolist() == TEST_IDS\n\n# The file always exists, even if a required input was forgotten.\nchance = SAMPLE.copy()\nchance[LABELS] = 0.5\natomic_write_csv(chance, OUTPUT_PATH)\n\nRAPTOR_WEIGHT_PATH = find_external_file(\n    \"raptor_ft_coatnet_v5_full_swa.pt\",\n    [\n        \"/kaggle/input/datasets/dreaddevelopment/raptor-knee-maxspan/raptor_ft_coatnet_v5_full_swa.pt\",\n        \"/kaggle/input/raptor-knee-maxspan/raptor_ft_coatnet_v5_full_swa.pt\",\n        \"/kaggle/input/raptor-knee-arms/raptor_ft_coatnet_v5_full_swa.pt\",\n        \"/kaggle/input/raptor-knee-arms/1/raptor_ft_coatnet_v5_full_swa.pt\",\n    ],\n)\n# A forgotten MaxSpan input must not force a chance submission if the prior v4\n# dataset happens to be attached. Its preprocessing recipe is selected explicitly.\nif RAPTOR_WEIGHT_PATH is None:\n    RAPTOR_WEIGHT_PATH = find_external_file(\n        \"raptor_ft_coatnet_v4_full.pt\",\n        [\n            \"/kaggle/input/datasets/dreaddevelopment/raptor-knee-widedense/raptor_ft_coatnet_v4_full.pt\",\n            \"/kaggle/input/raptor-knee-widedense/raptor_ft_coatnet_v4_full.pt\",\n        ],\n    )\nDINO_CHECKPOINT_DIR = find_dino_checkpoint_directory()\n\nif RAPTOR_WEIGHT_PATH is None:\n    raise FileNotFoundError(\n        \"Missing Raptor weights. Add dataset 'dreaddevelopment/raptor-knee-maxspan'.\"\n    )\nif DINO_CHECKPOINT_DIR is None:\n    print(\"WARNING: DINOv3 checkpoints are missing; the notebook will safely keep Raptor-only output.\")\n\nDEVICE = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nif DEVICE.type != \"cuda\":\n    raise RuntimeError(\"Select GPU T4 x2 before running; CPU inference may exceed nine hours.\")\n\nSERIES_ROOT = ROOT / \"test_series\"\nif not SERIES_ROOT.is_dir():\n    SERIES_ROOT = ROOT / \"test_images\"\n\nprint({\n    \"competition_root\": str(ROOT),\n    \"test_studies\": len(TEST_IDS),\n    \"test_series\": len(TEST_SERIES),\n    \"raptor_checkpoint\": str(RAPTOR_WEIGHT_PATH),\n    \"dinov3_checkpoint_dir\": str(DINO_CHECKPOINT_DIR) if DINO_CHECKPOINT_DIR else None,\n    \"device\": str(DEVICE),\n    \"gpu_count\": torch.cuda.device_count(),\n    \"torch\": torch.__version__,\n    \"timm\": timm.__version__,\n    \"timm_bootstrap\": TIMM_BOOTSTRAP,\n    \"initial_fallback\": str(OUTPUT_PATH),\n})\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-26T14:30:57.949352Z","iopub.execute_input":"2026-08-26T14:30:57.95004Z","iopub.status.idle":"2026-08-26T14:31:01.51807Z","shell.execute_reply.started":"2026-08-26T14:30:57.950011Z","shell.execute_reply":"2026-08-26T14:31:01.517383Z"}},"outputs":[],"execution_count":null},{"id":"0f8a63a9","cell_type":"markdown","source":"## 2. Raptor CoAtNet model\n\nRaptor is run first. Once every study has been attempted, a fully valid Raptor-only\nsubmission atomically replaces the chance fallback. DICOM preprocessing mirrors\nthe checkpoint's training pipeline: five series slots, geometric slice ordering,\na 140 mm crop, a 2–98% slice span, and 62 overlapping 2.5D windows.\n","metadata":{}},{"id":"3e1482ae","cell_type":"code","source":"R_IMG = 336\nR_CROP_MM = 140.0\nR_SLOTS = [\n    (\"Sagittal\", 1, 18),\n    (\"Sagittal\", 0, 14),\n    (\"Coronal\", 1, 12),\n    (\"Coronal\", 0, 8),\n    (\"Axial\", -1, 12),\n]\nR_MAX_SLICES = sum(slot[2] for slot in R_SLOTS)\nif RAPTOR_WEIGHT_PATH.name == \"raptor_ft_coatnet_v5_full_swa.pt\":\n    R_SPAN_LOW, R_SPAN_HIGH, R_N_WINDOWS = 0.02, 0.98, 62\n    R_RECIPE = \"maxspan-v5\"\nelif RAPTOR_WEIGHT_PATH.name == \"raptor_ft_coatnet_v4_full.pt\":\n    R_SPAN_LOW, R_SPAN_HIGH, R_N_WINDOWS = 0.06, 0.94, 42\n    R_RECIPE = \"widedense-v4-fallback\"\nelse:\n    raise ValueError(f\"No reviewed preprocessing recipe for {RAPTOR_WEIGHT_PATH.name}\")\nR_IMAGENET_MEAN = torch.tensor([0.485, 0.456, 0.406]).view(3, 1, 1)\nR_IMAGENET_STD = torch.tensor([0.229, 0.224, 0.225]).view(3, 1, 1)\nR_DEFAULT_ARCH = \"coatnet_rmlp_2_rw_384.sw_in12k_ft_in1k\"\nR_DEFAULT_RESOLUTION = 384\n\n\ndef r_build_backbone(architecture, pretrained=False):\n    hybrid = architecture.startswith((\"maxvit\", \"maxxvit\", \"coatnet\", \"coat_\", \"convnext\"))\n    is_vit = (not hybrid) and any(name in architecture for name in (\n        \"vit\", \"deit\", \"dinov2\", \"eva\", \"beit\"\n    ))\n    options = dict(pretrained=pretrained, num_classes=0, in_chans=3)\n    options.update(global_pool=\"token\", dynamic_img_size=True) if is_vit else options.update(global_pool=\"avg\")\n    return timm.create_model(architecture, **options)\n\n\nclass RaptorClassifier(nn.Module):\n    def __init__(self, backbone, feature_dim, n_labels=12, dropout=0.2):\n        super().__init__()\n        self.backbone = backbone\n        self.norm = nn.LayerNorm(feature_dim)\n        # Names must match the published checkpoint exactly.\n        self.att = nn.Sequential(\n            nn.Linear(feature_dim, 256), nn.Tanh(), nn.Dropout(dropout),\n            nn.Linear(256, n_labels),\n        )\n        self.clsW = nn.Parameter(torch.zeros(n_labels, feature_dim))\n        self.clsb = nn.Parameter(torch.zeros(n_labels))\n        nn.init.trunc_normal_(self.clsW, std=0.02)\n\n    def forward(self, windows):\n        batch, count = windows.shape[:2]\n        features = self.backbone(windows.flatten(0, 1)).view(batch, count, -1)\n        features = self.norm(features)\n        attention = torch.softmax(self.att(features), dim=1)\n        pooled = torch.einsum(\"bkn,bkf->bnf\", attention, features)\n        return (pooled * self.clsW).sum(-1) + self.clsb\n\n\ndef r_load_model(path, device):\n    checkpoint = torch.load(path, map_location=\"cpu\", weights_only=False)\n    checkpoint_labels = checkpoint.get(\"lab\", checkpoint.get(\"labels\"))\n    if checkpoint_labels is not None and list(checkpoint_labels) != LABELS:\n        raise ValueError(\"Raptor checkpoint target order does not match the competition.\")\n    architecture = checkpoint.get(\"arch\", R_DEFAULT_ARCH)\n    resolution = int(checkpoint.get(\"res\", R_DEFAULT_RESOLUTION))\n    backbone = r_build_backbone(architecture, pretrained=False)\n    model = RaptorClassifier(backbone, backbone.num_features)\n    model.load_state_dict(checkpoint[\"model\"], strict=True)\n    model.eval().to(device)\n    del checkpoint\n    gc.collect()\n    return model, resolution, architecture\n\n\ndef r_evaluation_centers(mask, depth, count):\n    valid = np.where(mask > 0)[0]\n    if len(valid) < 3:\n        valid = np.arange(min(3, depth))\n    low, high = int(valid.min()), int(valid.max())\n    centers = [index for index in range(low + 1, high)\n               if index - 1 >= low and index + 1 <= high]\n    if not centers:\n        centers = [max(1, min((low + high) // 2, depth - 2))]\n    positions = np.linspace(0, len(centers) - 1, count).round().astype(int)\n    return [centers[position] for position in positions]\n\n\ndef r_make_windows(volume, mask, count, resolution):\n    centers = r_evaluation_centers(mask, len(volume), count)\n    windows = np.empty((len(centers), 3, resolution, resolution), np.float32)\n    for window_index, center in enumerate(centers):\n        center = max(1, min(center, len(volume) - 2))\n        triplet = np.stack([volume[center - 1], volume[center], volume[center + 1]])\n        tensor = torch.from_numpy(triplet.astype(np.float32) / 255.0)\n        if tensor.shape[-1] != resolution:\n            tensor = F.interpolate(\n                tensor[None], size=(resolution, resolution), mode=\"bilinear\", align_corners=False\n            )[0]\n        windows[window_index] = tensor.numpy()\n    tensor = torch.from_numpy(windows)\n    return (tensor - R_IMAGENET_MEAN) / R_IMAGENET_STD\n\n\n@torch.inference_mode()\ndef r_predict_study(model, windows, device):\n    windows = windows.unsqueeze(0).to(device)\n    try:\n        with torch.autocast(\"cuda\", dtype=torch.float16):\n            return torch.sigmoid(model(windows).float())[0].cpu().numpy()\n    except RuntimeError as error:\n        print(f\"Raptor half-precision retry in full precision: {error}\")\n        torch.cuda.empty_cache()\n        return torch.sigmoid(model(windows).float())[0].cpu().numpy()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-26T14:31:01.519604Z","iopub.execute_input":"2026-08-26T14:31:01.519921Z","iopub.status.idle":"2026-08-26T14:31:01.540422Z","shell.execute_reply.started":"2026-08-26T14:31:01.519898Z","shell.execute_reply":"2026-08-26T14:31:01.539663Z"}},"outputs":[],"execution_count":null},{"id":"45ca9198","cell_type":"code","source":"def r_ordered_files_and_spacing(series_directory):\n    records, spacings = [], []\n    for path in glob.glob(str(series_directory / \"*.dcm\")):\n        try:\n            header = pydicom.dcmread(path, stop_before_pixels=True)\n            orientation = getattr(header, \"ImageOrientationPatient\", None)\n            position = getattr(header, \"ImagePositionPatient\", None)\n            if orientation is not None and position is not None and len(orientation) == 6:\n                row = np.asarray(orientation[:3], dtype=float)\n                column = np.asarray(orientation[3:], dtype=float)\n                normal = np.cross(row, column)\n                location = float(np.dot(np.asarray(position, dtype=float), normal))\n            else:\n                location = float(getattr(header, \"InstanceNumber\", 0) or 0)\n            pixel_spacing = getattr(header, \"PixelSpacing\", None)\n            pixel_spacing = float(pixel_spacing[0]) if pixel_spacing is not None else 0.5\n            spacings.append(pixel_spacing)\n            records.append((location, path, pixel_spacing))\n        except Exception:\n            records.append((0.0, path, 0.5))\n    records.sort(key=lambda item: item[0])\n    median_spacing = float(np.median(spacings)) if spacings else 0.5\n    return [(path, spacing) for _, path, spacing in records], median_spacing\n\n\ndef r_read_pixels(path):\n    dicom = pydicom.dcmread(path)\n    pixels = apply_modality_lut(dicom.pixel_array, dicom).astype(np.float32)\n    if pixels.ndim > 2:\n        pixels = pixels[len(pixels) // 2]\n    if str(getattr(dicom, \"PhotometricInterpretation\", \"\")) == \"MONOCHROME1\":\n        pixels = pixels.max() - pixels\n    return pixels\n\n\ndef r_crop_in_millimetres(pixels, pixel_spacing):\n    height, width = pixels.shape\n    crop_pixels = int(round(R_CROP_MM / max(pixel_spacing, 1e-3)))\n    crop_pixels = min(crop_pixels, height, width)\n    y0, x0 = (height - crop_pixels) // 2, (width - crop_pixels) // 2\n    crop = pixels[y0:y0 + crop_pixels, x0:x0 + crop_pixels]\n    return cv2.resize(crop, (R_IMG, R_IMG), interpolation=cv2.INTER_AREA)\n\n\ndef r_pick_series(rows, plane, fluid_sensitive, used):\n    candidates = [\n        row for row in rows\n        if row[\"Anatomical_Plane\"] == plane and row[\"SeriesInstanceUID\"] not in used\n    ]\n    if fluid_sensitive in (0, 1):\n        preferred = [\n            row for row in candidates\n            if int(row.get(\"Fluid_Sensitive\", 0) or 0) == fluid_sensitive\n        ]\n        if preferred:\n            return preferred[0]\n    return candidates[0] if candidates else None\n\n\ndef r_build_study_volume(study_id, series_by_study):\n    rows = series_by_study.get(study_id, [])\n    volume = np.zeros((R_MAX_SLICES, R_IMG, R_IMG), dtype=np.uint8)\n    output_index, used = 0, set()\n    for plane, fluid_sensitive, slice_count in R_SLOTS:\n        series = r_pick_series(rows, plane, fluid_sensitive, used)\n        if series is None:\n            output_index += slice_count\n            continue\n        used.add(series[\"SeriesInstanceUID\"])\n        directory = SERIES_ROOT / study_id / series[\"SeriesInstanceUID\"]\n        files, median_spacing = r_ordered_files_and_spacing(directory)\n        if not files:\n            output_index += slice_count\n            continue\n        count = len(files)\n        low = int(count * R_SPAN_LOW)\n        high = max(int(count * R_SPAN_HIGH) - 1, low)\n        positions = (np.linspace(low, high, slice_count).round().astype(int)\n                     if count > 1 else [0] * slice_count)\n        arrays, spacings = [], []\n        for position in positions:\n            path, spacing = files[min(int(position), count - 1)]\n            try:\n                arrays.append(r_read_pixels(path))\n                spacings.append(spacing)\n            except Exception:\n                arrays.append(None)\n                spacings.append(median_spacing)\n        valid_arrays = [array for array in arrays if array is not None]\n        if valid_arrays:\n            combined = np.concatenate([array.ravel() for array in valid_arrays])\n            low_value, high_value = np.percentile(combined, [2.0, 98.0])\n        else:\n            low_value, high_value = 0.0, 1.0\n        for array, spacing in zip(arrays, spacings):\n            if output_index >= R_MAX_SLICES:\n                break\n            if array is None:\n                output_index += 1\n                continue\n            normalized = np.clip((array - low_value) / (high_value - low_value + 1e-6), 0, 1)\n            normalized = r_crop_in_millimetres(\n                normalized, spacing if spacing > 0 else median_spacing\n            )\n            volume[output_index] = (normalized * 255).astype(np.uint8)\n            output_index += 1\n    mask = (volume.reshape(R_MAX_SLICES, -1).sum(axis=1) > 0).astype(np.uint8)\n    return volume, mask\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-26T14:31:01.541588Z","iopub.execute_input":"2026-08-26T14:31:01.541905Z","iopub.status.idle":"2026-08-26T14:31:01.561156Z","shell.execute_reply.started":"2026-08-26T14:31:01.54187Z","shell.execute_reply":"2026-08-26T14:31:01.56031Z"}},"outputs":[],"execution_count":null},{"id":"b9e8bdbe","cell_type":"markdown","source":"## 3. Run Raptor and write the safe baseline\n\nIndividual study failures remain unavailable in the raw matrix. Average midranks\nare computed only from successful predictions; unavailable rows receive neutral\n`0.5` in the standalone submission. Ties are preserved rather than arbitrarily\nordered.\n","metadata":{}},{"id":"f34c2420","cell_type":"code","source":"raptor_started = time.time()\nseries_by_study = {\n    str(study_id): group.to_dict(\"records\")\n    for study_id, group in TEST_SERIES.groupby(\"StudyInstanceUID\")\n}\nraptor_raw = np.full((len(TEST_IDS), len(LABELS)), np.nan, dtype=np.float32)\nraptor_raw_ok = np.zeros_like(raptor_raw, dtype=bool)\nraptor_failures = []\n\nraptor_model, raptor_resolution, raptor_architecture = r_load_model(\n    RAPTOR_WEIGHT_PATH, DEVICE\n)\nprint(\n    f\"Loaded Raptor {raptor_architecture} at {raptor_resolution}px | \"\n    f\"recipe={R_RECIPE}, span={R_SPAN_LOW:.0%}–{R_SPAN_HIGH:.0%}, windows={R_N_WINDOWS}\"\n)\n\nfor study_index, study_id in enumerate(TEST_IDS):\n    try:\n        volume, mask = r_build_study_volume(study_id, series_by_study)\n        if int(mask.sum()) < 3:\n            raise ValueError(\"fewer than three successfully decoded nonzero Raptor slices\")\n        windows = r_make_windows(volume, mask, R_N_WINDOWS, raptor_resolution)\n        prediction = r_predict_study(raptor_model, windows, DEVICE)\n        if prediction.shape != (len(LABELS),) or not np.isfinite(prediction).all():\n            raise FloatingPointError(f\"Invalid Raptor prediction shape/value: {prediction.shape}\")\n        raptor_raw[study_index] = prediction\n        raptor_raw_ok[study_index] = True\n        del volume, mask, windows\n    except Exception as error:\n        raptor_failures.append({\n            \"StudyInstanceUID\": study_id,\n            \"model\": R_RECIPE,\n            \"error_type\": type(error).__name__,\n            \"message\": str(error)[:400],\n        })\n        print(f\"Raptor fallback {study_index + 1}: {study_id[:20]} — {type(error).__name__}: {error}\")\n    if (study_index + 1) % 100 == 0 or study_index + 1 == len(TEST_IDS):\n        print(\n            f\"Raptor {study_index + 1}/{len(TEST_IDS)} in \"\n            f\"{time.time() - raptor_started:.0f}s\",\n            flush=True,\n        )\n\nraptor_raw_frame = pd.DataFrame(raptor_raw, columns=LABELS)\nraptor_raw_frame.insert(0, \"StudyInstanceUID\", TEST_IDS)\natomic_write_csv(raptor_raw_frame, RAPTOR_RAW_PATH)\n\nraptor_rank, raptor_rank_ok = rank_available(raptor_raw, raptor_raw_ok)\nraptor_submission = frame_from_rank(raptor_rank, raptor_rank_ok, TEST_IDS)\nraptor_submission = raptor_submission[SAMPLE.columns]\nvalidate_submission(raptor_submission, TEST_IDS, SAMPLE.columns.tolist())\natomic_write_csv(raptor_submission, RAPTOR_SUBMISSION_PATH)\natomic_write_csv(raptor_submission, OUTPUT_PATH)\n\ndel raptor_model\ngc.collect()\ntorch.cuda.empty_cache()\n\nraptor_seconds = time.time() - raptor_started\nprint({\n    \"safe_submission\": str(OUTPUT_PATH),\n    \"raptor_raw\": str(RAPTOR_RAW_PATH),\n    \"raptor_rows\": len(raptor_submission),\n    \"raptor_failed_studies\": len(raptor_failures),\n    \"raptor_seconds\": round(raptor_seconds, 1),\n    \"raptor_recipe\": R_RECIPE,\n})\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-26T14:31:01.562971Z","iopub.execute_input":"2026-08-26T14:31:01.563258Z","iopub.status.idle":"2026-08-26T14:31:09.403569Z","shell.execute_reply.started":"2026-08-26T14:31:01.563237Z","shell.execute_reply":"2026-08-26T14:31:09.40291Z"}},"outputs":[],"execution_count":null},{"id":"930b2476","cell_type":"markdown","source":"## 4. Independent DINOv3 preprocessing\n\nThe independent model uses six slots: fat-suppressed and non-fat-suppressed\nsagittal, coronal, and axial series. Sixteen slices per slot are cropped to a\n130 mm field of view and resized to `336×336`. This intentionally follows the\ncheckpoint publisher's preprocessing rather than reusing Raptor's representation.\n","metadata":{}},{"id":"0a9a6c46","cell_type":"code","source":"D_CROP_MM = 130.0\nD_SIZE = 336\nD_SLICE_BAND = (0.12, 0.88)\nD_N_SLICE = 16\nD_SLOTS = [\n    (\"Sagittal\", 1), (\"Sagittal\", 0),\n    (\"Coronal\", 1), (\"Coronal\", 0),\n    (\"Axial\", 1), (\"Axial\", 0),\n]\nD_N_SLOT = len(D_SLOTS)\n\n\ndef d_ordered_files(series_directory, cap=64):\n    keyed = []\n    for path in series_directory.glob(\"*.dcm\"):\n        try:\n            header = pydicom.dcmread(str(path), stop_before_pixels=True)\n            keyed.append((int(header.InstanceNumber), str(path)))\n        except Exception:\n            continue\n        if len(keyed) >= cap * 4:\n            break\n    return [path for _, path in sorted(keyed)]\n\n\ndef d_series_side(path):\n    try:\n        return float(pydicom.dcmread(path, stop_before_pixels=True).ImagePositionPatient[0])\n    except Exception:\n        return 0.0\n\n\ndef d_read_crop(path):\n    try:\n        dicom = pydicom.dcmread(path)\n        array = dicom.pixel_array.astype(np.float32)\n    except Exception:\n        return None\n    try:\n        pixel_spacing = float(dicom.PixelSpacing[0])\n    except Exception:\n        pixel_spacing = D_CROP_MM / max(array.shape)\n    half = int(round(D_CROP_MM / pixel_spacing / 2))\n    centre_y, centre_x = array.shape[0] // 2, array.shape[1] // 2\n    crop = array[\n        max(0, centre_y - half):min(array.shape[0], centre_y + half),\n        max(0, centre_x - half):min(array.shape[1], centre_x + half),\n    ]\n    return None if crop.size == 0 else crop\n\n\ndef d_window(crop, low, high, flip):\n    normalized = np.clip((crop - low) / max(high - low, 1e-6), 0, 1)\n    image = cv2.resize(normalized, (D_SIZE, D_SIZE), interpolation=cv2.INTER_AREA)\n    return image[:, ::-1].copy() if flip else image\n\n\ndef d_render(path, flip):\n    crop = d_read_crop(path)\n    if crop is None:\n        return None\n    low, high = np.percentile(crop[::4, ::4], [1, 99])\n    return d_window(crop, low, high, flip)\n\n\ndef d_build_study(arguments):\n    \"\"\"Top-level function so Kaggle's ProcessPoolExecutor can pickle it.\"\"\"\n    study_index, study_id, records = arguments\n    output = np.zeros((D_N_SLOT, D_N_SLICE, D_SIZE, D_SIZE), np.uint8)\n    mask = np.zeros(D_N_SLOT, np.uint8)\n    rows = pd.DataFrame(records)\n    if len(rows):\n        rows[\"Fat_Suppression\"] = pd.to_numeric(\n            rows.get(\"Fat_Suppression\", 0), errors=\"coerce\"\n        ).fillna(0).astype(int)\n        for slot_index, (plane, fat_suppression) in enumerate(D_SLOTS):\n            selected = rows[\n                (rows[\"Anatomical_Plane\"] == plane)\n                & (rows[\"Fat_Suppression\"] == fat_suppression)\n            ]\n            if selected.empty:\n                continue\n            files = d_ordered_files(\n                SERIES_ROOT / study_id / str(selected.iloc[0].SeriesInstanceUID)\n            )\n            if not files:\n                continue\n            flip = plane != \"Sagittal\" and d_series_side(files[0]) < 0\n            first = int(round(D_SLICE_BAND[0] * (len(files) - 1)))\n            last = int(round(D_SLICE_BAND[1] * (len(files) - 1)))\n            available = list(range(first, last + 1))\n            if len(available) >= D_N_SLICE:\n                picks = [available[int(round(position))]\n                         for position in np.linspace(0, len(available) - 1, D_N_SLICE)]\n                offset = 0\n            else:\n                picks = available\n                offset = (D_N_SLICE - len(available)) // 2\n            decoded_nonzero = 0\n            for slice_index, position in enumerate(picks):\n                image = d_render(files[position], flip)\n                if image is None:\n                    image = d_render(files[min(len(files) - 1, position + 1)], flip)\n                if image is not None:\n                    rendered = (image * 255).astype(np.uint8)\n                    output[slot_index, offset + slice_index] = rendered\n                    decoded_nonzero += int(np.any(rendered))\n            mask[slot_index] = decoded_nonzero\n    return study_index, output, mask\n\n\ndino_series_by_study = {\n    str(study_id): group.to_dict(\"records\")\n    for study_id, group in TEST_SERIES.groupby(\"StudyInstanceUID\")\n}\nprint(\n    f\"DINOv3 preprocessing sees {len(TEST_IDS)} studies and \"\n    f\"{len(dino_series_by_study)} with series metadata\"\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-26T14:31:09.40445Z","iopub.execute_input":"2026-08-26T14:31:09.404713Z","iopub.status.idle":"2026-08-26T14:31:09.424505Z","shell.execute_reply.started":"2026-08-26T14:31:09.404692Z","shell.execute_reply":"2026-08-26T14:31:09.423661Z"}},"outputs":[],"execution_count":null},{"id":"cba62306","cell_type":"markdown","source":"## 5. Independent DINOv3 model\n\nEach of the five fold checkpoints has a DINOv3 ViT-S/16 encoder. A learned\nplane/contrast token is inserted into each series, and twelve label queries attend\nacross all available series in a study. Fold predictions are converted to midranks,\naveraged, and re-ranked; probability scales from one fold therefore cannot dominate.\n","metadata":{}},{"id":"a3091e52","cell_type":"code","source":"D_N_SLOT_TYPES, D_MASK_IDX = 6, 0\n\n\ndef d_segment_softmax(scores, study_index, batch_size):\n    _, target_count = scores.shape\n    indices = study_index.unsqueeze(1).expand(-1, target_count)\n    maxima = torch.full(\n        (batch_size, target_count), float(\"-inf\"), device=scores.device, dtype=scores.dtype\n    )\n    maxima = maxima.scatter_reduce(0, indices, scores, reduce=\"amax\", include_self=True)\n    exponentials = (scores - maxima[study_index]).exp()\n    totals = torch.zeros(\n        batch_size, target_count, device=scores.device, dtype=scores.dtype\n    ).index_add_(0, study_index, exponentials)\n    return exponentials / totals[study_index].clamp(min=1e-6)\n\n\nclass DMeanMaxPool(nn.Module):\n    def forward(self, features, study_index, batch_size, slot=None, return_attn=False):\n        dimension = features.shape[1]\n        counts = torch.zeros(batch_size, device=features.device, dtype=features.dtype).index_add_(\n            0, study_index, torch.ones(features.shape[0], device=features.device, dtype=features.dtype)\n        )\n        mean = torch.zeros(\n            batch_size, dimension, device=features.device, dtype=features.dtype\n        ).index_add_(0, study_index, features)\n        mean = mean / counts.clamp(min=1).unsqueeze(1)\n        maximum = torch.full(\n            (batch_size, dimension), -10000.0, device=features.device, dtype=features.dtype\n        )\n        maximum = maximum.scatter_reduce(\n            0, study_index.unsqueeze(1).expand(-1, dimension), features,\n            reduce=\"amax\", include_self=True,\n        )\n        return torch.cat([mean, maximum], 1), None\n\n\nclass DLabelAttentionPool(nn.Module):\n    def __init__(self, dimension, n_labels=12, n_heads=4, slot_bias=True):\n        super().__init__()\n        self.d, self.k, self.h = dimension, n_labels, n_heads\n        self.q = nn.Parameter(torch.randn(n_labels, dimension) * 0.02)\n        self.key = nn.Linear(dimension, dimension)\n        self.val = nn.Linear(dimension, dimension)\n        self.slot_bias = (\n            nn.Parameter(torch.zeros(n_labels, D_N_SLOT_TYPES + 1)) if slot_bias else None\n        )\n\n    def forward(self, features, study_index, batch_size, slot=None, return_attn=False):\n        scores = self.key(features) @ self.q.t() / self.d ** 0.5\n        if self.slot_bias is not None and slot is not None:\n            scores = scores + self.slot_bias.t()[slot]\n        attention = d_segment_softmax(scores, study_index, batch_size)\n        output = torch.zeros(\n            batch_size, self.k, self.d,\n            device=features.device, dtype=features.dtype,\n        )\n        output = output.index_add_(\n            0, study_index, attention.unsqueeze(-1) * self.val(features).unsqueeze(1)\n        )\n        return output, attention\n\n\nclass DTokenXAttnPool(nn.Module):\n    def __init__(self, dimension, n_labels=12, n_heads=6, dropout=0.2):\n        super().__init__()\n        self.d, self.k = dimension, n_labels\n        self.q = nn.Parameter(torch.randn(n_labels, dimension) * 0.02)\n        self.slot_emb = nn.Embedding(\n            D_N_SLOT_TYPES + 1, dimension, padding_idx=D_MASK_IDX\n        )\n        self.kv_norm = nn.LayerNorm(dimension)\n        self.attn = nn.MultiheadAttention(\n            dimension, n_heads, dropout=dropout, batch_first=True\n        )\n\n    def forward(self, tokens, study_index, batch_size, slot=None, return_attn=False):\n        token_groups, token_count, dimension = tokens.shape\n        counts = torch.bincount(study_index, minlength=batch_size)\n        max_series = int(counts.max().item())\n        starts = torch.cumsum(counts, 0) - counts\n        positions = torch.arange(token_groups, device=tokens.device) - starts[study_index]\n        keys = tokens + self.slot_emb(slot).unsqueeze(1)\n        padded = tokens.new_zeros(batch_size, max_series, token_count, dimension)\n        padded[study_index, positions] = keys\n        keep = torch.zeros(batch_size, max_series, dtype=torch.bool, device=tokens.device)\n        keep[study_index, positions] = True\n        padding_mask = ~keep.repeat_interleave(token_count, dim=1)\n        padded = self.kv_norm(padded.reshape(batch_size, max_series * token_count, dimension))\n        queries = self.q.unsqueeze(0).expand(batch_size, -1, -1)\n        attended, weights = self.attn(\n            queries, padded, padded, key_padding_mask=padding_mask,\n            need_weights=return_attn, average_attn_weights=True,\n        )\n        cls = tokens[:, 0]\n        mean = torch.zeros(\n            batch_size, dimension, device=tokens.device, dtype=tokens.dtype\n        ).index_add_(0, study_index, cls) / counts.clamp(min=1).unsqueeze(1)\n        maximum = torch.full(\n            (batch_size, dimension), -10000.0, device=tokens.device, dtype=tokens.dtype\n        )\n        maximum = maximum.scatter_reduce(\n            0, study_index.unsqueeze(1).expand(-1, dimension), cls,\n            reduce=\"amax\", include_self=True,\n        )\n        base = torch.cat([mean, maximum], 1).unsqueeze(1).expand(-1, self.k, -1)\n        return torch.cat([attended, base], -1), weights\n\n\nclass DViTSlotToken(nn.Module):\n    def __init__(self, vit, n_categories, dimension=None):\n        super().__init__()\n        self.vit = vit\n        dimension = dimension or vit.embed_dim\n        self.tok = nn.Embedding(n_categories + 1, dimension, padding_idx=D_MASK_IDX)\n        self.num_features = vit.num_features\n        self._orig_prefix = getattr(vit, \"num_prefix_tokens\", 1)\n        vit.num_prefix_tokens = self._orig_prefix + 1\n        for block in vit.blocks:\n            attention = getattr(block, \"attn\", None)\n            if attention is not None and hasattr(attention, \"num_prefix_tokens\"):\n                attention.num_prefix_tokens += 1\n\n    @staticmethod\n    def _maybe(module, value):\n        return value if module is None else module(value)\n\n    def forward_features(self, images, categories):\n        vit = self.vit\n        features = vit.patch_embed(images)\n        positioned = vit._pos_embed(features)\n        rope = None\n        if isinstance(positioned, tuple):\n            features, rope = positioned\n        else:\n            features = positioned\n        features = self._maybe(getattr(vit, \"patch_drop\", None), features)\n        features = self._maybe(getattr(vit, \"norm_pre\", None), features)\n        token = self.tok(categories).unsqueeze(1)\n        features = torch.cat(\n            [features[:, :self._orig_prefix], token, features[:, self._orig_prefix:]], dim=1\n        )\n        if rope is not None:\n            if getattr(vit, \"rope_mixed\", False):\n                for index, block in enumerate(vit.blocks):\n                    features = block(features, rope=rope[index])\n            else:\n                for block in vit.blocks:\n                    features = block(features, rope=rope)\n        else:\n            features = vit.blocks(features)\n        return vit.norm(features)\n\n    def forward_head(self, features, pre_logits=True):\n        return self.vit.forward_head(features, pre_logits=pre_logits)\n\n\nD_IMAGENET_MEAN = (0.485, 0.456, 0.406)\nD_IMAGENET_STD = (0.229, 0.224, 0.225)\nD_N_PLANE, D_N_CONTRAST = 3, 2\n\n\nclass D_GatedDepthBlock(nn.Module):\n    def __init__(self, n_slice, dropout=0.0, ls_init=0.1):\n        super().__init__()\n        self.norm = nn.GroupNorm(1, n_slice)\n        self.v = nn.Conv2d(n_slice, n_slice, 1)\n        self.g = nn.Conv2d(n_slice, n_slice, 1)\n        self.out = nn.Conv2d(n_slice, n_slice, 1)\n        self.gamma = nn.Parameter(torch.full((n_slice, 1, 1), ls_init))\n        self.drop = nn.Dropout2d(dropout) if dropout else nn.Identity()\n\n    def forward(self, images):\n        normalized = self.norm(images)\n        update = self.out(self.v(normalized) * F.silu(self.g(normalized)))\n        return images + self.gamma * self.drop(update)\n\n\nclass DDepthCompress(nn.Module):\n    def __init__(\n        self, n_slice=16, out_ch=3, depth=1, dropout=0.0,\n        ls_init=0.1, imagenet=True, proj_noise=0.25,\n    ):\n        super().__init__()\n        self.imagenet = imagenet\n        self.blocks = nn.ModuleList([\n            D_GatedDepthBlock(n_slice, dropout, ls_init) for _ in range(depth)\n        ])\n        self.proj = nn.Conv2d(n_slice, out_ch, 1, bias=True)\n        if imagenet:\n            self.register_buffer(\"mu\", torch.tensor(D_IMAGENET_MEAN).view(1, -1, 1, 1))\n            self.register_buffer(\"sd\", torch.tensor(D_IMAGENET_STD).view(1, -1, 1, 1))\n\n    def forward(self, images):\n        keep = (images.amax(dim=1, keepdim=True) > 0).to(images.dtype)\n        features = images\n        for block in self.blocks:\n            features = block(features)\n        features = self.proj(features)\n        if self.imagenet:\n            features = (features - self.mu.to(features.dtype)) / self.sd.to(features.dtype)\n        return features * keep\n\n\ndef d_plane_of(slot):\n    return torch.clamp(slot - 1, 0, 5) // 2\n\n\ndef d_contrast_of(slot):\n    return torch.clamp(slot - 1, 0, 5) % 2\n\n\nclass DSlotDepthMixer(nn.Module):\n    def __init__(self, n_slice=16, ksize=5, alpha_max=0.25):\n        super().__init__()\n        self.n_slice, self.ksize, self.r = n_slice, ksize, ksize // 2\n        self.alpha_max = alpha_max\n        base = torch.tensor([1.0, 4.0, 6.0, 4.0, 1.0])\n        self.register_buffer(\"base\", base.log()[self.r:])\n        n_unique = self.r + 1\n        self.shared = nn.Parameter(torch.zeros(n_unique))\n        self.plane_k = nn.Parameter(torch.zeros(D_N_PLANE, n_unique))\n        self.contrast_k = nn.Parameter(torch.zeros(D_N_CONTRAST, n_unique))\n        self.g0 = nn.Parameter(torch.zeros(()))\n        self.gate_p = nn.Parameter(torch.zeros(D_N_PLANE))\n        self.gate_c = nn.Parameter(torch.zeros(D_N_CONTRAST))\n        indices = torch.arange(n_slice)\n        self.register_buffer(\"off\", indices[None, :] - indices[:, None])\n\n    def kernel(self, slot):\n        plane, contrast = d_plane_of(slot), d_contrast_of(slot)\n        half = self.base + self.shared + self.plane_k[plane] + self.contrast_k[contrast]\n        full = torch.cat([half.flip(-1)[..., :self.r], half], dim=-1)\n        return F.softmax(full, dim=-1)\n\n    def alpha(self, slot):\n        plane, contrast = d_plane_of(slot), d_contrast_of(slot)\n        return self.alpha_max * torch.tanh(\n            self.g0 + self.gate_p[plane] + self.gate_c[contrast]\n        )\n\n    def forward(self, images, slot, valid_mask):\n        token_count, n_slice, height, width = images.shape\n        if valid_mask is None:\n            raise ValueError(\"stem=mixer requires the padding mask\")\n        kernel = self.kernel(slot)\n        valid = valid_mask.to(kernel.dtype)\n        distance = self.off + self.r\n        in_bounds = (distance >= 0) & (distance < self.ksize)\n        local = kernel[:, distance.clamp(0, self.ksize - 1)] * in_bounds\n        matrix = local * valid[:, None, :]\n        denominator = matrix.sum(-1, keepdim=True)\n        identity = torch.eye(n_slice, device=images.device, dtype=matrix.dtype).expand(\n            token_count, n_slice, n_slice\n        )\n        okay = (denominator > 1e-6) & valid[:, :, None].bool()\n        matrix = torch.where(okay, matrix / denominator.clamp(min=1e-6), identity)\n        alpha = self.alpha(slot)[:, None, None]\n        operator = ((1.0 - alpha) * identity + alpha * matrix).to(images.dtype)\n        if images.is_contiguous(memory_format=torch.channels_last) and not images.is_contiguous():\n            mixed = torch.bmm(\n                images.permute(0, 2, 3, 1).reshape(token_count, height * width, n_slice),\n                operator.transpose(1, 2),\n            )\n            return mixed.reshape(token_count, height, width, n_slice).permute(0, 3, 1, 2)\n        return torch.bmm(operator, images.reshape(token_count, n_slice, height * width)).reshape(\n            token_count, n_slice, height, width\n        )\n\n\ndef d_segment_mean_max(values, study_index, batch_size):\n    dimension = values.shape[1]\n    counts = torch.zeros(\n        batch_size, device=values.device, dtype=values.dtype\n    ).index_add_(\n        0, study_index,\n        torch.ones(values.shape[0], device=values.device, dtype=values.dtype),\n    )\n    mean = torch.zeros(\n        batch_size, dimension, device=values.device, dtype=values.dtype\n    ).index_add_(0, study_index, values)\n    mean = mean / counts.clamp(min=1).unsqueeze(1)\n    maximum = torch.full(\n        (batch_size, dimension), -10000.0, device=values.device, dtype=values.dtype\n    )\n    maximum = maximum.scatter_reduce(\n        0, study_index.unsqueeze(1).expand(-1, dimension), values,\n        reduce=\"amax\", include_self=True,\n    )\n    return torch.cat([mean, maximum], 1)\n\n\ndef d_pad_keys(values, study_index, batch_size, norm):\n    token_groups, patches, dimension = values.shape\n    counts = torch.bincount(study_index, minlength=batch_size)\n    max_series = int(counts.max().item())\n    starts = torch.cumsum(counts, 0) - counts\n    positions = torch.arange(token_groups, device=values.device) - starts[study_index]\n    padded = values.new_zeros(batch_size, max_series, patches, dimension)\n    padded[study_index, positions] = values\n    keep = torch.zeros(batch_size, max_series, dtype=torch.bool, device=values.device)\n    keep[study_index, positions] = True\n    return (\n        norm(padded.reshape(batch_size, max_series * patches, dimension)),\n        ~keep.repeat_interleave(patches, dim=1),\n    )\n\n\nclass D_GatedDelta(nn.Module):\n    def __init__(self, dimension, n_labels, n_heads, dropout):\n        super().__init__()\n        self.q = nn.Parameter(torch.randn(n_labels, dimension) * 0.02)\n        self.kv_norm = nn.LayerNorm(dimension)\n        self.attn = nn.MultiheadAttention(\n            dimension, n_heads, dropout=dropout, batch_first=True\n        )\n        self.d_norm = nn.LayerNorm(dimension)\n        self.dw = nn.Parameter(\n            torch.randn(n_labels, dimension) * (1.0 / dimension ** 0.5)\n        )\n        self.db = nn.Parameter(torch.zeros(n_labels))\n        self.gate = nn.Parameter(torch.zeros(n_labels))\n\n    def delta(self, patches, study_index, batch_size, return_attn):\n        keys, padding_mask = d_pad_keys(patches, study_index, batch_size, self.kv_norm)\n        queries = self.q.unsqueeze(0).expand(batch_size, -1, -1)\n        attended, weights = self.attn(\n            queries, keys, keys, key_padding_mask=padding_mask,\n            need_weights=return_attn, average_attn_weights=True,\n        )\n        logits = (self.d_norm(attended) * self.dw).sum(-1) + self.db\n        return logits, weights\n\n\nclass DTokenResidualPool(D_GatedDelta):\n    def __init__(self, dimension, n_labels=12, n_heads=6, pe=64, dropout=0.2):\n        super().__init__(dimension, n_labels, n_heads, dropout)\n        self.base = nn.Sequential(\n            nn.LayerNorm(2 * dimension + pe), nn.Dropout(dropout),\n            nn.Linear(2 * dimension + pe, n_labels),\n        )\n\n    def forward(self, tokens, slot, study_index, batch_size, presence, return_attn=False):\n        base = self.base(torch.cat([\n            d_segment_mean_max(tokens[:, 1:].mean(1), study_index, batch_size),\n            presence,\n        ], 1))\n        delta, weights = self.delta(tokens[:, 1:], study_index, batch_size, return_attn)\n        return base + self.gate * delta, weights\n\n\nclass DCodexResidualPool(D_GatedDelta):\n    def __init__(self, dimension, n_labels=12, n_heads=6, pe=64, dropout=0.2):\n        super().__init__(dimension, n_labels, n_heads, dropout)\n        self.base = nn.Sequential(\n            nn.LayerNorm(2 * dimension + pe), nn.Dropout(dropout),\n            nn.Linear(2 * dimension + pe, n_labels),\n        )\n\n    def forward(self, tokens, slot, study_index, batch_size, presence, return_attn=False):\n        base = self.base(torch.cat([\n            d_segment_mean_max(tokens[:, 0], study_index, batch_size), presence,\n        ], 1))\n        delta, weights = self.delta(tokens[:, 1:], study_index, batch_size, return_attn)\n        return base + self.gate * delta, weights\n\n\nclass DClsAddPool(nn.Module):\n    def __init__(self, dimension, n_labels=12, pe=64, dropout=0.2):\n        super().__init__()\n        self.net = nn.Sequential(\n            nn.LayerNorm(4 * dimension + pe), nn.Dropout(dropout),\n            nn.Linear(4 * dimension + pe, n_labels),\n        )\n\n    def forward(self, tokens, slot, study_index, batch_size, presence, return_attn=False):\n        combined = torch.cat([\n            d_segment_mean_max(tokens[:, 1:].mean(1), study_index, batch_size),\n            d_segment_mean_max(tokens[:, 0], study_index, batch_size),\n            presence,\n        ], 1)\n        return self.net(combined), None\n\n\nclass DReadout(nn.Module):\n    def __init__(self, pool, dimension, n_labels=12, pe=64):\n        super().__init__()\n        self.pool_kind, self.k = pool, n_labels\n        self.pres_emb = nn.Embedding(D_N_SLOT_TYPES + 1, pe, padding_idx=0)\n        if pool in (\"xres\", \"clsadd\", \"xcodex\"):\n            pool_class = {\n                \"xres\": DTokenResidualPool,\n                \"clsadd\": DClsAddPool,\n                \"xcodex\": DCodexResidualPool,\n            }[pool]\n            self.pool = pool_class(dimension, n_labels, pe=pe)\n        elif pool in (\"attn\", \"xattn\"):\n            if pool == \"xattn\":\n                self.pool = DTokenXAttnPool(dimension, n_labels)\n                weight_dimension = 3 * dimension + pe\n            else:\n                self.pool = DLabelAttentionPool(dimension, n_labels)\n                weight_dimension = dimension + pe\n            self.norm = nn.LayerNorm(weight_dimension)\n            self.w = nn.Parameter(\n                torch.randn(n_labels, weight_dimension) * (1.0 / weight_dimension ** 0.5)\n            )\n            self.b = nn.Parameter(torch.zeros(n_labels))\n        else:\n            self.pool = DMeanMaxPool()\n            self.net = nn.Sequential(\n                nn.LayerNorm(2 * dimension + pe), nn.Dropout(0.2),\n                nn.Linear(2 * dimension + pe, n_labels),\n            )\n        self.drop = nn.Dropout(0.2)\n\n    def forward(self, features, slot, study_index, batch_size, return_attn=False):\n        embedded = self.pres_emb(slot)\n        presence = torch.zeros(\n            batch_size, embedded.shape[1], device=features.device, dtype=features.dtype\n        ).index_add_(0, study_index, embedded)\n        if self.pool_kind in (\"xres\", \"clsadd\", \"xcodex\"):\n            return self.pool(features, slot, study_index, batch_size, presence)[0]\n        pooled, attention = self.pool(\n            features, study_index, batch_size, slot=slot, return_attn=return_attn\n        )\n        if self.pool_kind in (\"attn\", \"xattn\"):\n            combined = torch.cat([\n                pooled, presence.unsqueeze(1).expand(-1, self.k, -1)\n            ], -1)\n            combined = self.drop(self.norm(combined))\n            return (combined * self.w).sum(-1) + self.b\n        return self.net(torch.cat([pooled, presence], 1))\n\n\nclass DNet(nn.Module):\n    def __init__(self, enc, cond, n_meta=0, pool=\"mean_max\", stem=\"native\", n_slice=16):\n        super().__init__()\n        self.enc, self.cond = enc, cond\n        self.compress = DDepthCompress(n_slice, 3) if stem == \"compress\" else None\n        self.mixer = DSlotDepthMixer(n_slice) if stem == \"mixer\" else None\n        self.tokens = pool in (\"xattn\", \"xres\", \"clsadd\", \"xcodex\")\n        dimension = enc.num_features\n        self.meta_mlp = (\n            nn.Sequential(\n                nn.LayerNorm(n_meta), nn.Linear(n_meta, 128), nn.GELU(),\n                nn.Linear(128, dimension),\n            ) if n_meta > 0 else None\n        )\n        self.readout = DReadout(pool, dimension)\n        if cond == \"post\":\n            self.slot_emb = nn.Embedding(\n                D_N_SLOT_TYPES + 1, dimension, padding_idx=D_MASK_IDX\n            )\n\n    def forward(self, images, slot, series_meta, study_index, batch_size, vm=None):\n        if self.mixer is not None:\n            images = self.mixer(images, slot, vm)\n        if self.compress is not None:\n            images = self.compress(images)\n        features = (\n            self.enc.forward_features(images, slot)\n            if self.cond == \"token\" else self.enc.forward_features(images)\n        )\n        if self.tokens:\n            inner = getattr(self.enc, \"vit\", self.enc)\n            original = getattr(\n                self.enc, \"_orig_prefix\", getattr(inner, \"num_prefix_tokens\", 1)\n            )\n            features = torch.cat([features[:, :1], features[:, original:]], 1)\n        else:\n            features = self.enc.forward_head(features, pre_logits=True)\n            if features.dim() > 2:\n                features = features.flatten(1)\n        expand = (lambda value: value.unsqueeze(1)) if self.tokens else (lambda value: value)\n        if self.cond == \"post\":\n            features = features + expand(self.slot_emb(slot))\n        if self.meta_mlp is not None and series_meta.shape[1] > 0:\n            meta = self.meta_mlp(series_meta)\n            features = (\n                torch.cat([features, meta.unsqueeze(1)], 1)\n                if self.tokens else features + meta\n            )\n        return self.readout(features, slot, study_index, batch_size)\n\n\ndef d_checkpoint_paths(directory):\n    paths = [directory / f\"m_f{fold}.pt\" for fold in range(5)]\n    missing = [path.name for path in paths if not path.is_file()]\n    if missing:\n        raise FileNotFoundError(f\"Missing DINOv3 fold checkpoints: {missing}\")\n    return paths\n\n\ndef d_config_signature(config):\n    keys = (\"backbone\", \"img\", \"cond\", \"pool\", \"stem\", \"n_slice\", \"n_meta\", \"norm\")\n    return {key: config.get(key) for key in keys}\n\n\ndef d_load_models(directory):\n    checkpoint_paths = d_checkpoint_paths(directory)\n    device_names = [f\"cuda:{index}\" for index in range(min(2, torch.cuda.device_count()))]\n    if not device_names:\n        raise RuntimeError(\"DINOv3 requires a CUDA GPU.\")\n    records, reference_signature, reference_config = [], None, None\n    seen_folds = set()\n    for checkpoint_index, checkpoint_path in enumerate(checkpoint_paths):\n        payload = torch.load(checkpoint_path, map_location=\"cpu\", weights_only=False)\n        config = payload[\"cfg\"]\n        signature = d_config_signature(config)\n        if reference_signature is None:\n            reference_signature, reference_config = signature, dict(config)\n        elif signature != reference_signature:\n            raise ValueError(\n                f\"DINO fold config mismatch in {checkpoint_path.name}: {signature}\"\n            )\n        if config.get(\"n_meta\", 0) != 0:\n            raise ValueError(\"These DINO checkpoints unexpectedly require metadata features.\")\n        if int(config.get(\"img\", D_SIZE)) != D_SIZE:\n            raise ValueError(f\"Unexpected DINO image size: {config.get('img')}\")\n        if int(config.get(\"n_slice\", D_N_SLICE)) != D_N_SLICE:\n            raise ValueError(f\"Unexpected DINO slice count: {config.get('n_slice')}\")\n        backbone_name = str(config[\"backbone\"])\n        if \"dinov3\" not in backbone_name or \"vit_small_patch16\" not in backbone_name:\n            raise ValueError(f\"Unexpected independent backbone: {backbone_name}\")\n        stem = config.get(\"stem\", \"native\")\n        input_channels = 3 if stem == \"compress\" else int(config.get(\"n_slice\", D_N_SLICE))\n        options = {\"img_size\": config[\"img\"]} if \"vit_\" in backbone_name else {}\n        encoder = timm.create_model(\n            backbone_name, pretrained=False, num_classes=0,\n            in_chans=input_channels, **options,\n        )\n        if config[\"cond\"] == \"token\":\n            encoder = DViTSlotToken(encoder, D_N_SLOT_TYPES)\n        model = DNet(\n            encoder, config[\"cond\"], config.get(\"n_meta\", 0), config[\"pool\"],\n            stem=stem, n_slice=config.get(\"n_slice\", D_N_SLICE),\n        )\n        # Verified against the published checkpoint and its bundled timm 1.0.22:\n        # all 180 keys match. Any drift discards the optional arm globally.\n        model.load_state_dict(payload[\"state_dict\"], strict=True)\n        checkpoint_labels = config.get(\n            \"labels\",\n            payload.get(\"labels\", payload.get(\"targets\", payload.get(\"lab\"))),\n        )\n        if checkpoint_labels is not None and list(checkpoint_labels) != LABELS:\n            raise ValueError(\n                f\"DINO target order mismatch in {checkpoint_path.name}\"\n            )\n        fold = int(payload[\"fold\"])\n        if fold in seen_folds:\n            raise ValueError(f\"Duplicate DINO fold id {fold}\")\n        seen_folds.add(fold)\n        device = device_names[checkpoint_index % len(device_names)]\n        model = model.eval().to(device)\n        records.append({\n            \"fold\": fold,\n            \"path\": checkpoint_path,\n            \"model\": model,\n            \"device\": device,\n            \"strict_state_dict\": True,\n        })\n        print(\n            f\"Loaded {checkpoint_path.name}: fold={fold}, device={device}, \"\n            f\"backbone={backbone_name}, pool={config['pool']}, stem={stem}\"\n        )\n        del payload\n        gc.collect()\n    if seen_folds != set(range(5)):\n        raise ValueError(f\"Expected folds 0–4, found {sorted(seen_folds)}\")\n    records.sort(key=lambda record: record[\"fold\"])\n    return records, reference_config\n\n\ndef d_normalize(images, config):\n    method = config.get(\"norm\", \"none\")\n    if method == \"zscore\":\n        mask = (images > 0).float()\n        count = mask.sum(dim=(1, 2, 3), keepdim=True).clamp(min=1.0)\n        mean = (images * mask).sum(dim=(1, 2, 3), keepdim=True) / count\n        variance = (((images - mean) * mask) ** 2).sum(\n            dim=(1, 2, 3), keepdim=True\n        ) / count\n        return (images - mean) / (variance.sqrt() + 1e-6) * mask\n    if method == \"imagenet\":\n        mask = (images > 0).float()\n        return (images - 0.485) / 0.229 * mask\n    return images\n\n\ndef d_amp_dtype(device):\n    capability = torch.cuda.get_device_capability(device)\n    return torch.bfloat16 if capability >= (8, 0) else torch.float16\n\n\n@torch.inference_mode()\ndef d_predict_device(images, masks, model_records, config):\n    device = model_records[0][\"device\"]\n    torch.cuda.set_device(torch.device(device))\n    tensors, slots, study_indices, valid_masks = [], [], [], []\n    for batch_index in range(len(masks)):\n        present = np.nonzero(masks[batch_index] > 0)[0]\n        if len(present) == 0:\n            continue\n        block = images[batch_index][present]\n        tensors.append(torch.from_numpy(block))\n        valid_masks.append(\n            torch.from_numpy(block.reshape(block.shape[0], block.shape[1], -1).max(2) > 0)\n        )\n        slots.append(torch.from_numpy(present + 1).long())\n        study_indices.append(torch.full((len(present),), batch_index, dtype=torch.long))\n    output = np.full(\n        (len(model_records), len(masks), len(LABELS)), np.nan, dtype=np.float32\n    )\n    if not tensors:\n        return [record[\"fold\"] for record in model_records], output\n    tensor = d_normalize(\n        torch.cat(tensors).to(device, non_blocking=True).float().div_(255.0), config\n    )\n    slot = torch.cat(slots).to(device, non_blocking=True)\n    study_index = torch.cat(study_indices).to(device, non_blocking=True)\n    valid_mask = torch.cat(valid_masks).to(device, non_blocking=True)\n    series_meta = torch.zeros(\n        len(slot), config.get(\"n_meta\", 0), device=device, dtype=torch.float32\n    )\n    keep = np.array([(mask > 0).any() for mask in masks], dtype=bool)\n    amp_dtype = d_amp_dtype(device)\n    with torch.autocast(\"cuda\", dtype=amp_dtype):\n        for local_index, record in enumerate(model_records):\n            prediction = torch.sigmoid(\n                record[\"model\"](\n                    tensor, slot, series_meta, study_index, len(masks), vm=valid_mask\n                ).float()\n            ).cpu().numpy()\n            output[local_index, keep] = prediction[keep]\n    return [record[\"fold\"] for record in model_records], output\n\n\ndef d_predict(images, masks, model_records, config, micro_batch=4):\n    fold_count = len(model_records)\n    output = np.full(\n        (fold_count, len(masks), len(LABELS)), np.nan, dtype=np.float32\n    )\n    device_groups = {}\n    for record in model_records:\n        device_groups.setdefault(record[\"device\"], []).append(record)\n    groups = list(device_groups.values())\n    executor = ThreadPoolExecutor(max_workers=len(groups)) if len(groups) > 1 else None\n    try:\n        for start in range(0, len(masks), micro_batch):\n            stop = min(start + micro_batch, len(masks))\n            if executor is None:\n                results = [d_predict_device(\n                    images[start:stop], masks[start:stop], groups[0], config\n                )]\n            else:\n                futures = [\n                    executor.submit(\n                        d_predict_device,\n                        images[start:stop], masks[start:stop], group, config,\n                    )\n                    for group in groups\n                ]\n                results = [future.result() for future in futures]\n            for fold_ids, predictions in results:\n                for local_index, fold in enumerate(fold_ids):\n                    output[fold, start:stop] = predictions[local_index]\n    finally:\n        if executor is not None:\n            executor.shutdown(wait=True)\n    return output\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-26T14:31:09.425715Z","iopub.execute_input":"2026-08-26T14:31:09.4264Z","iopub.status.idle":"2026-08-26T14:31:09.509534Z","shell.execute_reply.started":"2026-08-26T14:31:09.426377Z","shell.execute_reply":"2026-08-26T14:31:09.508699Z"}},"outputs":[],"execution_count":null},{"id":"0ebdc579","cell_type":"markdown","source":"## 6. Run the independent arm\n\nFive folds must load and the full study loop must finish before DINOv3 is eligible\nfor blending. On the hidden rerun, a runtime guard preserves the already-written\nMaxSpan submission rather than risking Kaggle's nine-hour cutoff.\n","metadata":{}},{"id":"7177257b","cell_type":"code","source":"D_WORKERS = max(1, min(4, os.cpu_count() or 4))\nD_CHUNK = 24\nD_MICRO = 4\nD_MIN_COVERAGE = 1.0\n\ndino_fold_raw = np.full(\n    (5, len(TEST_IDS), len(LABELS)), np.nan, dtype=np.float32\n)\ndino_probability_mean = np.full(\n    (len(TEST_IDS), len(LABELS)), np.nan, dtype=np.float64\n)\ndino_rank = np.full((len(TEST_IDS), len(LABELS)), np.nan, dtype=np.float64)\ndino_rank_ok = np.zeros((len(TEST_IDS), len(LABELS)), dtype=bool)\ndino_failures = []\ndino_model_records = []\ndino_config = None\ndino_completed = False\ndino_usable = False\ndino_skip_reason = None\ndino_started = None\n\nif DINO_CHECKPOINT_DIR is None:\n    dino_skip_reason = \"checkpoint dataset not attached\"\nelif time.time() - NOTEBOOK_START >= DINO_START_LATEST_SECONDS:\n    dino_skip_reason = \"runtime guard: MaxSpan finished too late to safely start DINOv3\"\nelse:\n    dino_started = time.time()\n    try:\n        dino_model_records, dino_config = d_load_models(DINO_CHECKPOINT_DIR)\n        processed = 0\n        with ProcessPoolExecutor(max_workers=D_WORKERS) as executor:\n            for chunk_start in range(0, len(TEST_IDS), D_CHUNK):\n                if time.time() - NOTEBOOK_START >= DINO_HARD_STOP_SECONDS:\n                    raise TimeoutError(\"runtime guard stopped DINOv3 before the full rerun\")\n                block_ids = TEST_IDS[chunk_start:chunk_start + D_CHUNK]\n                images = np.zeros(\n                    (len(block_ids), D_N_SLOT, D_N_SLICE, D_SIZE, D_SIZE), dtype=np.uint8\n                )\n                masks = np.zeros((len(block_ids), D_N_SLOT), dtype=np.uint8)\n                future_to_study = {\n                    executor.submit(\n                        d_build_study,\n                        (local_index, study_id, dino_series_by_study.get(study_id, [])),\n                    ): (local_index, study_id)\n                    for local_index, study_id in enumerate(block_ids)\n                }\n                for future in as_completed(future_to_study):\n                    local_index, study_id = future_to_study[future]\n                    try:\n                        result_index, study_images, study_mask = future.result()\n                        images[result_index], masks[result_index] = study_images, study_mask\n                        if int(study_mask.sum()) == 0:\n                            dino_failures.append({\n                                \"StudyInstanceUID\": study_id,\n                                \"model\": \"dinov3-preprocess\",\n                                \"error_type\": \"NoDecodedPixels\",\n                                \"message\": \"no nonzero DINOv3 slice decoded in any slot\",\n                            })\n                    except Exception as error:\n                        dino_failures.append({\n                            \"StudyInstanceUID\": study_id,\n                            \"model\": \"dinov3-preprocess\",\n                            \"error_type\": type(error).__name__,\n                            \"message\": str(error)[:400],\n                        })\n                dino_fold_raw[:, chunk_start:chunk_start + len(block_ids)] = d_predict(\n                    images, masks, dino_model_records, dino_config, D_MICRO\n                )\n                processed += len(block_ids)\n                elapsed = time.time() - dino_started\n                eta = elapsed / max(processed, 1) * (len(TEST_IDS) - processed)\n                print(\n                    f\"DINOv3 {processed}/{len(TEST_IDS)} | \"\n                    f\"elapsed={elapsed / 60:.1f}m, eta={eta / 60:.1f}m\",\n                    flush=True,\n                )\n                if (\n                    processed >= min(48, len(TEST_IDS))\n                    and time.time() + eta\n                    >= NOTEBOOK_START + DINO_HARD_STOP_SECONDS - 5 * 60\n                ):\n                    raise TimeoutError(\n                        \"projected DINOv3 finish would violate the runtime reserve\"\n                    )\n                del images, masks\n                gc.collect()\n        dino_completed = processed == len(TEST_IDS)\n    except Exception as error:\n        dino_skip_reason = f\"{type(error).__name__}: {error}\"\n        dino_failures.append({\n            \"StudyInstanceUID\": \"__run__\",\n            \"model\": \"dinov3\",\n            \"error_type\": type(error).__name__,\n            \"message\": str(error)[:400],\n        })\n        print(f\"DINOv3 discarded; keeping MaxSpan output — {dino_skip_reason}\")\n\nif dino_completed:\n    finite_count = np.isfinite(dino_fold_raw).sum(axis=0)\n    dino_probability_mean = np.divide(\n        np.nansum(dino_fold_raw, axis=0), finite_count,\n        out=np.full((len(TEST_IDS), len(LABELS)), np.nan, dtype=np.float64),\n        where=finite_count > 0,\n    )\n    dino_raw_frame = pd.DataFrame(dino_probability_mean, columns=LABELS)\n    dino_raw_frame.insert(0, \"StudyInstanceUID\", TEST_IDS)\n    atomic_write_csv(dino_raw_frame, DINO_RAW_PATH)\n\n    fold_ranks, fold_rank_masks = [], []\n    for fold in range(5):\n        fold_rank, fold_rank_ok = rank_available(\n            dino_fold_raw[fold], np.isfinite(dino_fold_raw[fold])\n        )\n        fold_ranks.append(fold_rank)\n        fold_rank_masks.append(fold_rank_ok)\n    fold_ranks = np.stack(fold_ranks)\n    fold_rank_masks = np.stack(fold_rank_masks)\n    complete_fold_cell = fold_rank_masks.all(axis=0)\n    fold_rank_mean = np.where(\n        complete_fold_cell,\n        np.where(fold_rank_masks, fold_ranks, 0.0).sum(axis=0) / 5.0,\n        np.nan,\n    )\n    dino_rank, dino_rank_ok = rank_available(fold_rank_mean, complete_fold_cell)\n    full_study = np.isfinite(dino_fold_raw).all(axis=(0, 2))\n    study_coverage = float(full_study.mean()) if len(full_study) else 0.0\n    usable_targets = int((dino_rank_ok.sum(axis=0) >= 2).sum())\n    # Eligibility is global: every fold, study, and target must be finite, and all\n    # twelve targets must have a nonconstant fold-ensemble ordering.\n    dino_usable = (\n        bool(np.isfinite(dino_fold_raw).all())\n        and study_coverage >= D_MIN_COVERAGE\n        and usable_targets == len(LABELS)\n    )\n    if not dino_usable:\n        dino_skip_reason = (\n            f\"quality gate failed: study coverage={study_coverage:.1%}, \"\n            f\"usable targets={usable_targets}/12\"\n        )\n        print(f\"DINOv3 discarded; keeping MaxSpan output — {dino_skip_reason}\")\n    else:\n        dino_submission = frame_from_rank(dino_rank, dino_rank_ok, TEST_IDS)\n        dino_submission = dino_submission[SAMPLE.columns]\n        validate_submission(dino_submission, TEST_IDS, SAMPLE.columns.tolist())\n        atomic_write_csv(dino_submission, DINO_SUBMISSION_PATH)\nelse:\n    study_coverage, usable_targets = 0.0, 0\n\nfor record in dino_model_records:\n    record[\"model\"] = None\ngc.collect()\ntorch.cuda.empty_cache()\ndino_seconds = time.time() - dino_started if dino_started is not None else 0.0\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-26T14:31:09.510701Z","iopub.execute_input":"2026-08-26T14:31:09.511452Z","iopub.status.idle":"2026-08-26T14:31:18.944147Z","shell.execute_reply.started":"2026-08-26T14:31:09.511411Z","shell.execute_reply":"2026-08-26T14:31:18.943511Z"}},"outputs":[],"execution_count":null},{"id":"dc847b4b","cell_type":"markdown","source":"## 7. Fixed rank blend and audit trail\n\nRaptor receives 90% and DINOv3 10% for every target. This was declared before\nseeing a Notebook 3 score. If one model is unavailable for a study/target, the\nother is used unchanged; if both are unavailable, the neutral value is `0.5`.\nThe blended ordering is re-ranked once to preserve ties cleanly.\n","metadata":{}},{"id":"5a0d89fb","cell_type":"code","source":"final_mode = R_RECIPE\nblend_rank = raptor_rank.copy()\nblend_rank_ok = raptor_rank_ok.copy()\n\nif dino_usable:\n    both = raptor_rank_ok & dino_rank_ok\n    raptor_only = raptor_rank_ok & ~dino_rank_ok\n    dino_only = dino_rank_ok & ~raptor_rank_ok\n    blend_pre_rank = np.full(raptor_rank.shape, np.nan, dtype=np.float64)\n    blend_pre_rank[both] = (\n        RAPTOR_BLEND_WEIGHT * raptor_rank[both]\n        + DINO_BLEND_WEIGHT * dino_rank[both]\n    )\n    blend_pre_rank[raptor_only] = raptor_rank[raptor_only]\n    blend_pre_rank[dino_only] = dino_rank[dino_only]\n    blend_availability = both | raptor_only | dino_only\n    blend_rank, blend_rank_ok = rank_available(blend_pre_rank, blend_availability)\n    blend_submission = frame_from_rank(blend_rank, blend_rank_ok, TEST_IDS)\n    blend_submission = blend_submission[SAMPLE.columns]\n    validate_submission(blend_submission, TEST_IDS, SAMPLE.columns.tolist())\n    atomic_write_csv(blend_submission, WORK / \"submission_blend_90_10.csv\")\n    atomic_write_csv(blend_submission, OUTPUT_PATH)\n    final_mode = f\"{R_RECIPE}_dinov3_rank_blend_90_10\"\n\ndiagnostic_rows = []\nfor target_index, label in enumerate(LABELS):\n    paired = raptor_rank_ok[:, target_index] & dino_rank_ok[:, target_index]\n    raptor_only_cells = raptor_rank_ok[:, target_index] & ~dino_rank_ok[:, target_index]\n    dino_only_cells = dino_rank_ok[:, target_index] & ~raptor_rank_ok[:, target_index]\n    correlation = np.nan\n    mean_absolute_rank_difference = np.nan\n    if paired.sum() >= 3:\n        left = raptor_rank[paired, target_index]\n        right = dino_rank[paired, target_index]\n        mean_absolute_rank_difference = float(np.mean(np.abs(left - right)))\n        if np.ptp(left) > 0 and np.ptp(right) > 0:\n            correlation = float(spearmanr(left, right).statistic)\n    raptor_values = raptor_raw[np.isfinite(raptor_raw[:, target_index]), target_index]\n    dino_values = dino_probability_mean[\n        np.isfinite(dino_probability_mean[:, target_index]), target_index\n    ]\n    diagnostic_rows.append({\n        \"target\": label,\n        \"raptor_available\": int(raptor_rank_ok[:, target_index].sum()),\n        \"dinov3_available\": int(dino_rank_ok[:, target_index].sum()),\n        \"paired\": int(paired.sum()),\n        \"raptor_only_cells\": int(raptor_only_cells.sum()),\n        \"dinov3_only_cells\": int(dino_only_cells.sum()),\n        \"spearman_rank_correlation\": correlation,\n        \"mean_absolute_rank_difference\": mean_absolute_rank_difference,\n        \"raptor_raw_std\": float(np.std(raptor_values)) if len(raptor_values) else np.nan,\n        \"dinov3_raw_std\": float(np.std(dino_values)) if len(dino_values) else np.nan,\n        \"raptor_raw_unique\": int(np.unique(raptor_values).size),\n        \"dinov3_raw_unique\": int(np.unique(dino_values).size),\n        \"raptor_weight_when_paired\": RAPTOR_BLEND_WEIGHT,\n        \"dinov3_weight_when_paired\": DINO_BLEND_WEIGHT,\n        \"final_available\": int(blend_rank_ok[:, target_index].sum()),\n    })\ndiagnostics = pd.DataFrame(diagnostic_rows)\noptional_write_csv(diagnostics, DIAGNOSTIC_PATH)\n\nfailure_columns = [\"StudyInstanceUID\", \"model\", \"error_type\", \"message\"]\nfailures = pd.DataFrame(\n    raptor_failures + dino_failures, columns=failure_columns\n)\noptional_write_csv(failures, FAILURE_PATH)\n\nmanifest = {\n    \"final_mode\": final_mode,\n    \"final_submission\": str(OUTPUT_PATH),\n    \"weights_predeclared\": True,\n    \"raptor_weight\": RAPTOR_BLEND_WEIGHT,\n    \"dinov3_weight\": DINO_BLEND_WEIGHT,\n    \"raptor_recipe\": R_RECIPE,\n    \"raptor_checkpoint\": RAPTOR_WEIGHT_PATH.name,\n    \"raptor_checkpoint_bytes\": RAPTOR_WEIGHT_PATH.stat().st_size,\n    \"raptor_checkpoint_sha256\": safe_sha256_file(RAPTOR_WEIGHT_PATH),\n    \"final_submission_sha256\": safe_sha256_file(OUTPUT_PATH),\n    \"dinov3_checkpoint_files\": [\n        {\n            \"name\": record[\"path\"].name,\n            \"bytes\": record[\"path\"].stat().st_size,\n            \"fold\": record[\"fold\"],\n            \"device\": record[\"device\"],\n            \"sha256\": safe_sha256_file(record[\"path\"]),\n            \"strict_state_dict\": record[\"strict_state_dict\"],\n        }\n        for record in dino_model_records\n    ],\n    \"dinov3_config\": d_config_signature(dino_config) if dino_config else None,\n    \"dinov3_completed\": dino_completed,\n    \"dinov3_usable\": dino_usable,\n    \"dinov3_skip_reason\": dino_skip_reason,\n    \"dinov3_study_coverage\": study_coverage,\n    \"dinov3_usable_targets\": usable_targets,\n    \"test_studies\": len(TEST_IDS),\n    \"raptor_failed_studies\": len(raptor_failures),\n    \"dinov3_failures\": len(dino_failures),\n    \"raptor_seconds\": round(raptor_seconds, 1),\n    \"dinov3_seconds\": round(dino_seconds, 1),\n    \"total_seconds\": round(time.time() - NOTEBOOK_START, 1),\n    \"gpu_count\": torch.cuda.device_count(),\n    \"torch\": torch.__version__,\n    \"timm\": timm.__version__,\n}\noptional_write_json(manifest, MANIFEST_PATH)\n\nfinal_submission = pd.read_csv(OUTPUT_PATH, dtype={\"StudyInstanceUID\": \"string\"})\nvalidate_submission(final_submission, TEST_IDS, SAMPLE.columns.tolist())\nprint(\"\\nNotebook 3 complete\")\nprint({\n    \"final_mode\": final_mode,\n    \"submission\": str(OUTPUT_PATH),\n    \"raptor_backup\": str(RAPTOR_SUBMISSION_PATH),\n    \"dinov3_standalone\": str(DINO_SUBMISSION_PATH) if DINO_SUBMISSION_PATH.exists() else None,\n    \"diagnostics\": str(DIAGNOSTIC_PATH),\n    \"failures\": str(FAILURE_PATH),\n    \"manifest\": str(MANIFEST_PATH),\n    \"total_minutes\": round((time.time() - NOTEBOOK_START) / 60, 1),\n})\ndisplay(diagnostics)\ndisplay(final_submission.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-08-26T14:31:18.945077Z","iopub.execute_input":"2026-08-26T14:31:18.945392Z","iopub.status.idle":"2026-08-26T14:31:21.176318Z","shell.execute_reply.started":"2026-08-26T14:31:18.94535Z","shell.execute_reply":"2026-08-26T14:31:21.175618Z"}},"outputs":[],"execution_count":null},{"id":"185c105c","cell_type":"markdown","source":"## After the run\n\nIn the final printed dictionary, check `final_mode`:\n\n- `maxspan-v5_dinov3_rank_blend_90_10` means the fully validated ensemble became\n  `submission.csv`.\n- `maxspan-v5` means the independent arm was safely rejected and\n  `submission.csv` is the strong MaxSpan-only result.\n\nKeep `submission_raptor_maxspan.csv` as the single-model control. When asking for\nthe next iteration, share the final dictionary and `ensemble_diagnostics.csv`;\nthey tell us whether the independent arm was complete and genuinely diverse.\n","metadata":{}}]}