Контроль качества денситометрических исследований (DXA)

Материалы к презентации в трёх вариантах: краткий спич, словарь терминов к нему и полная техническая выкладка. Все числа проверяемы, источник указан рядом.

Краткий спич Около трёх минут. Каждый блок — один абзац для произнесения; ниже — что показать на слайде.

1. Задача

Произнести Мы делали цифрового помощника по контролю качества денситометрии. По снимку DXA нужно решить, пригоден ли он для дальнейшего анализа, и объяснить, что именно не так. Вход — DICOM, выход — таблица XLSX или CSV, одна строка на снимок. Работает офлайн, в контейнере, не дольше трёх минут на исследование. Области — поясничный отдел позвоночника и проксимальный отдел бедра.

На слайд: колонки результата и требования — офлайн, контейнер, три минуты.

2. Данные

Произнести В наборе 544 файла, но это 252 уникальных снимка в ста исследованиях: остальное — те же кадры, сохранённые повторно. Экспертная оценка сделана в таблице, по каждому исследованию и с разбивкой на критерии: укладка, ось, артефакты, позиционирование, область интереса.

3. Как из оценки исследования получилась метка снимка

Произнести Оценка в таблице относится к исследованию, а модель работает со снимками — вердикт нужно было перенести. Здесь помогло свойство набора: после склейки дублей каждая анатомическая область встречается в исследовании ровно один раз. Значит, не нужно угадывать, какой из снимков «плохой»: вердикт области переносится на её снимок однозначно. Так размечены все 252 снимка, из них 77 с нарушениями.

На слайд: 544 файла → 252 снимка → 100 исследований; одна область на исследование.

4. Выбор правила разметки делали измерением

Произнести Метку можно было строить только из экспертной таблицы или дополнительно учитывать служебные пометки, которые проставлялись при подготовке набора. Они расходились с оценкой эксперта в пятнадцати случаях из двухсот пятидесяти двух, поэтому мы не стали верить на слово ни одному варианту: зафиксировали разбиение, обучили оба пятью seed'ами и сравнили по одному эталону. Победило правило «только таблица»: ROC-AUC 0.68 против 0.62, преимущество на всех пяти seed'ах. Служебные пометки в метках не участвуют.

5. Модель

Произнести Архитектура намеренно простая: ResNet18 с весами ImageNet как замороженный экстрактор признаков и линейная голова. Полное дообучение на двухстах снимках переобучается — train-метрика уходит в единицу, а качество на валидации падает до случайного. Аугментацию отключили: яркость и положение снимка сами являются признаками качества, и её включение роняло площадь под ROC-кривой с 0.87 до 0.56. Порог решения подбираем по логиту, максимизируя F1: вероятности насыщаются, и порог 0.5 даёт почти нулевой recall.

6. Результат

Произнести На фиксированном разбиении, пять seed'ов, оценка по вердикту эксперта: ROC-AUC 0.676 с интервалом от 0.63 до 0.72, PR-AUC 0.476, F1 0.568. Рабочий чекпоинт — обычный прогон с seed по умолчанию, его собственная оценка 0.671, то есть близка к среднему: результат не отобран по удачности.

На слайд: три строки метрик с интервалами и одна оговорка про эталон.

7. Модель смотрит на снимок, а не на область

Произнести Область исследования почти однозначно определяется шириной кадра, поэтому есть риск, что модель просто угадывает анатомию. Мы это проверили отдельно: внутри областей модель даёт AUC от 0.85 до 0.93, а правило «позвоночник — значит нарушение» — ровно 0.5, потому что внутри области подсказки нет. Значит, модель работает с содержимым снимка.

8. Скорость

Произнести Обработка одного снимка — около пятнадцати миллисекунд, на процессоре двадцать. При бюджете три минуты на исследование запас более чем тысячекратный. Чекпоинт занимает 43 мегабайта, ускоритель для этой задачи не обязателен: время уходит на декодирование снимка, а не на сеть.

9. Чего мы не утверждаем

Произнести Модель бинарная: она не определяет тип нарушения. Тип, который вы видите в интерфейсе, посчитан эвристикой по метрикам снимка и помечен соответствующей пометкой — мы намеренно не выдаём предположение за заключение. Эталон, по которому мы мерили, — та же экспертная таблица, независимой истины у нас нет. Данных мало: 252 снимка, в валидации шестнадцать нарушений, интервалы широкие. И отдельно: локальная vision-модель на девять миллиардов параметров, которой мы хотели размечать снимки визуально, вынесла «непригоден» всем четырнадцати снимкам калибровки, включая заведомо качественные. От этого пути отказались, проверив его одним прогоном, а не неделей разработки.

