27 KiB
Разметка датасета и выбор правила метки
Документ описывает, откуда берутся метки снимков, как проверялось правило разметки и какие результаты из этого следуют. Числа проверяемы: ссылки на источники приведены рядом.
1. Задача разметки
Экспертная оценка в наборе сделана на уровне исследования: в таблице
разметка.xlsx по каждому исследованию отмечены критерии качества, а не по
отдельному снимку. Модель же работает со снимками, поэтому вердикт исследования
нужно было перенести на каждый снимок — без догадок и без потери информации о
том, откуда метка взялась.
2. Экспертная таблица
Столбцы (две строки заголовков, данные с третьей):
| Столбец | Смысл | Тип нарушения |
|---|---|---|
| 2 | Позвоночник: укладка | positioning |
| 3 | Позвоночник: ось | axis_deviation |
| 4 | Позвоночник: артефакты, наложения | artifact |
| 5, 6 | Бедро R: позиционирование/ротация, область интереса | rotation, roi_incorrect |
| 7, 8 | Бедро L: то же | rotation, roi_incorrect |
| 9, 10, 11 | Итог по области | — |
| 12 | Комментарий эксперта | — |
Семантика значений установлена по данным, а не по формулировкам заголовков:
1в столбце критерия означает нарушение, хотя часть заголовков сформулирована положительно («корректная укладка»);- итог области равен логическому ИЛИ критериев: бёдра 72/72 и 78/78, позвоночник 96/99;
- три расхождения позвоночника (два случая «итог без критериев», один «критерий без итога») трактуются как нарушение — по правилу «хотя бы один существенный пункт нарушен»;
- заполненность: позвоночник 99/100, бедро R 72/100, бедро L 78/100; у 23 исследований есть комментарий.
3. Перенос вердикта на снимок
| Шаг | Что делается | Почему так |
|---|---|---|
| Ключ склейки | имя каталога исследования | таблица ссылается на каталог (2.25…), а в DICOM лежит другой идентификатор (1.2.643…); соответствие каталог → тег 100/100 |
| Склейка дублей | по хешу пиксельных данных | 478 файлов — это 251 уникальный снимок |
| Область снимка | голосование по именам файлов группы | один снимок назван и как позвоночник, и как бедро; при равенстве голосов область остаётся неопределённой (такой снимок один) |
| Вердикт | оценка области переносится на её снимок | каждая область встречается в исследовании ровно один раз, поэтому не нужно решать, какой из нескольких снимков «плохой» |
| Сторона бедра | при единственном снимке бедра берётся единственный заполненный столбец | в 71 из 72 исследований с двумя бёдрами столбцы совпадают с именами файлов; в 7 исследованиях с одним снимком заполнена противоположная сторона. Факт переноса фиксируется флагом laterality_mirrored; теги Laterality в DICOM пусты |
| Тип нарушения | только из структурированных критериев | комментарии («сколиоз», «эндопротезирование ТБС») сохранены дословно: перекладывать свободный текст в код — догадка |
4. Правило метки и почему оно такое
Метка могла строиться двумя способами: только из таблицы или с добавлением
пометок, которые вручную проставлялись в именах файлов (суффикс _bad). Пометки
в именах оказались ненадёжными: они расходились с оценкой эксперта в 62 случаях
из 251. Выбор сделан измерением, а не по вкусу.
Постановка. Разбиение по исследованиям зафиксировано один раз, оба варианта обучены пятью seed'ами на нём, оценены по одному эталону — вердикту эксперта на снимках валидации. Снимки валидации не участвуют в обучении ни в одном варианте.
Воспроизведение: python -m src.dxa.excel_labels --label-rule {table,union,expert}
и python -m src.dxa.compare_labels --split-file labels/split_expert_seed42.json.
Результат (53 снимка валидации, 16 нарушений по эталону, 5 seed'ов):
| Метрика (эталон) | только таблица | таблица или суффикс _bad |
|---|---|---|
| ROC-AUC | 0.6726 [0.6367, 0.7086] | 0.6003 [0.5592, 0.6415] |
| PR-AUC | 0.4753 [0.4188, 0.5318] | 0.3864 [0.3487, 0.4242] |
| F1 | 0.5559 [0.5212, 0.5906] | 0.5354 [0.4978, 0.5729] |
| Recall | 0.7125 | 0.7875 |
| Precision | 0.4716 | 0.4087 |
Парная разница («только таблица» − «с суффиксами»):
| Метрика | Δ, среднее [95 % ДИ] | Знаки по seed'ам |
|---|---|---|
| ROC-AUC | +0.0723 [+0.0541, +0.0905] | +++++ |
| PR-AUC | +0.0889 [+0.0500, +0.1277] | +++++ |
| F1 | +0.0205 [−0.0182, +0.0592] | +-+-+ |
| Precision | +0.0629 [−0.0133, +0.1392] | +++-+ |
| Recall | −0.0750 [−0.1931, +0.0431] | 0---0 |
Решение: принято правило «только экспертная таблица». Дополнительные пометки из имён файлов ухудшали согласие модели с экспертом на невиданных исследованиях: вариант с ними чаще срабатывал (recall 0.79), но за счёт точности, а по беспороговым метрикам проигрывал на всех пяти seed'ах.
Оговорка: эталон — та же экспертная таблица, поэтому вариант, обучавшийся непосредственно на ней, находится в выигрышном положении. Значимо здесь другое: добавление ненадёжных пометок снижает согласие с экспертом, что и служит аргументом против них.
5. Словарь типов нарушений
| Код | Подпись | Область | Источник |
|---|---|---|---|
positioning |
Некорректная укладка | позвоночник | таблица |
axis_deviation |
Отклонение оси | позвоночник | таблица |
artifact |
Артефакты и импланты | любая | таблица |
rotation |
Ротация, позиционирование | бедро | таблица |
roi_incorrect |
Некорректная область интереса | любая | таблица |
motion |
Движение, размытие | любая | критерии методики |
incomplete_anatomy |
Анатомия видна не полностью | любая | критерии методики |
labeling_error |
Ошибка разметки | позвоночник | критерии методики |
unspecified |
Нарушение без уточнения | любая | служебный |
Распределение в разметке: rotation 35, artifact 17, axis_deviation 10,
roi_incorrect 7, positioning 6, unspecified 5. Всего 80 критериев на 76
нарушений: у части снимков таблица отмечает по два критерия.
Словарь один на всё решение (src/dxa/violations.py): коды используют инференс,
отчёт DICOM SR и веб-интерфейс, подписи отдаёт сервер, копий в JavaScript нет.
6. Результат разметки
labels/labels_images.csv (и XLSX) — по одной строке на уникальный снимок:
| позвоночник | бедро R | бедро L | неопред. | всего | |
|---|---|---|---|---|---|
| качественных | 66 | 58 | 51 | 0 | 175 |
| с нарушением | 33 | 20 | 22 | 1 | 76 |
| итого | 99 | 78 | 73 | 1 | 251 |
Помимо метки в CSV сохранено происхождение: quality_from_excel (вердикт
эксперта), quality_from_filename (пометка из имени файла), sources_conflict,
label_rule, filename_fallback, laterality_mirrored, region_ambiguous,
expert_comment. Поэтому правило можно переиграть без повторного разбора.
Рядом лежат варианты для воспроизведения сравнения:
labels_images_table.csv, labels_images_union.csv, labels_images_expert.csv
(эталон: только снимки с экспертной оценкой, 248 строк) и
split_expert_seed42.json (зафиксированное разбиение).
7. Гигиена данных: имена файлов
Имена проставлялись вручную и разошлись: spine_1 и spine_01, Spine_01,
r_spine_03, r_hip03, r_hop_02 (опечатка), spine-1. Они приведены к виду
<область>_<NN>[_good|_bad].dcm инструментом src/dxa/rename_files.py;
переименовано 344 файла из 548, карта отката — labels/rename_map.csv.
Переименование сделано после того, как разметка и метрики были посчитаны, и
проверено, что оно на них не влияет: набор из 252 пиксельных групп идентичен до и
после, разметка не изменилась ни в одной строке. Суффиксы _good/_bad
сохранены как были и в метках не участвуют — только как диагностический столбец.
Числа в этих двух абзацах — состояние на момент проверки; актуальное состояние
набора и разметки приведено ниже.
Расхождение разметки с датасетом и его устранение (2026-09-27)
К описанному проходу добавился более поздний: 2026-09-27 около 02:02 суффиксы
_good/_bad дописаны ещё 54 файлам, то есть после сборки разметки
(2026-09-26 22:35). apply_excel_labels сопоставляет метки строго по
path_to_image, поэтому во всех четырёх файлах разметки (labels_images.csv,
_table, _union, _expert) 20 строк стали ссылаться на имена, которых больше
нет. Последствие: эти 20 снимков теряли экспертную метку и падали на пометку из
имени файла, у 6 из них метка инвертировалась 0 → 1 (вердикт эксперта — «годное»,
файл назван ..._bad.dcm), и пайплайн отдавал 251 снимок / 82 нарушения вместо
записанных выше 252 / 77. Расхождение нашли сравнением меток с именами файлов;
тесты падали на числах (assert 251 == 252), то есть оно было замечено, а не
осталось незамеченным.
Устранено пересборкой: ./run.sh label и три варианта правила, ./run.sh split,
затем переобучение ./run.sh train. Актуальное состояние — 251 снимок / 76
нарушений, все пути разметки существуют, расхождений с датасетом нет. Пометки в
именах при этом расходятся с вердиктом эксперта в 62 случаях из 251 (было 15
из 252): после второго переименования пометок стало больше, и они чаще спорят с
таблицей. На метку это не влияет — правило table их не использует (см. §4), —
но именно эти 62 снимка имеет смысл разобрать первыми в интерфейсе ручной
разметки (см. §10).
Чистка датасета в тот же день: удалены 38 лишних байт-идентичных копий .dcm
внутри НД_для_обучения и 10 файлов .DS_Store. На разметку и на набор
пиксельных групп это не влияет: групп 251, все совпадают с path_to_image. На
диске 482 .dcm из 494 файлов. У каждого удалённого файла остался байт-идентичный
близнец, поэтому потеряно только имя, а не содержимое.
8. Оценка качества модели
Разбиение по исследованиям (по умолчанию seed 42): обучение 198 снимков / 81 исследование, валидация 53 снимка / 19 исследований, 16 нарушений.
| Метрика | Значение | Как получено |
|---|---|---|
| ROC-AUC | 0.6726 [0.6367, 0.7086] | 5 seed'ов на фиксированном разбиении, эталон — вердикт эксперта |
| PR-AUC | 0.4753 [0.4188, 0.5318] | там же |
| F1 | 0.5559 [0.5212, 0.5906] | там же; порог подобран по F1 на валидации, поэтому смещён вверх |
| ROC-AUC по областям | позвоночник 0.929, бедро R 0.606, бедро L 0.567 | рабочий чекпоинт, его собственная валидация |
Рабочий чекпоинт — обычный прогон с seed по умолчанию (эпоха 57, порог логита −0.1370 → вероятность 0.466), его собственная валидационная ROC-AUC 0.6689 близка к среднему по seed'ам, то есть результат не отобран по удачности.
Проверка, что модель смотрит на снимок, а не угадывает анатомию: внутри областей она даёт AUC 0.88–0.95, правило «позвоночник значит нарушение» — ровно 0.50. Числа считаются на всём наборе, включая обучающие снимки, поэтому смещены вверх и отвечают на вопрос «есть ли вклад содержимого», а не «каково качество на новых данных».
9. Ограничения
- Разметка унаследована от исследования. Таблица оценивает исследование, а не снимок; перенос однозначен, потому что область встречается один раз, но исходная оценка всё равно не поштучная.
- Мало данных: 251 снимок, 76 нарушений. Интервалы широкие.
- Эталон — та же таблица. Независимой истины нет; вариант, обучавшийся на таблице, в сравнении в выигрышном положении.
- Тип нарушения — эвристика, а не вывод модели: 5 снимков имеют только
unspecified, у остальных тип приходит из критериев таблицы. - Три снимка без экспертной оценки размечены по пометке в имени файла и
помечены
filename_fallback. - Сторона бедра в 7 исследованиях не проверяема: теги латеральности пусты.
- Корректность областей интереса наследуется из таблицы: разметки ROI в DICOM нет, сравнить её напрямую не с чем.
- Пометки в именах файлов спорят с таблицей в 62 случаях из 251. На метку
это не влияет (правило
table), но означает, что один из двух источников ошибается почти в четверти набора. Разбирать их поштучно можно в/label; для выбора правила измерения в §8 такие снимки не использовались. - Поштучной разметки всё ещё нет. Интерфейс
/label(§10) её даёт, но им ещё не пользовались: пока набор размечен на уровне исследования.
10. Ручная разметка: интерфейс /label
Поштучной экспертной оценки снимков в наборе нет — это ограничение №1, и автоматически его не закрыть: локальная vision-модель оказалась непригодна (§11), а экспертная таблица описывает исследование. Поэтому в сервисе есть интерфейс ручной разметки — раздел 2.6 задания прямо просит «автоматическую коррекцию разметки с возможностью подтверждения специалистом».
./run.sh serve # http://localhost:8000/label
Что он делает:
- показывает снимок целиком (PNG через
/api/v1/labeling/image) без наложений, чтобы разметчик судил по изображению, а не по подсказке алгоритма; - отдаёт список снимков с текущей меткой и её источником (
table,filenameилиmanual), причём снимки с расхождением метки и пометки в имени файла идут первыми — именно там один из источников ошибается (см. §9, п. 8); - сохраняет вердикт: анатомическая область, «годное / нарушение», тип нарушения из
violations.pyи комментарий. Тип нарушения проверяется на совместимость с областью (ротация — критерий бедра), у качественного снимка типа быть не может, а опечатка в коде не превращается молча вunspecified; - пишет вердикты в
labels/manual_labels.csv. Формат тот же, что у построенной разметки, поэтому файл читаетсяload_labels_csvи принимается обучением как--labels-csv; - выгружает
scope=all— весь набор с наложенными ручными вердиктами (готовый источник меток для./run.sh train) — илиscope=reviewed— только разобранные снимки, чтобы сверить их с построенной разметкой.
Оценка модели в интерфейсе намеренно не показывается: разметчик, видя подсказку, соглашался бы с ней, и поштучная разметка теряла бы ценность независимого суждения. Прогресс по областям и число расхождений показаны, чтобы работу можно было вести частями и прерывать.
Горячие клавиши: g — годное, b — нарушение, Enter — сохранить и перейти к
следующему, d — снять вердикт, j/k — навигация по списку.
Инструмент не заменяет эксперта: он только фиксирует суждение специалиста в формате, который пайплайн уже умеет читать.
Передача врачу: автономный пакет
/label требует запущенного сервиса и Python, а размечать должен врач — обычно на
своей машине, вне сети и без установки чего-либо. Поэтому тот же сценарий
собирается в один HTML-файл со встроенными снимками (src/dxa/review_pack.py):
python -m src.dxa.review_pack --out review/doctor_review.html # 251 снимок, ~7 МБ
python -m src.dxa.review_pack --merge review/doctor.csv \
--out labels/labels_images_reviewed.csv # наложить вердикты врача
Страница не делает ни одного сетевого запроса (проверяется тестом), вердикты
хранит браузер, выгрузка — CSV в формате manual_labels.csv с дополнительной
колонкой pack_id (отпечаток набора: по нему видно, что файл вернулся из того же
пакета). Модель в пакет не попадает: если показать разметчику оценку алгоритма,
он будет с ней соглашаться, и независимого суждения не получится.
Что стоит размечать. Порядок в пакете и в интерфейсе — как в §7: сперва 62 снимка, где метка разметки расходится с пометкой в имени файла (там ошибается один из двух источников). Но одних расхождений мало: они отобраны по признаку, который сам может быть смещён. Чтобы получить независимую оценку качества, нужен ещё случайный подсчёт — если врач разметит, например, случайные 50 снимков из 251, по ним можно будет измерить ROC-AUC и F1 модели на человеческом суждении, а не на той же экспертной таблице, из которой выведена разметка (ограничение 3 в §9). Такой замер в проекте ещё не делался: ни один снимок пока не размечен поштучно.
11. Отрицательный результат: локальная vision-модель
Планировалась визуальная разметка локальной vision-моделью (9 млрд параметров, офлайн), чтобы не зависеть от таблицы. На калибровке по 14 снимкам, из которых 8 заведомо с нарушениями, модель вынесла «непригоден» всем 14, включая все качественные, с шаблонными формулировками и выдуманными имплантами. Разделяющая способность — на уровне случайной, поэтому как разметчик модель непригодна.
Вывод, который стоит зафиксировать: разделяющую способность инструмента нужно
проверять до того, как строить на нём пайплайн. Инструменты рендера снимков и
контактных листов остались в src/dxa/render.py — они полезны для выборочной
ручной проверки.
12. Воспроизведение
./run.sh label # разметка по экспертной таблице
./run.sh rename # имена файлов (план; --apply)
./run.sh split && ./run.sh compare # выбор правила метки, 5 seed'ов
python -m src.dxa.excel_labels --label-rule union --out-name labels_images_union
python -m src.dxa.render --by-region --out dataset_hack/_preview
13. Что дальше
- Поштучная разметка снимков специалистом через
/label(§10) — снимет ограничение №1 и позволит перемерить качество на независимом суждении. - Мультилейбл по типам нарушений вместо эвристики: в интерфейсе тип уже проставляется вручную, но модель его не предсказывает.
- Больше исследований (500+), чтобы сузить интервалы.
- Калибровка порога определения области под конкретное оборудование.