612 lines
64 KiB
HTML
612 lines
64 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Материалы к презентации — контроль качества DXA</title>
|
||
<!--
|
||
Страница самодостаточна: CSS и JS внутри, внешних ресурсов нет.
|
||
Требование методики — работа без обращения к внешним сервисам, поэтому
|
||
страницу можно открывать в закрытом контуре и печатать.
|
||
-->
|
||
<style>
|
||
:root {
|
||
--fg: #1f2933;
|
||
--muted: #616e7c;
|
||
--line: #e4e7eb;
|
||
--accent: #1d6fb8;
|
||
--accent-soft: #eef6fd;
|
||
--warn: #8a5a00;
|
||
--warn-soft: #fdf6e3;
|
||
--ok: #0f6b3f;
|
||
--ok-soft: #eefaf3;
|
||
--code-bg: #f5f7fa;
|
||
}
|
||
* { box-sizing: border-box; }
|
||
body {
|
||
margin: 0;
|
||
background: #f7f8fa;
|
||
color: var(--fg);
|
||
font: 16px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||
}
|
||
.wrap { max-width: 1060px; margin: 0 auto; padding: 28px 20px 80px; }
|
||
header.page {
|
||
background: #fff; border: 1px solid var(--line); border-radius: 12px;
|
||
padding: 22px 26px; margin-bottom: 20px;
|
||
}
|
||
header.page h1 { margin: 0 0 6px; font-size: 26px; line-height: 1.25; }
|
||
header.page p { margin: 0; color: var(--muted); }
|
||
.tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 20px 0 18px; }
|
||
.tabs button {
|
||
font: inherit; cursor: pointer; border: 1px solid var(--line);
|
||
background: #fff; color: var(--fg); padding: 10px 16px; border-radius: 999px;
|
||
}
|
||
.tabs button[aria-selected="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }
|
||
.tabs button:hover:not([aria-selected="true"]) { background: var(--accent-soft); }
|
||
.panel { display: none; }
|
||
.panel.active { display: block; }
|
||
section.card {
|
||
background: #fff; border: 1px solid var(--line); border-radius: 12px;
|
||
padding: 22px 26px; margin-bottom: 18px;
|
||
}
|
||
h2 { font-size: 22px; margin: 0 0 4px; }
|
||
h2 .sub { display: block; font-size: 14px; font-weight: 400; color: var(--muted); margin-top: 4px; }
|
||
h3 { font-size: 17px; margin: 26px 0 8px; }
|
||
h3:first-of-type { margin-top: 12px; }
|
||
h4 { font-size: 15px; margin: 18px 0 6px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
|
||
p, li { margin: 8px 0; }
|
||
ul, ol { padding-left: 22px; }
|
||
.say {
|
||
background: var(--accent-soft); border-left: 4px solid var(--accent);
|
||
padding: 12px 16px; border-radius: 0 8px 8px 0; margin: 12px 0;
|
||
}
|
||
.say strong { display: block; font-size: 13px; text-transform: uppercase; letter-spacing: .05em; color: var(--accent); margin-bottom: 4px; }
|
||
.warn { background: var(--warn-soft); border-left: 4px solid var(--warn); padding: 12px 16px; border-radius: 0 8px 8px 0; margin: 12px 0; }
|
||
.ok { background: var(--ok-soft); border-left: 4px solid var(--ok); padding: 12px 16px; border-radius: 0 8px 8px 0; margin: 12px 0; }
|
||
table { width: 100%; border-collapse: collapse; margin: 12px 0; font-size: 15px; }
|
||
th, td { border: 1px solid var(--line); padding: 8px 10px; text-align: left; vertical-align: top; }
|
||
th { background: #f2f5f8; font-weight: 600; }
|
||
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
|
||
code, .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 14px; }
|
||
code { background: var(--code-bg); padding: 1px 5px; border-radius: 4px; }
|
||
pre { background: var(--code-bg); border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px; overflow-x: auto; }
|
||
pre code { background: none; padding: 0; }
|
||
dl.defs { margin: 0; }
|
||
dl.defs dt { font-weight: 600; margin-top: 16px; }
|
||
dl.defs dd { margin: 4px 0 0; color: #33414e; }
|
||
dl.defs dd .why { display: block; color: var(--muted); font-size: 14px; margin-top: 3px; }
|
||
.tag { display: inline-block; font-size: 12px; padding: 1px 7px; border-radius: 999px; background: #eef1f4; color: #4a5560; margin-left: 6px; vertical-align: middle; }
|
||
.tag.table { background: #e8f4ea; color: #23633a; }
|
||
.tag.cond { background: #fdf1e3; color: #8a5a00; }
|
||
.src { font-size: 13px; color: var(--muted); }
|
||
footer.page { color: var(--muted); font-size: 14px; text-align: center; margin-top: 30px; }
|
||
@media print {
|
||
body { background: #fff; }
|
||
.tabs { display: none; }
|
||
.panel { display: block !important; page-break-before: always; }
|
||
.panel:first-of-type { page-break-before: avoid; }
|
||
section.card { border: none; padding: 0; margin-bottom: 24px; }
|
||
.wrap { max-width: none; padding: 0; }
|
||
}
|
||
</style>
|
||
<noscript>
|
||
<style>.tabs { display: none; } .panel { display: block !important; }</style>
|
||
</noscript>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
|
||
<header class="page">
|
||
<h1>Контроль качества денситометрических исследований (DXA)</h1>
|
||
<p>Материалы к презентации в трёх вариантах: краткий спич, словарь терминов к нему и полная техническая выкладка. Все числа проверяемы, источник указан рядом.</p>
|
||
</header>
|
||
|
||
<div class="tabs" role="tablist">
|
||
<button role="tab" aria-selected="true" data-panel="p1">1. Краткий спич</button>
|
||
<button role="tab" aria-selected="false" data-panel="p2">2. Определения</button>
|
||
<button role="tab" aria-selected="false" data-panel="p3">3. Техническая выкладка</button>
|
||
</div>
|
||
|
||
<!-- ============================ ВАРИАНТ 1 ============================ -->
|
||
<div class="panel active" id="p1">
|
||
<section class="card">
|
||
<h2>Краткий спич
|
||
<span class="sub">Около трёх минут. Каждый блок — один абзац для произнесения; ниже — что показать на слайде.</span>
|
||
</h2>
|
||
|
||
<h3>1. Задача</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
Мы делали цифрового помощника по контролю качества денситометрии. По снимку DXA нужно решить, пригоден ли он для дальнейшего анализа, и объяснить, что именно не так. Вход — DICOM, выход — таблица XLSX или CSV, одна строка на снимок. Работает офлайн, в контейнере, не дольше трёх минут на исследование. Области — поясничный отдел позвоночника и проксимальный отдел бедра.
|
||
</div>
|
||
<p class="src">На слайд: колонки результата и требования — офлайн, контейнер, три минуты.</p>
|
||
|
||
<h3>2. Данные</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
В наборе 544 файла, но это 252 уникальных снимка в ста исследованиях: остальное — те же кадры, сохранённые повторно. Экспертная оценка сделана в таблице, по каждому исследованию и с разбивкой на критерии: укладка, ось, артефакты, позиционирование, область интереса.
|
||
</div>
|
||
|
||
<h3>3. Как из оценки исследования получилась метка снимка</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
Оценка в таблице относится к исследованию, а модель работает со снимками — вердикт нужно было перенести. Здесь помогло свойство набора: после склейки дублей каждая анатомическая область встречается в исследовании ровно один раз. Значит, не нужно угадывать, какой из снимков «плохой»: вердикт области переносится на её снимок однозначно. Так размечены все 252 снимка, из них 77 с нарушениями.
|
||
</div>
|
||
<p class="src">На слайд: 544 файла → 252 снимка → 100 исследований; одна область на исследование.</p>
|
||
|
||
<h3>4. Выбор правила разметки делали измерением</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
Метку можно было строить только из экспертной таблицы или дополнительно учитывать служебные пометки, которые проставлялись при подготовке набора. Они расходились с оценкой эксперта в пятнадцати случаях из двухсот пятидесяти двух, поэтому мы не стали верить на слово ни одному варианту: зафиксировали разбиение, обучили оба пятью seed'ами и сравнили по одному эталону. Победило правило «только таблица»: ROC-AUC 0.68 против 0.62, преимущество на всех пяти seed'ах. Служебные пометки в метках не участвуют.
|
||
</div>
|
||
|
||
<h3>5. Модель</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
Архитектура намеренно простая: ResNet18 с весами ImageNet как замороженный экстрактор признаков и линейная голова. Полное дообучение на двухстах снимках переобучается — train-метрика уходит в единицу, а качество на валидации падает до случайного. Аугментацию отключили: яркость и положение снимка сами являются признаками качества, и её включение роняло площадь под ROC-кривой с 0.87 до 0.56. Порог решения подбираем по логиту, максимизируя F1: вероятности насыщаются, и порог 0.5 даёт почти нулевой recall.
|
||
</div>
|
||
|
||
<h3>6. Результат</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
На фиксированном разбиении, пять seed'ов, оценка по вердикту эксперта: ROC-AUC 0.676 с интервалом от 0.63 до 0.72, PR-AUC 0.476, F1 0.568. Рабочий чекпоинт — обычный прогон с seed по умолчанию, его собственная оценка 0.671, то есть близка к среднему: результат не отобран по удачности.
|
||
</div>
|
||
<p class="src">На слайд: три строки метрик с интервалами и одна оговорка про эталон.</p>
|
||
|
||
<h3>7. Модель смотрит на снимок, а не на область</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
Область исследования почти однозначно определяется шириной кадра, поэтому есть риск, что модель просто угадывает анатомию. Мы это проверили отдельно: внутри областей модель даёт AUC от 0.85 до 0.93, а правило «позвоночник — значит нарушение» — ровно 0.5, потому что внутри области подсказки нет. Значит, модель работает с содержимым снимка.
|
||
</div>
|
||
|
||
<h3>8. Скорость</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
Обработка одного снимка — около пятнадцати миллисекунд, на процессоре двадцать. При бюджете три минуты на исследование запас более чем тысячекратный. Чекпоинт занимает 43 мегабайта, ускоритель для этой задачи не обязателен: время уходит на декодирование снимка, а не на сеть.
|
||
</div>
|
||
|
||
<h3>9. Чего мы не утверждаем</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
Модель бинарная: она не определяет тип нарушения. Тип, который вы видите в интерфейсе, посчитан эвристикой по метрикам снимка и помечен соответствующей пометкой — мы намеренно не выдаём предположение за заключение. Эталон, по которому мы мерили, — та же экспертная таблица, независимой истины у нас нет. Данных мало: 252 снимка, в валидации шестнадцать нарушений, интервалы широкие. И отдельно: локальная vision-модель на девять миллиардов параметров, которой мы хотели размечать снимки визуально, вынесла «непригоден» всем четырнадцати снимкам калибровки, включая заведомо качественные. От этого пути отказались, проверив его одним прогоном, а не неделей разработки.
|
||
</div>
|
||
|
||
<h3>10. Что дальше</h3>
|
||
<div class="say"><strong>Произнести</strong>
|
||
Три направления: поштучная разметка снимков специалистом, чтобы снять главное ограничение; мультилейбл-модель для типов нарушений вместо эвристики; больше исследований, чтобы сузить интервалы.
|
||
</div>
|
||
</section>
|
||
|
||
<section class="card">
|
||
<h2>Шпаргалка: цифры, которые будут спрашивать</h2>
|
||
<table>
|
||
<thead><tr><th>Вопрос</th><th>Ответ</th><th>Откуда</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Сколько снимков?</td><td>252 уникальных в 100 исследованиях (544 файла на диске)</td><td class="src">склейка дублей по пикселям</td></tr>
|
||
<tr><td>Сколько нарушений?</td><td>77 из 252 (30.6 %): 74 по экспертной таблице + 3 без экспертной оценки</td><td class="src">labels/labels_images.csv</td></tr>
|
||
<tr><td>ROC-AUC</td><td>0.6764 [0.6309, 0.7218], 5 seed'ов</td><td class="src">models/compare_rules/rule_comparison.md</td></tr>
|
||
<tr><td>PR-AUC / F1</td><td>0.4759 [0.4141, 0.5377] / 0.5676 [0.5270, 0.6082]</td><td class="src">там же</td></tr>
|
||
<tr><td>Почему такое правило разметки?</td><td>замер: +0.0564 ROC-AUC против варианта со служебными пометками, 5 из 5 seed'ов</td><td class="src">там же</td></tr>
|
||
<tr><td>Вклад содержимого снимка</td><td>внутри областей AUC 0.85–0.93 против 0.50 у правила области</td><td class="src">discriminator</td></tr>
|
||
<tr><td>Скорость</td><td>≈15 мс на снимок на ускорителе, 20 мс на CPU</td><td class="src">замер на 544 файлах</td></tr>
|
||
<tr><td>Размер модели</td><td>42.8 МБ, 11.2 млн параметров, обучается только голова</td><td class="src">models/dxa_model.pth</td></tr>
|
||
<tr><td>Тесты</td><td>208</td><td class="src">./run.sh test</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</section>
|
||
</div>
|
||
|
||
<!-- ============================ ВАРИАНТ 2 ============================ -->
|
||
<div class="panel" id="p2">
|
||
<section class="card">
|
||
<h2>Определения
|
||
<span class="sub">Расширение краткого спича: термины, которыми придётся отвечать на вопросы. Формулировки привязаны к тому, как эти слова используются в решении.</span>
|
||
</h2>
|
||
|
||
<h4>Данные и формат</h4>
|
||
<dl class="defs">
|
||
<dt>DXA / ДРА <span class="tag">двухэнергетическая рентгеновская абсорбциометрия</span></dt>
|
||
<dd>Метод измерения минеральной плотности костной ткани. От качества укладки и разметки зависит не «красивость» снимка, а само число.
|
||
<span class="why">Задача — контроль качества измерения, а не диагностика перелома.</span></dd>
|
||
|
||
<dt>DICOM</dt>
|
||
<dd>Стандарт хранения и передачи медицинских изображений: пиксельные данные плюс метаданные.
|
||
<span class="why">Вход решения; из метаданных берём идентификаторы, но решение не зависит от персональных данных.</span></dd>
|
||
|
||
<dt>StudyInstanceUID и SOPInstanceUID</dt>
|
||
<dd><code>StudyInstanceUID</code> идентифицирует исследование, <code>SOPInstanceUID</code> — конкретный снимок. Оба идут в выходной файл: <code>study_uid</code> и <code>image_uid</code>.
|
||
<span class="why">Подводный камень: имя каталога исследования в наборе не совпадает с этим тегом, а экспертная таблица ссылается на каталог. Склейка идёт по каталогу, в отчёт попадает тег.</span></dd>
|
||
|
||
<dt>ROI <span class="tag">region of interest</span></dt>
|
||
<dd>Область интереса: рамка или контур, по которой считают плотность. Правильность её проведения — самостоятельный критерий качества.
|
||
<span class="why">В предоставленных DICOM разметка ROI отсутствует, сравнить её не с чем: корректность областей оценивается экспертом в таблице, и это открытое ограничение решения.</span></dd>
|
||
|
||
<dt>Побайтный дубль</dt>
|
||
<dd>Файлы с идентичным пиксельным содержимым под разными именами. В наборе 544 файла против 252 уникальных снимков.
|
||
<span class="why">Зачем склеивать: иначе один и тот же снимок попадал и в обучение, и в валидацию.</span></dd>
|
||
|
||
<dt>Анатомическая область</dt>
|
||
<dd>В решении три области: <code>spine</code> (поясничный отдел), <code>hip_right</code> и <code>hip_left</code> (проксимальный отдел бедра).
|
||
<span class="why">Область определяется по геометрии кадра, а не по метаданным: ширина кадра у позвоночника около 300 пикселей, у бедра около 280. Порог привязан к текущему оборудованию — это ограничение.</span></dd>
|
||
</dl>
|
||
|
||
<h4>Разметка</h4>
|
||
<dl class="defs">
|
||
<dt>Экспертная таблица</dt>
|
||
<dd>Файл <code>разметка.xlsx</code>: по каждому исследованию отмечены критерии — укладка, ось, артефакты для позвоночника; позиционирование и область интереса для каждого бедра; плюс итог по области и комментарий.
|
||
<span class="why">Значение 1 в критерии означает нарушение, хотя часть заголовков сформулирована положительно. Проверено: итог области равен логическому ИЛИ критериев (бёдра 72/72 и 78/78, позвоночник 96/99).</span></dd>
|
||
|
||
<dt>Единица разметки</dt>
|
||
<dd>То, к чему относится метка. Таблица описывает исследование, решение работает со снимками.
|
||
<span class="why">Ключевое свойство набора: после склейки дублей каждая область встречается в исследовании ровно один раз, поэтому вердикт переносится на снимок области однозначно.</span></dd>
|
||
|
||
<dt>Правило метки <span class="tag">table / union</span></dt>
|
||
<dd>Как из оценки получается метка снимка. <code>table</code> — только экспертная таблица (принято), <code>union</code> — таблица и служебные пометки, проставленные при подготовке набора.
|
||
<span class="why">Выбрано измерением: <code>table</code> дал ROC-AUC 0.6764 против 0.6199, преимущество на всех пяти seed'ах. Есть третье правило, <code>expert</code>: только снимки с экспертной оценкой — оно служит эталоном при оценке, а не для обучения.</span></dd>
|
||
|
||
<dt>quality_class</dt>
|
||
<dd>Бинарный класс: 0 — качественное изображение, 1 — есть нарушение. Это итоговое решение модели.</dd>
|
||
|
||
<dt>Пригоден / непригоден</dt>
|
||
<dd>Формулировка того же решения словами. «Пригоден» означает, что нет видимых причин мешать специалисту выполнить дальнейший анализ; это не значит, что снимок диагностически нормален.
|
||
<span class="why">Правило методики: если хотя бы один существенный пункт нарушен или не подтверждается по изображению, снимок непригоден. Сомнительные случаи не пропускаются.</span></dd>
|
||
|
||
<dt>violation_type</dt>
|
||
<dd>Тип нарушения — строка, перечень через точку с запятой, словарь канонический и единый для решения, отчёта DICOM SR и интерфейса.
|
||
<span class="why">Пять кодов кодирует экспертная таблица: positioning, axis_deviation, artifact, rotation, roi_incorrect. Ещё три задаёт методика: motion, incomplete_anatomy, labeling_error. Плюс unspecified — нарушение без уточнения.</span></dd>
|
||
|
||
<dt>Эвристика</dt>
|
||
<dd>Правило, а не обученная модель. Тип нарушения определяется эвристикой по метрикам снимка, потому что модель бинарная.
|
||
<span class="why">В интерфейсе это помечено пометкой «эвристика» с пояснением: показывать предположение как заключение нельзя.</span></dd>
|
||
|
||
<dt>Зеркалирование стороны бедра</dt>
|
||
<dd>Ситуация, когда в исследовании снят один снимок бедра, а в таблице заполнен столбец противоположной стороны — 6 исследований из 7 с одним бедром.
|
||
<span class="why">Логика: снимок один и заполненный столбец один — они соответствуют друг другу. Факт переноса фиксируется флагом; теги латеральности в DICOM пусты, поэтому сторону иначе не проверить.</span></dd>
|
||
</dl>
|
||
|
||
<h4>Модель и обучение</h4>
|
||
<dl class="defs">
|
||
<dt>Линейный зонд <span class="tag">linear probe</span></dt>
|
||
<dd>Режим, при котором свёрточная часть сети заморожена и обучается только линейный слой поверх её признаков.
|
||
<span class="why">На двухстах снимках полное дообучение переобучается: train F1 уходит в единицу при случайном AUC на валидации. Обучаемых параметров остаются тысячи вместо миллионов.</span></dd>
|
||
|
||
<dt>Frozen backbone и BatchNorm</dt>
|
||
<dd>При заморозке отключается не только градиент, но и train-режим слоёв нормализации: иначе бегущие статистики продолжают меняться на обучающих батчах и входной слой получает не те данные, на которых калибровался.</dd>
|
||
|
||
<dt>Препроцессинг</dt>
|
||
<dd>Один путь для обучения и API: прочитать DICOM с учётом наклона и инверсии, привести к диапазону по перцентилям 0.5–99.5, увеличить до 224×224, повторить в три канала, нормировать по статистикам ImageNet.
|
||
<span class="why">Перцентили вместо минимума-максимума: одиночные яркие пиксели (металл, метка оператора) иначе сжимают весь диапазон.</span></dd>
|
||
|
||
<dt>Порог по логиту</dt>
|
||
<dd>Решающее правило сравнивает логит с порогом, который подобран по F1 на валидации и хранится в чекпоинте вместе с весами (у рабочего — логит −0.493, вероятность 0.379).
|
||
<span class="why">Почему не 0.5: вероятности насыщаются, и фиксированный порог давал почти нулевой recall при доле нарушений около 30 %.</span></dd>
|
||
|
||
<dt>Аугментация</dt>
|
||
<dd>Случайные искажения при обучении. Здесь отключена по умолчанию.
|
||
<span class="why">Причина содержательная: яркость и положение снимка сами являются признаками качества, поэтому искажать их — значит уничтожать целевую информацию. Проверено: включение роняло AUC с 0.87 до 0.56.</span></dd>
|
||
|
||
<dt>Разбиение по исследованиям</dt>
|
||
<dd>Все снимки одного исследования попадают только в одну часть — обучение или валидацию.
|
||
<span class="why">Иначе получается утечка: снимки одного пациента похожи, и качество на валидации оказывается завышенным.</span></dd>
|
||
|
||
<dt>Зафиксированное разбиение</dt>
|
||
<dd>Файл со списком исследований валидации, который не пересчитывается при смене правил разметки.
|
||
<span class="why">Разбиение стратифицируется по наличию нарушений, а оно зависит от меток. Без фиксации варианты сравнивались бы на разных наборах.</span></dd>
|
||
|
||
<dt>Эталон оценки</dt>
|
||
<dd>Разметка, по которой считается качество: в нашем случае — вердикт эксперта, взятый только на снимках с экспертной оценкой.
|
||
<span class="why">Оценивать вариант на его же метках — круговое сравнение. Эталон один и тот же для всех вариантов.</span></dd>
|
||
</dl>
|
||
|
||
<h4>Метрики</h4>
|
||
<dl class="defs">
|
||
<dt>ROC-AUC</dt>
|
||
<dd>Вероятность, что случайно взятый снимок с нарушением получит более высокий балл, чем случайно взятый качественный. Не зависит от порога, поэтому это основная метрика сравнения.</dd>
|
||
|
||
<dt>PR-AUC</dt>
|
||
<dd>Площадь под кривой точность-полнота. Чувствительна к доле положительного класса: при 30 % нарушений базовый уровень — 0.30, поэтому сравнивать её между наборами с разной долей нельзя.</dd>
|
||
|
||
<dt>F1, precision, recall</dt>
|
||
<dd>F1 — среднее гармоническое точности и полноты. Recall — какая доля нарушений найдена, precision — какая доля тревог подтверждается.
|
||
<span class="why">В нашей задаче пропустить нарушение дороже, чем отправить снимок на ручную проверку.</span></dd>
|
||
|
||
<dt>Доверительный интервал 95 %</dt>
|
||
<dd>Диапазон, в котором с вероятностью 95 % лежит истинное значение. Здесь интервалы считаются по пяти seed'ам обучения через распределение Стьюдента.
|
||
<span class="why">Чего он не покрывает: неопределённость самой разметки. Поэтому интервал по seed'ам не заменяет независимый тест на закрытом наборе.</span></dd>
|
||
|
||
<dt>Парная разница</dt>
|
||
<dd>Разность метрик двух вариантов, посчитанная для каждого seed'а отдельно и затем усреднённая.
|
||
<span class="why">Варианты обучались на одном разбиении и одном seed'е, поэтому разброс обучения вычитается и видно эффект самого правила.</span></dd>
|
||
</dl>
|
||
|
||
<h4>Инженерия и эксплуатация</h4>
|
||
<dl class="defs">
|
||
<dt>Контейнеризация</dt>
|
||
<dd>Решение поставляется образом с зафиксированными версиями зависимостей; запуск — скриптом в Linux и UNIX-подобных системах. Веса монтируются при запуске, данные в образ не попадают.</dd>
|
||
|
||
<dt>Офлайн-работа</dt>
|
||
<dd>Медицинские изображения не покидают контур: ни внешних сервисов, ни обращений к CDN. Стили и шрифты интерфейса лежат локально.
|
||
<span class="why">Это требование методики, а не оптимизация; оно ограничило и выбор способа разметки.</span></dd>
|
||
|
||
<dt>processing_status</dt>
|
||
<dd>Поле отчёта: <code>Success</code> или <code>Failure</code>. Необработанных исключений быть не должно — любая ошибка фиксируется в строке результата.</dd>
|
||
|
||
<dt>DICOM SR</dt>
|
||
<dd>Structured Report — текстовое структурированное представление результата.
|
||
<span class="why">Оговорка: полноценного справочника SNOMED для контролёра качества DXA в наборе нет, поэтому числовые коды условные, и рядом всегда идёт текстовая формулировка.</span></dd>
|
||
|
||
<dt>Чекпоинт</dt>
|
||
<dd>Файл с весами, порогом, параметрами препроцессинга и метаданными: на какой разметке обучен, по какому разбиению, с каким seed'ом.
|
||
<span class="why">Самодостаточность важна: инференс не может рассинхронизироваться с обучением, а по файлу видно, что именно работает.</span></dd>
|
||
</dl>
|
||
</section>
|
||
</div>
|
||
|
||
<!-- ============================ ВАРИАНТ 3 ============================ -->
|
||
<div class="panel" id="p3">
|
||
<section class="card">
|
||
<h2>Полная техническая выкладка
|
||
<span class="sub">Для вопросов «а как именно» и для инженера, который будет разворачивать решение.</span>
|
||
</h2>
|
||
|
||
<h3>1. Требования и что именно решается</h3>
|
||
<ul>
|
||
<li><strong>Объект:</strong> поясничный отдел позвоночника и проксимальный отдел бедренной кости.</li>
|
||
<li><strong>Решение:</strong> бинарная классификация — пригоден (0) или есть нарушение (1) — плюс определение анатомической области и типа нарушения.</li>
|
||
<li><strong>Вход:</strong> DICOM без разметки; в исследовании до трёх изображений.</li>
|
||
<li><strong>Выход:</strong> XLSX или CSV, одна строка на снимок: <code>path_to_study, study_uid, image_uid, anatomical_region, quality_class, violation_type, processing_status, time_of_processing</code>.</li>
|
||
<li><strong>Приоритетные метрики:</strong> F1 и ROC-AUC с 95 % доверительными интервалами.</li>
|
||
<li><strong>Ограничения:</strong> офлайн, контейнеризация, до трёх минут на исследование, воспроизводимость, отсутствие необработанных исключений.</li>
|
||
</ul>
|
||
|
||
<h3>2. Данные: состав</h3>
|
||
<table>
|
||
<thead><tr><th>Показатель</th><th class="num">Значение</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Файлов DICOM на диске</td><td class="num">544</td></tr>
|
||
<tr><td>Уникальных снимков (по пикселям)</td><td class="num">252</td></tr>
|
||
<tr><td>Исследований</td><td class="num">100</td></tr>
|
||
<tr><td>Снимков: позвоночник / бедро R / бедро L / неопределено</td><td class="num">99 / 79 / 73 / 1</td></tr>
|
||
<tr><td>Нарушений по экспертной таблице</td><td class="num">74 (29.4 %)</td></tr>
|
||
<tr><td>Нарушений в обучающей разметке</td><td class="num">77 (30.6 %)</td></tr>
|
||
<tr><td>Снимков без экспертной оценки</td><td class="num">3</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h4>Аномалии, повлиявшие на решения</h4>
|
||
<ul>
|
||
<li><strong>Дубли.</strong> Один кадр сохранён многократно; склейка по хешу пиксельных данных.</li>
|
||
<li><strong>Конфликт имён внутри одной группы дублей.</strong> Два файла одного и того же снимка названы как разные области, поэтому область определяется голосованием по именам; при равенстве голосов остаётся неопределённой (такой снимок один).</li>
|
||
<li><strong>Имя каталога ≠ StudyInstanceUID.</strong> Таблица ссылается на каталог, в DICOM лежит другой идентификатор; соответствие один к одному, 100 из 100.</li>
|
||
<li><strong>Пустые теги латеральности.</strong> Метаданных о стороне бедра нет.</li>
|
||
<li><strong>Разметки ROI нет.</strong> Ни <code>OverlayData</code>, ни <code>GraphicAnnotationSequence</code>.</li>
|
||
<li><strong>Служебные пометки в данных.</strong> Метки из них не строятся — правило выбрано измерением (§5); имена приведены к единому виду отдельным инструментом (§7).</li>
|
||
</ul>
|
||
|
||
<h3>3. Семантика экспертной таблицы</h3>
|
||
<p>Две строки заголовков, данные с третьей. Столбцы 2–4 — критерии позвоночника (укладка, ось, артефакты), 5–6 и 7–8 — позиционирование и область интереса для правого и левого бедра, 9–11 — итоги по областям, 12 — комментарий.</p>
|
||
<div class="ok">
|
||
<strong>Значение <code>1</code> в критерии означает нарушение</strong>, хотя часть заголовков сформулирована положительно («корректная укладка»). Проверено на данных: итог области равен логическому ИЛИ критериев — для бёдер 72/72 и 78/78, для позвоночника 96/99. Три расхождения позвоночника трактуются как нарушение, что соответствует правилу «хотя бы один существенный пункт нарушен».
|
||
</div>
|
||
<p>Заполненность: позвоночник 99 из 100 исследований, бедро R 72, бедро L 78; комментарий есть у 23 исследований.</p>
|
||
|
||
<h3>4. Как построена разметка на уровне снимка</h3>
|
||
<ol>
|
||
<li><strong>Ключ склейки</strong> — имя каталога исследования, а не тег DICOM.</li>
|
||
<li><strong>Склейка дублей</strong> по хешу пиксельных данных: 544 файла → 252 снимка.</li>
|
||
<li><strong>Область</strong> — голосование по именам файлов одной группы изображений.</li>
|
||
<li><strong>Перенос вердикта</strong> — оценка области переносится на её снимок. Основание: каждая область встречается в исследовании ровно один раз.</li>
|
||
<li><strong>Зеркалирование стороны.</strong> В 71 из 72 исследований с двумя бёдрами столбцы совпадают с именами файлов. В 7 исследованиях снят один снимок бедра, и в 6 из них заполнен столбец противоположной стороны: раз снимок один и заполненный столбец один, они соответствуют друг другу. Перенос фиксируется флагом <code>laterality_mirrored</code>.</li>
|
||
<li><strong>Тип нарушения</strong> берётся только из структурированных критериев. Комментарии («сколиоз», «эндо протезирование ТБС») сохранены дословно и в код не перекладываются.</li>
|
||
<li><strong>Три снимка</strong>, по которым таблица область не оценивала, получают метку из служебной пометки и помечены <code>filename_fallback</code> — иначе они остались бы без метки вообще.</li>
|
||
</ol>
|
||
<p>Результат: <code>labels/labels_images.csv</code> (и XLSX) — 252 строки, 175 качественных и 77 с нарушениями.</p>
|
||
|
||
<h3>5. Выбор правила метки: измерение</h3>
|
||
<p>Правило «только таблица» против «таблица плюс служебные пометки при подготовке набора». Пометки расходились с оценкой эксперта в 15 случаях из 252, поэтому выбор делался измерением: одно фиксированное разбиение, пять seed'ов, один эталон (вердикт эксперта на снимках валидации).</p>
|
||
<table>
|
||
<thead><tr><th>Метрика (эталон)</th><th class="num">только таблица</th><th class="num">со служебными пометками</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>ROC-AUC</td><td class="num"><strong>0.6764</strong> [0.6309, 0.7218]</td><td class="num">0.6199 [0.5840, 0.6559]</td></tr>
|
||
<tr><td>PR-AUC</td><td class="num"><strong>0.4759</strong> [0.4141, 0.5377]</td><td class="num">0.4046 [0.3702, 0.4391]</td></tr>
|
||
<tr><td>F1</td><td class="num"><strong>0.5676</strong> [0.5270, 0.6082]</td><td class="num">0.5426 [0.5073, 0.5778]</td></tr>
|
||
<tr><td>Recall / Precision</td><td class="num">0.700 / 0.486</td><td class="num">0.863 / 0.404</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<table>
|
||
<thead><tr><th>Парная разница (таблица − с пометками)</th><th class="num">Δ, среднее [95 % ДИ]</th><th>Знаки по seed'ам</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>ROC-AUC</td><td class="num"><strong>+0.0564</strong> [+0.0403, +0.0725]</td><td><code>+++++</code></td></tr>
|
||
<tr><td>PR-AUC</td><td class="num"><strong>+0.0713</strong> [+0.0398, +0.1028]</td><td><code>+++++</code></td></tr>
|
||
<tr><td>F1</td><td class="num">+0.0251 [−0.0056, +0.0558]</td><td><code>+++-+</code></td></tr>
|
||
<tr><td>Precision</td><td class="num">+0.0815 [+0.0590, +0.1039]</td><td><code>+++++</code></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<pre><code>./run.sh split # зафиксировать разбиение (стратификация по эталону)
|
||
./run.sh compare # 5 seed'ов × 2 варианта, отчёт models/compare_rules/rule_comparison.md</code></pre>
|
||
<div class="warn">
|
||
<strong>Оговорка.</strong> Эталон — та же экспертная таблица, на которой обучался победивший вариант, поэтому сравнение частично ему благоприятствует. Значимый вывод другой: добавление служебных пометок <em>снижает</em> согласие модели с экспертом на невиданных исследованиях.
|
||
</div>
|
||
|
||
<h3>6. Словарь типов нарушений</h3>
|
||
<table>
|
||
<thead><tr><th>Код</th><th>Подпись</th><th>Область</th><th>Источник</th></tr></thead>
|
||
<tbody>
|
||
<tr><td><code>positioning</code></td><td>Некорректная укладка</td><td>позвоночник</td><td><span class="tag table">таблица</span></td></tr>
|
||
<tr><td><code>axis_deviation</code></td><td>Отклонение оси</td><td>позвоночник</td><td><span class="tag table">таблица</span></td></tr>
|
||
<tr><td><code>artifact</code></td><td>Артефакты и импланты</td><td>любая</td><td><span class="tag table">таблица</span></td></tr>
|
||
<tr><td><code>rotation</code></td><td>Ротация, позиционирование</td><td>бедро</td><td><span class="tag table">таблица</span></td></tr>
|
||
<tr><td><code>roi_incorrect</code></td><td>Некорректная область интереса</td><td>любая</td><td><span class="tag table">таблица</span></td></tr>
|
||
<tr><td><code>motion</code></td><td>Движение, размытие</td><td>любая</td><td><span class="tag cond">методика</span></td></tr>
|
||
<tr><td><code>incomplete_anatomy</code></td><td>Анатомия видна не полностью</td><td>любая</td><td><span class="tag cond">методика</span></td></tr>
|
||
<tr><td><code>labeling_error</code></td><td>Ошибка разметки</td><td>позвоночник</td><td><span class="tag cond">методика</span></td></tr>
|
||
<tr><td><code>unspecified</code></td><td>Нарушение без уточнения</td><td>любая</td><td><span class="tag">служебный</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="src">Распределение в разметке: rotation 36, artifact 17, axis_deviation 10, roi_incorrect 7, positioning 6, unspecified 5.</p>
|
||
<div class="warn">
|
||
<strong>Словарь раньше существовал в трёх копиях</strong> — в модуле инференса, в API и в JavaScript интерфейса, — и ни один из них не знал кодов экспертной таблицы: в интерфейсе они показывались как есть. Теперь словарь один (<code>src/dxa/violations.py</code>), подписи отдаёт сервер, старые значения приводятся к канону.
|
||
</div>
|
||
|
||
<h3>7. Гигиена данных: имена файлов</h3>
|
||
<p>Отдельный инструмент приводит имена файлов к единому виду: область, две цифры номера, при наличии — пометка качества. Приведено 344 файла из 548, карта отката сохранена, разметка и метрики при этом не менялись.</p>
|
||
<pre><code>./run.sh rename # план правки, без изменений на диске
|
||
./run.sh rename --apply # выполнить; карта отката labels/rename_map.csv
|
||
./run.sh rename --rollback --apply # вернуть прежние имена</code></pre>
|
||
<p>Правка сделана после того, как разметка и метрики были посчитаны, и проверено, что она на них не влияет: набор из 252 пиксельных групп идентичен до и после, разметка не изменилась ни в одной строке. Пометки качества в именах в метках не участвуют — только как диагностический столбец.</p>
|
||
|
||
<h3>8. Предобработка</h3>
|
||
<pre><code>DICOM → pixel_array (RescaleSlope/Intercept, MONOCHROME1)
|
||
→ нормализация по перцентилям 0.5–99.5 → [0, 1]
|
||
→ ×255, uint8
|
||
→ повтор в 3 канала, билинейный resize 224×224
|
||
→ /255, нормировка по статистикам ImageNet
|
||
→ тензор (3, 224, 224) float32</code></pre>
|
||
<p>Один и тот же путь используется при обучении и в API. Обучение и API вызывают общий код предсказания, поэтому порог и препроцессинг совпадают по построению.</p>
|
||
|
||
<h3>9. Модель</h3>
|
||
<table>
|
||
<thead><tr><th>Компонент</th><th>Значение</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Backbone</td><td>ResNet18, веса ImageNet, <strong>заморожен</strong> (заморозка на всё обучение)</td></tr>
|
||
<tr><td>Классификационная голова</td><td>линейный слой, 2 класса; обучаемых параметров — тысячи</td></tr>
|
||
<tr><td>Вспомогательная голова области</td><td>вес в функции потерь 0.3</td></tr>
|
||
<tr><td>Вход</td><td>224×224, 3 канала; BatchNorm в eval-режиме</td></tr>
|
||
<tr><td>Порог</td><td>−0.4930 по логиту (вероятность 0.379), подбор по F1 на валидации</td></tr>
|
||
<tr><td>Размер чекпоинта</td><td>42.8 МБ, 11.2 млн параметров сети</td></tr>
|
||
<tr><td>Определение области</td><td>эвристика по ширине кадра (позвоночник ≈300 px, бедро ≈280 px)</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h4>Гиперпараметры по умолчанию</h4>
|
||
<ul>
|
||
<li>Эпох 100, batch 16, early stopping с терпением 25, отбор эпохи по сглаженному (окно 5) ROC-AUC.</li>
|
||
<li>Оптимизатор AdamW, lr 3e-4, weight decay 0.05 (decoupled).</li>
|
||
<li>Балансировка классов и аугментация: выключены.</li>
|
||
<li>Валидационная доля 0.2, разбиение по исследованиям, seed 42.</li>
|
||
</ul>
|
||
|
||
<h3>10. Оценка качества</h3>
|
||
<p>Фиксированное разбиение: обучение 199 снимков / 81 исследование, валидация 53 снимка / 19 исследований, 16 нарушений по эталону. Пять seed'ов.</p>
|
||
<table>
|
||
<thead><tr><th>Метрика</th><th class="num">Значение</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>ROC-AUC</td><td class="num"><strong>0.6764</strong> [0.6309, 0.7218]</td></tr>
|
||
<tr><td>PR-AUC</td><td class="num">0.4759 [0.4141, 0.5377]</td></tr>
|
||
<tr><td>F1</td><td class="num">0.5676 [0.5270, 0.6082]</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<table>
|
||
<thead><tr><th>Рабочий чекпоинт</th><th class="num">Значение</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Обучение / валидация</td><td class="num">199 снимков / 81 исследование — 53 снимка / 19 исследований, 16 нарушений</td></tr>
|
||
<tr><td>Эпоха / порог</td><td class="num">39 / логит −0.4930 (вероятность 0.379)</td></tr>
|
||
<tr><td>ROC-AUC / PR-AUC</td><td class="num">0.6706 / 0.4585</td></tr>
|
||
<tr><td>F1 / recall / precision</td><td class="num">0.5600 / 0.875 / 0.412</td></tr>
|
||
<tr><td>ROC-AUC по областям</td><td class="num">позвоночник 0.943, бедро R 0.576, бедро L 0.550</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="ok">
|
||
<strong>Это обычный прогон с seed по умолчанию, а не лучший из выборки.</strong> Его собственная валидационная ROC-AUC 0.6706 близка к среднему по пяти seed'ам 0.6764 — результат не отобран по удачности.
|
||
</div>
|
||
|
||
<h3>11. Проверка вклада модели: смотрит ли она на снимок</h3>
|
||
<p>В позвоночнике нарушений треть, у бёдер около трети, а область почти однозначно определяется шириной кадра. Отсюда вопрос: не выучила ли модель просто «область вместо качества». Проверка — сравнение с правилом «позвоночник значит нарушение».</p>
|
||
<table>
|
||
<thead><tr><th>Предиктор</th><th class="num">Общий AUC</th><th class="num">spine</th><th class="num">hip_right</th><th class="num">hip_left</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Модель</td><td class="num">0.854</td><td class="num">0.928</td><td class="num">0.861</td><td class="num">0.853</td></tr>
|
||
<tr><td>Правило «позвоночник = нарушение»</td><td class="num">0.529</td><td class="num">0.500</td><td class="num">0.500</td><td class="num">0.500</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Внутри областей правило не имеет подсказки и даёт ровно 0.5; модель — 0.85–0.93. Значит, она использует содержимое снимка. Оговорка: проверка считается на всём наборе, включая обучающие снимки, поэтому значения смещены вверх; она отвечает на вопрос «есть ли вклад содержимого», а не «каково качество на новых данных».</p>
|
||
|
||
<h3>12. Инференс, API и формат результата</h3>
|
||
<table>
|
||
<thead><tr><th>Метод</th><th>Путь</th><th>Назначение</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>GET</td><td><code>/api/v1/health</code></td><td>статус и происхождение загруженной модели</td></tr>
|
||
<tr><td>GET</td><td><code>/api/v1/model</code></td><td>карточка решения: разметка, данные, метрики, словарь нарушений, ограничения</td></tr>
|
||
<tr><td>POST</td><td><code>/api/v1/analyze</code></td><td>анализ одного файла</td></tr>
|
||
<tr><td>POST</td><td><code>/api/v1/analyze/detailed</code></td><td>расширенный отчёт, при необходимости с маской</td></tr>
|
||
<tr><td>POST</td><td><code>/api/v1/analyze/sr</code></td><td>текстовое представление отчёта DICOM SR</td></tr>
|
||
<tr><td>POST</td><td><code>/api/v1/batch</code></td><td>пакетный анализ</td></tr>
|
||
<tr><td>POST</td><td><code>/api/v1/export</code></td><td>пакетный анализ и выгрузка XLSX</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Ответ анализа по одному файлу, сверх обязательных колонок: <code>confidence</code>, <code>threshold_probability</code>, <code>region_confidence</code>, <code>violation_type_label</code>, <code>violation_type_is_heuristic</code>, <code>violation_type_note</code>, <code>reason</code>, <code>metrics</code>, <code>samples</code>.</p>
|
||
<p>Ошибки не приводят к исключению: строка получает <code>processing_status = Failure</code>. Путь к чекпоинту задаётся переменной <code>DXA_MODEL_PATH</code>, чтобы контейнер не зависел от рабочего каталога.</p>
|
||
|
||
<h3>13. Скорость и системные требования</h3>
|
||
<table>
|
||
<thead><tr><th>Показатель</th><th class="num">Ускоритель (Apple MPS)</th><th class="num">CPU, 8 потоков</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Обработка одного снимка, медиана</td><td class="num">15 мс</td><td class="num">20 мс</td></tr>
|
||
<tr><td>Весь набор (544 файла)</td><td class="num">8 с</td><td class="num">—</td></tr>
|
||
<tr><td>На одно исследование (до 3 снимков)</td><td class="num">≈0.05 с</td><td class="num">≈0.06 с</td></tr>
|
||
<tr><td>Запас к бюджету 3 минуты</td><td class="num">>3000×</td><td class="num">>2500×</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Основное время уходит на декодирование DICOM и препроцессинг, а не на сеть: разница между ускорителем и процессором в пределах 1.4×. Значит, ускоритель для этой задачи не является узким местом. Минимальная конфигурация — CPU; чекпоинт занимает 43 МБ, память ограничена накладными расходами среды исполнения. Образ содержит только код и фронтенд; веса монтируются при запуске.</p>
|
||
|
||
<h3>14. Тесты и воспроизводимость</h3>
|
||
<ul>
|
||
<li><strong>208 тестов</strong> в <code>tests/</code>: разбор имён и склейка дублей, отсутствие утечки при разбиении, фиксация разбиения, разметка по таблице и три правила метки, единый словарь типов, приведение имён файлов с откатом, препроцессинг и метрики, контракт API для интерфейса.</li>
|
||
<li><strong>Три браузерных теста</strong> на живом сервере: переключение строк меняет панель деталей, ветка «нарушение» показывает пометку «эвристика», страница не обращается к внешним хостам.</li>
|
||
<li><strong>Воспроизводимость:</strong> фиксированные seed'ы, гиперпараметры в отчёте, состав разбиения в файле, происхождение модели внутри чекпоинта.</li>
|
||
<li><strong>Команды:</strong> <code>./run.sh label | rename | split | compare | train | infer | serve | test</code>.</li>
|
||
</ul>
|
||
|
||
<h3>15. Ограничения и что с ними делать</h3>
|
||
<table>
|
||
<thead><tr><th>Ограничение</th><th>Следствие</th><th>Что планируется</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Разметка выведена из оценки исследования</td><td>поштучной экспертной оценки снимков нет</td><td>разметка отдельных снимков специалистом</td></tr>
|
||
<tr><td>Мало данных: 252 снимка, 77 нарушений</td><td>широкие интервалы, закрытый набор может дать другие цифры</td><td>500+ исследований</td></tr>
|
||
<tr><td>Тип нарушения — эвристика</td><td>5 снимков имеют только «нарушение без уточнения»</td><td>мультилейбл-модель по типам</td></tr>
|
||
<tr><td>Эталон — та же таблица</td><td>сравнение правил частично благоприятствует таблице</td><td>независимая экспертная оценка снимков</td></tr>
|
||
<tr><td>Область определяется по ширине кадра</td><td>порог привязан к текущему оборудованию</td><td>калибровка по метаданным аппарата</td></tr>
|
||
<tr><td>Теги латеральности пусты</td><td>сторона бедра в 7 исследованиях не проверяема</td><td>запрос тега у источника данных</td></tr>
|
||
<tr><td>Разметки ROI нет в DICOM</td><td>корректность областей наследуется из таблицы</td><td>проверка на данных с экспортной разметкой</td></tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3>16. Негативный результат, который стоит упомянуть</h3>
|
||
<p>Планировалась визуальная разметка снимков локальной vision-моделью (9 млрд параметров, офлайн): это сняло бы зависимость от экспертной таблицы. На калибровке по 14 снимкам, из которых 8 заведомо с нарушениями, модель вынесла «непригоден» всем 14, включая все качественные, с шаблонными формулировками и выдуманными имплантами. Разделяющая способность — на уровне случайной.</p>
|
||
<div class="warn">
|
||
Вывод: разделяющую способность инструмента нужно проверять <em>до</em> того, как строить на нём пайплайн. Инструменты рендера снимков и контактных листов остались в проекте — они полезны для выборочной ручной проверки.
|
||
</div>
|
||
|
||
<h3>17. Быстрые ответы на неудобные вопросы</h3>
|
||
<dl class="defs">
|
||
<dt>Почему ROC-AUC 0.68 — это не много?</dt>
|
||
<dd>Двести пятьдесят снимков и разметка, выведенная из оценки исследования. На таком объёме это ожидаемый порядок; выше 0.8 означало бы утечку или подгонку.</dd>
|
||
<dt>Почему не дообучали всю сеть?</dt>
|
||
<dd>Пробовали: train уходит в единицу, валидация — к случайной. Замороженный backbone и линейная голова дают устойчивый результат.</dd>
|
||
<dt>Почему не использовать все доступные пометки?</dt>
|
||
<dd>Проверили: служебные пометки расходились с экспертом в 15 случаях из 252, и обучение с ними дало ROC-AUC 0.6199 против 0.6764 — хуже на всех пяти seed'ах.</dd>
|
||
<dt>Почему тип нарушения не от модели?</dt>
|
||
<dd>Разметки типов на уровне снимка мало, а мультилейбл на 77 нарушениях дал бы ещё более широкие интервалы. Честнее показать эвристику с пометкой, чем модель, которой нельзя верить.</dd>
|
||
<dt>Что если на вход придёт область, которой не было?</dt>
|
||
<dd>Область определяется эвристикой; при неуверенности снимок относится к неизвестной области, а решение всё равно формируется и помечается в отчёте.</dd>
|
||
<dt>Можно ли доверять метрике на закрытом наборе?</dt>
|
||
<dd>Ожидаемо близко к валидационной, но с оговорками: порог подобран на валидации, объём мал, эталон — та же таблица. Ориентир — 0.68, а не выше.</dd>
|
||
</dl>
|
||
</section>
|
||
</div>
|
||
|
||
<footer class="page">
|
||
Все числа получены из артефактов проекта. Источники: <code>labels/labels_images.csv</code>, <code>models/compare_rules/rule_comparison.md</code>, <code>models/train_report.json</code>, <code>docs/labeling.md</code>, <code>README.md</code>, <code>QWEN.md</code>.
|
||
Страница самодостаточна и не обращается к внешним ресурсам.
|
||
</footer>
|
||
</div>
|
||
|
||
<script>
|
||
// Переключение вариантов. Без JavaScript виден только первый вариант,
|
||
// поэтому в <head> есть <noscript> с показом всех трёх подряд.
|
||
(function () {
|
||
var tabs = Array.prototype.slice.call(document.querySelectorAll('.tabs button'));
|
||
var panels = Array.prototype.slice.call(document.querySelectorAll('.panel'));
|
||
tabs.forEach(function (tab) {
|
||
tab.addEventListener('click', function () {
|
||
tabs.forEach(function (t) { t.setAttribute('aria-selected', String(t === tab)); });
|
||
panels.forEach(function (p) { p.classList.toggle('active', p.id === tab.dataset.panel); });
|
||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||
});
|
||
});
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|