10. Что дальше

Произнести Три направления: поштучная разметка снимков специалистом, чтобы снять главное ограничение; мультилейбл-модель для типов нарушений вместо эвристики; больше исследований, чтобы сузить интервалы.

Шпаргалка: цифры, которые будут спрашивать

ВопросОтветОткуда
Сколько снимков?252 уникальных в 100 исследованиях (544 файла на диске)склейка дублей по пикселям
Сколько нарушений?77 из 252 (30.6 %): 74 по экспертной таблице + 3 без экспертной оценкиlabels/labels_images.csv
ROC-AUC0.6764 [0.6309, 0.7218], 5 seed'овmodels/compare_rules/rule_comparison.md
PR-AUC / F10.4759 [0.4141, 0.5377] / 0.5676 [0.5270, 0.6082]там же
Почему такое правило разметки?замер: +0.0564 ROC-AUC против варианта со служебными пометками, 5 из 5 seed'овтам же
Вклад содержимого снимкавнутри областей AUC 0.85–0.93 против 0.50 у правила областиdiscriminator
Скорость≈15 мс на снимок на ускорителе, 20 мс на CPUзамер на 544 файлах
Размер модели42.8 МБ, 11.2 млн параметров, обучается только головаmodels/dxa_model.pth
Тесты208./run.sh test

Определения Расширение краткого спича: термины, которыми придётся отвечать на вопросы. Формулировки привязаны к тому, как эти слова используются в решении.

Данные и формат

DXA / ДРА двухэнергетическая рентгеновская абсорбциометрия
Метод измерения минеральной плотности костной ткани. От качества укладки и разметки зависит не «красивость» снимка, а само число. Задача — контроль качества измерения, а не диагностика перелома.
DICOM
Стандарт хранения и передачи медицинских изображений: пиксельные данные плюс метаданные. Вход решения; из метаданных берём идентификаторы, но решение не зависит от персональных данных.
StudyInstanceUID и SOPInstanceUID
StudyInstanceUID идентифицирует исследование, SOPInstanceUID — конкретный снимок. Оба идут в выходной файл: study_uid и image_uid. Подводный камень: имя каталога исследования в наборе не совпадает с этим тегом, а экспертная таблица ссылается на каталог. Склейка идёт по каталогу, в отчёт попадает тег.
ROI region of interest
Область интереса: рамка или контур, по которой считают плотность. Правильность её проведения — самостоятельный критерий качества. В предоставленных DICOM разметка ROI отсутствует, сравнить её не с чем: корректность областей оценивается экспертом в таблице, и это открытое ограничение решения.
Побайтный дубль
Файлы с идентичным пиксельным содержимым под разными именами. В наборе 544 файла против 252 уникальных снимков. Зачем склеивать: иначе один и тот же снимок попадал и в обучение, и в валидацию.
Анатомическая область
В решении три области: spine (поясничный отдел), hip_right и hip_left (проксимальный отдел бедра). Область определяется по геометрии кадра, а не по метаданным: ширина кадра у позвоночника около 300 пикселей, у бедра около 280. Порог привязан к текущему оборудованию — это ограничение.

Разметка

Экспертная таблица
Файл разметка.xlsx: по каждому исследованию отмечены критерии — укладка, ось, артефакты для позвоночника; позиционирование и область интереса для каждого бедра; плюс итог по области и комментарий. Значение 1 в критерии означает нарушение, хотя часть заголовков сформулирована положительно. Проверено: итог области равен логическому ИЛИ критериев (бёдра 72/72 и 78/78, позвоночник 96/99).
Единица разметки
То, к чему относится метка. Таблица описывает исследование, решение работает со снимками. Ключевое свойство набора: после склейки дублей каждая область встречается в исследовании ровно один раз, поэтому вердикт переносится на снимок области однозначно.
Правило метки table / union
Как из оценки получается метка снимка. table — только экспертная таблица (принято), union — таблица и служебные пометки, проставленные при подготовке набора. Выбрано измерением: table дал ROC-AUC 0.6764 против 0.6199, преимущество на всех пяти seed'ах. Есть третье правило, expert: только снимки с экспертной оценкой — оно служит эталоном при оценке, а не для обучения.
quality_class
Бинарный класс: 0 — качественное изображение, 1 — есть нарушение. Это итоговое решение модели.
Пригоден / непригоден
Формулировка того же решения словами. «Пригоден» означает, что нет видимых причин мешать специалисту выполнить дальнейший анализ; это не значит, что снимок диагностически нормален. Правило методики: если хотя бы один существенный пункт нарушен или не подтверждается по изображению, снимок непригоден. Сомнительные случаи не пропускаются.
violation_type
Тип нарушения — строка, перечень через точку с запятой, словарь канонический и единый для решения, отчёта DICOM SR и интерфейса. Пять кодов кодирует экспертная таблица: positioning, axis_deviation, artifact, rotation, roi_incorrect. Ещё три задаёт методика: motion, incomplete_anatomy, labeling_error. Плюс unspecified — нарушение без уточнения.
Эвристика
Правило, а не обученная модель. Тип нарушения определяется эвристикой по метрикам снимка, потому что модель бинарная. В интерфейсе это помечено пометкой «эвристика» с пояснением: показывать предположение как заключение нельзя.
Зеркалирование стороны бедра
Ситуация, когда в исследовании снят один снимок бедра, а в таблице заполнен столбец противоположной стороны — 6 исследований из 7 с одним бедром. Логика: снимок один и заполненный столбец один — они соответствуют друг другу. Факт переноса фиксируется флагом; теги латеральности в DICOM пусты, поэтому сторону иначе не проверить.

Модель и обучение

Линейный зонд linear probe
Режим, при котором свёрточная часть сети заморожена и обучается только линейный слой поверх её признаков. На двухстах снимках полное дообучение переобучается: train F1 уходит в единицу при случайном AUC на валидации. Обучаемых параметров остаются тысячи вместо миллионов.
Frozen backbone и BatchNorm
При заморозке отключается не только градиент, но и train-режим слоёв нормализации: иначе бегущие статистики продолжают меняться на обучающих батчах и входной слой получает не те данные, на которых калибровался.
Препроцессинг
Один путь для обучения и API: прочитать DICOM с учётом наклона и инверсии, привести к диапазону по перцентилям 0.5–99.5, увеличить до 224×224, повторить в три канала, нормировать по статистикам ImageNet. Перцентили вместо минимума-максимума: одиночные яркие пиксели (металл, метка оператора) иначе сжимают весь диапазон.
Порог по логиту
Решающее правило сравнивает логит с порогом, который подобран по F1 на валидации и хранится в чекпоинте вместе с весами (у рабочего — логит −0.493, вероятность 0.379). Почему не 0.5: вероятности насыщаются, и фиксированный порог давал почти нулевой recall при доле нарушений около 30 %.
Аугментация
Случайные искажения при обучении. Здесь отключена по умолчанию. Причина содержательная: яркость и положение снимка сами являются признаками качества, поэтому искажать их — значит уничтожать целевую информацию. Проверено: включение роняло AUC с 0.87 до 0.56.
Разбиение по исследованиям
Все снимки одного исследования попадают только в одну часть — обучение или валидацию. Иначе получается утечка: снимки одного пациента похожи, и качество на валидации оказывается завышенным.
Зафиксированное разбиение
Файл со списком исследований валидации, который не пересчитывается при смене правил разметки. Разбиение стратифицируется по наличию нарушений, а оно зависит от меток. Без фиксации варианты сравнивались бы на разных наборах.
Эталон оценки
Разметка, по которой считается качество: в нашем случае — вердикт эксперта, взятый только на снимках с экспертной оценкой. Оценивать вариант на его же метках — круговое сравнение. Эталон один и тот же для всех вариантов.

Метрики

ROC-AUC
Вероятность, что случайно взятый снимок с нарушением получит более высокий балл, чем случайно взятый качественный. Не зависит от порога, поэтому это основная метрика сравнения.
PR-AUC
Площадь под кривой точность-полнота. Чувствительна к доле положительного класса: при 30 % нарушений базовый уровень — 0.30, поэтому сравнивать её между наборами с разной долей нельзя.
F1, precision, recall
F1 — среднее гармоническое точности и полноты. Recall — какая доля нарушений найдена, precision — какая доля тревог подтверждается. В нашей задаче пропустить нарушение дороже, чем отправить снимок на ручную проверку.
Доверительный интервал 95 %
Диапазон, в котором с вероятностью 95 % лежит истинное значение. Здесь интервалы считаются по пяти seed'ам обучения через распределение Стьюдента. Чего он не покрывает: неопределённость самой разметки. Поэтому интервал по seed'ам не заменяет независимый тест на закрытом наборе.
Парная разница
Разность метрик двух вариантов, посчитанная для каждого seed'а отдельно и затем усреднённая. Варианты обучались на одном разбиении и одном seed'е, поэтому разброс обучения вычитается и видно эффект самого правила.

Инженерия и эксплуатация

Контейнеризация
Решение поставляется образом с зафиксированными версиями зависимостей; запуск — скриптом в Linux и UNIX-подобных системах. Веса монтируются при запуске, данные в образ не попадают.
Офлайн-работа
Медицинские изображения не покидают контур: ни внешних сервисов, ни обращений к CDN. Стили и шрифты интерфейса лежат локально. Это требование методики, а не оптимизация; оно ограничило и выбор способа разметки.
processing_status
Поле отчёта: Success или Failure. Необработанных исключений быть не должно — любая ошибка фиксируется в строке результата.
DICOM SR
Structured Report — текстовое структурированное представление результата. Оговорка: полноценного справочника SNOMED для контролёра качества DXA в наборе нет, поэтому числовые коды условные, и рядом всегда идёт текстовая формулировка.
Чекпоинт
Файл с весами, порогом, параметрами препроцессинга и метаданными: на какой разметке обучен, по какому разбиению, с каким seed'ом. Самодостаточность важна: инференс не может рассинхронизироваться с обучением, а по файлу видно, что именно работает.

Полная техническая выкладка Для вопросов «а как именно» и для инженера, который будет разворачивать решение.

1. Требования и что именно решается

  • Объект: поясничный отдел позвоночника и проксимальный отдел бедренной кости.
  • Решение: бинарная классификация — пригоден (0) или есть нарушение (1) — плюс определение анатомической области и типа нарушения.
  • Вход: DICOM без разметки; в исследовании до трёх изображений.
  • Выход: XLSX или CSV, одна строка на снимок: path_to_study, study_uid, image_uid, anatomical_region, quality_class, violation_type, processing_status, time_of_processing.
  • Приоритетные метрики: F1 и ROC-AUC с 95 % доверительными интервалами.
  • Ограничения: офлайн, контейнеризация, до трёх минут на исследование, воспроизводимость, отсутствие необработанных исключений.

2. Данные: состав

ПоказательЗначение
Файлов DICOM на диске544
Уникальных снимков (по пикселям)252
Исследований100
Снимков: позвоночник / бедро R / бедро L / неопределено99 / 79 / 73 / 1
Нарушений по экспертной таблице74 (29.4 %)
Нарушений в обучающей разметке77 (30.6 %)
Снимков без экспертной оценки3

Аномалии, повлиявшие на решения

  • Дубли. Один кадр сохранён многократно; склейка по хешу пиксельных данных.
  • Конфликт имён внутри одной группы дублей. Два файла одного и того же снимка названы как разные области, поэтому область определяется голосованием по именам; при равенстве голосов остаётся неопределённой (такой снимок один).
  • Имя каталога ≠ StudyInstanceUID. Таблица ссылается на каталог, в DICOM лежит другой идентификатор; соответствие один к одному, 100 из 100.
  • Пустые теги латеральности. Метаданных о стороне бедра нет.
  • Разметки ROI нет. Ни OverlayData, ни GraphicAnnotationSequence.
  • Служебные пометки в данных. Метки из них не строятся — правило выбрано измерением (§5); имена приведены к единому виду отдельным инструментом (§7).

3. Семантика экспертной таблицы

Две строки заголовков, данные с третьей. Столбцы 2–4 — критерии позвоночника (укладка, ось, артефакты), 5–6 и 7–8 — позиционирование и область интереса для правого и левого бедра, 9–11 — итоги по областям, 12 — комментарий.

Значение 1 в критерии означает нарушение, хотя часть заголовков сформулирована положительно («корректная укладка»). Проверено на данных: итог области равен логическому ИЛИ критериев — для бёдер 72/72 и 78/78, для позвоночника 96/99. Три расхождения позвоночника трактуются как нарушение, что соответствует правилу «хотя бы один существенный пункт нарушен».

Заполненность: позвоночник 99 из 100 исследований, бедро R 72, бедро L 78; комментарий есть у 23 исследований.

4. Как построена разметка на уровне снимка

  1. Ключ склейки — имя каталога исследования, а не тег DICOM.
  2. Склейка дублей по хешу пиксельных данных: 544 файла → 252 снимка.
  3. Область — голосование по именам файлов одной группы изображений.
  4. Перенос вердикта — оценка области переносится на её снимок. Основание: каждая область встречается в исследовании ровно один раз.
  5. Зеркалирование стороны. В 71 из 72 исследований с двумя бёдрами столбцы совпадают с именами файлов. В 7 исследованиях снят один снимок бедра, и в 6 из них заполнен столбец противоположной стороны: раз снимок один и заполненный столбец один, они соответствуют друг другу. Перенос фиксируется флагом laterality_mirrored.
  6. Тип нарушения берётся только из структурированных критериев. Комментарии («сколиоз», «эндо протезирование ТБС») сохранены дословно и в код не перекладываются.
  7. Три снимка, по которым таблица область не оценивала, получают метку из служебной пометки и помечены filename_fallback — иначе они остались бы без метки вообще.

Результат: labels/labels_images.csv (и XLSX) — 252 строки, 175 качественных и 77 с нарушениями.

5. Выбор правила метки: измерение

Правило «только таблица» против «таблица плюс служебные пометки при подготовке набора». Пометки расходились с оценкой эксперта в 15 случаях из 252, поэтому выбор делался измерением: одно фиксированное разбиение, пять seed'ов, один эталон (вердикт эксперта на снимках валидации).

Метрика (эталон)только таблицасо служебными пометками
ROC-AUC0.6764 [0.6309, 0.7218]0.6199 [0.5840, 0.6559]
PR-AUC0.4759 [0.4141, 0.5377]0.4046 [0.3702, 0.4391]
F10.5676 [0.5270, 0.6082]0.5426 [0.5073, 0.5778]
Recall / Precision0.700 / 0.4860.863 / 0.404
Парная разница (таблица − с пометками)Δ, среднее [95 % ДИ]Знаки по seed'ам
ROC-AUC+0.0564 [+0.0403, +0.0725]+++++
PR-AUC+0.0713 [+0.0398, +0.1028]+++++
F1+0.0251 [−0.0056, +0.0558]+++-+
Precision+0.0815 [+0.0590, +0.1039]+++++
./run.sh split      # зафиксировать разбиение (стратификация по эталону)
./run.sh compare    # 5 seed'ов × 2 варианта, отчёт models/compare_rules/rule_comparison.md
Оговорка. Эталон — та же экспертная таблица, на которой обучался победивший вариант, поэтому сравнение частично ему благоприятствует. Значимый вывод другой: добавление служебных пометок снижает согласие модели с экспертом на невиданных исследованиях.

6. Словарь типов нарушений

КодПодписьОбластьИсточник
positioningНекорректная укладкапозвоночниктаблица
axis_deviationОтклонение осипозвоночниктаблица
artifactАртефакты и имплантылюбаятаблица
rotationРотация, позиционированиебедротаблица
roi_incorrectНекорректная область интересалюбаятаблица
motionДвижение, размытиелюбаяметодика
incomplete_anatomyАнатомия видна не полностьюлюбаяметодика
labeling_errorОшибка разметкипозвоночникметодика
unspecifiedНарушение без уточнениялюбаяслужебный

Распределение в разметке: rotation 36, artifact 17, axis_deviation 10, roi_incorrect 7, positioning 6, unspecified 5.

Словарь раньше существовал в трёх копиях — в модуле инференса, в API и в JavaScript интерфейса, — и ни один из них не знал кодов экспертной таблицы: в интерфейсе они показывались как есть. Теперь словарь один (src/dxa/violations.py), подписи отдаёт сервер, старые значения приводятся к канону.

7. Гигиена данных: имена файлов

Отдельный инструмент приводит имена файлов к единому виду: область, две цифры номера, при наличии — пометка качества. Приведено 344 файла из 548, карта отката сохранена, разметка и метрики при этом не менялись.

./run.sh rename            # план правки, без изменений на диске
./run.sh rename --apply    # выполнить; карта отката labels/rename_map.csv
./run.sh rename --rollback --apply   # вернуть прежние имена

Правка сделана после того, как разметка и метрики были посчитаны, и проверено, что она на них не влияет: набор из 252 пиксельных групп идентичен до и после, разметка не изменилась ни в одной строке. Пометки качества в именах в метках не участвуют — только как диагностический столбец.

8. Предобработка

DICOM → pixel_array (RescaleSlope/Intercept, MONOCHROME1)
      → нормализация по перцентилям 0.5–99.5 → [0, 1]
      → ×255, uint8
      → повтор в 3 канала, билинейный resize 224×224
      → /255, нормировка по статистикам ImageNet
      → тензор (3, 224, 224) float32

Один и тот же путь используется при обучении и в API. Обучение и API вызывают общий код предсказания, поэтому порог и препроцессинг совпадают по построению.

9. Модель

КомпонентЗначение
BackboneResNet18, веса ImageNet, заморожен (заморозка на всё обучение)
Классификационная головалинейный слой, 2 класса; обучаемых параметров — тысячи
Вспомогательная голова областивес в функции потерь 0.3
Вход224×224, 3 канала; BatchNorm в eval-режиме
Порог−0.4930 по логиту (вероятность 0.379), подбор по F1 на валидации
Размер чекпоинта42.8 МБ, 11.2 млн параметров сети
Определение областиэвристика по ширине кадра (позвоночник ≈300 px, бедро ≈280 px)

Гиперпараметры по умолчанию

  • Эпох 100, batch 16, early stopping с терпением 25, отбор эпохи по сглаженному (окно 5) ROC-AUC.
  • Оптимизатор AdamW, lr 3e-4, weight decay 0.05 (decoupled).
  • Балансировка классов и аугментация: выключены.
  • Валидационная доля 0.2, разбиение по исследованиям, seed 42.

10. Оценка качества

Фиксированное разбиение: обучение 199 снимков / 81 исследование, валидация 53 снимка / 19 исследований, 16 нарушений по эталону. Пять seed'ов.

МетрикаЗначение
ROC-AUC0.6764 [0.6309, 0.7218]
PR-AUC0.4759 [0.4141, 0.5377]
F10.5676 [0.5270, 0.6082]
Рабочий чекпоинтЗначение
Обучение / валидация199 снимков / 81 исследование — 53 снимка / 19 исследований, 16 нарушений
Эпоха / порог39 / логит −0.4930 (вероятность 0.379)
ROC-AUC / PR-AUC0.6706 / 0.4585
F1 / recall / precision0.5600 / 0.875 / 0.412
ROC-AUC по областямпозвоночник 0.943, бедро R 0.576, бедро L 0.550
Это обычный прогон с seed по умолчанию, а не лучший из выборки. Его собственная валидационная ROC-AUC 0.6706 близка к среднему по пяти seed'ам 0.6764 — результат не отобран по удачности.

11. Проверка вклада модели: смотрит ли она на снимок

В позвоночнике нарушений треть, у бёдер около трети, а область почти однозначно определяется шириной кадра. Отсюда вопрос: не выучила ли модель просто «область вместо качества». Проверка — сравнение с правилом «позвоночник значит нарушение».

ПредикторОбщий AUCspinehip_righthip_left
Модель0.8540.9280.8610.853
Правило «позвоночник = нарушение»0.5290.5000.5000.500

Внутри областей правило не имеет подсказки и даёт ровно 0.5; модель — 0.85–0.93. Значит, она использует содержимое снимка. Оговорка: проверка считается на всём наборе, включая обучающие снимки, поэтому значения смещены вверх; она отвечает на вопрос «есть ли вклад содержимого», а не «каково качество на новых данных».

12. Инференс, API и формат результата

МетодПутьНазначение
GET/api/v1/healthстатус и происхождение загруженной модели
GET/api/v1/modelкарточка решения: разметка, данные, метрики, словарь нарушений, ограничения
POST/api/v1/analyzeанализ одного файла
POST/api/v1/analyze/detailedрасширенный отчёт, при необходимости с маской
POST/api/v1/analyze/srтекстовое представление отчёта DICOM SR
POST/api/v1/batchпакетный анализ
POST/api/v1/exportпакетный анализ и выгрузка XLSX

Ответ анализа по одному файлу, сверх обязательных колонок: confidence, threshold_probability, region_confidence, violation_type_label, violation_type_is_heuristic, violation_type_note, reason, metrics, samples.

Ошибки не приводят к исключению: строка получает processing_status = Failure. Путь к чекпоинту задаётся переменной DXA_MODEL_PATH, чтобы контейнер не зависел от рабочего каталога.

13. Скорость и системные требования

ПоказательУскоритель (Apple MPS)CPU, 8 потоков
Обработка одного снимка, медиана15 мс20 мс
Весь набор (544 файла)8 с—
На одно исследование (до 3 снимков)≈0.05 с≈0.06 с
Запас к бюджету 3 минуты>3000×>2500×

Основное время уходит на декодирование DICOM и препроцессинг, а не на сеть: разница между ускорителем и процессором в пределах 1.4×. Значит, ускоритель для этой задачи не является узким местом. Минимальная конфигурация — CPU; чекпоинт занимает 43 МБ, память ограничена накладными расходами среды исполнения. Образ содержит только код и фронтенд; веса монтируются при запуске.

14. Тесты и воспроизводимость

  • 208 тестов в tests/: разбор имён и склейка дублей, отсутствие утечки при разбиении, фиксация разбиения, разметка по таблице и три правила метки, единый словарь типов, приведение имён файлов с откатом, препроцессинг и метрики, контракт API для интерфейса.
  • Три браузерных теста на живом сервере: переключение строк меняет панель деталей, ветка «нарушение» показывает пометку «эвристика», страница не обращается к внешним хостам.
  • Воспроизводимость: фиксированные seed'ы, гиперпараметры в отчёте, состав разбиения в файле, происхождение модели внутри чекпоинта.
  • Команды: ./run.sh label | rename | split | compare | train | infer | serve | test.

15. Ограничения и что с ними делать

ОграничениеСледствиеЧто планируется
Разметка выведена из оценки исследованияпоштучной экспертной оценки снимков нетразметка отдельных снимков специалистом
Мало данных: 252 снимка, 77 нарушенийширокие интервалы, закрытый набор может дать другие цифры500+ исследований
Тип нарушения — эвристика5 снимков имеют только «нарушение без уточнения»мультилейбл-модель по типам
Эталон — та же таблицасравнение правил частично благоприятствует таблиценезависимая экспертная оценка снимков
Область определяется по ширине кадрапорог привязан к текущему оборудованиюкалибровка по метаданным аппарата
Теги латеральности пустысторона бедра в 7 исследованиях не проверяемазапрос тега у источника данных
Разметки ROI нет в DICOMкорректность областей наследуется из таблицыпроверка на данных с экспортной разметкой

16. Негативный результат, который стоит упомянуть

Планировалась визуальная разметка снимков локальной vision-моделью (9 млрд параметров, офлайн): это сняло бы зависимость от экспертной таблицы. На калибровке по 14 снимкам, из которых 8 заведомо с нарушениями, модель вынесла «непригоден» всем 14, включая все качественные, с шаблонными формулировками и выдуманными имплантами. Разделяющая способность — на уровне случайной.

Вывод: разделяющую способность инструмента нужно проверять до того, как строить на нём пайплайн. Инструменты рендера снимков и контактных листов остались в проекте — они полезны для выборочной ручной проверки.

17. Быстрые ответы на неудобные вопросы

Почему ROC-AUC 0.68 — это не много?
Двести пятьдесят снимков и разметка, выведенная из оценки исследования. На таком объёме это ожидаемый порядок; выше 0.8 означало бы утечку или подгонку.
Почему не дообучали всю сеть?
Пробовали: train уходит в единицу, валидация — к случайной. Замороженный backbone и линейная голова дают устойчивый результат.
Почему не использовать все доступные пометки?
Проверили: служебные пометки расходились с экспертом в 15 случаях из 252, и обучение с ними дало ROC-AUC 0.6199 против 0.6764 — хуже на всех пяти seed'ах.
Почему тип нарушения не от модели?
Разметки типов на уровне снимка мало, а мультилейбл на 77 нарушениях дал бы ещё более широкие интервалы. Честнее показать эвристику с пометкой, чем модель, которой нельзя верить.
Что если на вход придёт область, которой не было?
Область определяется эвристикой; при неуверенности снимок относится к неизвестной области, а решение всё равно формируется и помечается в отчёте.
Можно ли доверять метрике на закрытом наборе?
Ожидаемо близко к валидационной, но с оговорками: порог подобран на валидации, объём мал, эталон — та же таблица. Ориентир — 0.68, а не выше.