# Разметка датасета и выбор правила метки Документ описывает, откуда берутся метки снимков, как проверялось правило разметки и какие результаты из этого следуют. Числа проверяемы: ссылки на источники приведены рядом. ## 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 | | Склейка дублей | по хешу пиксельных данных | 544 файла — это 252 уникальных снимка | | Область снимка | голосование по именам файлов группы | один снимок назван и как позвоночник, и как бедро; при равенстве голосов область остаётся неопределённой (такой снимок один) | | Вердикт | оценка области переносится на её снимок | **каждая область встречается в исследовании ровно один раз**, поэтому не нужно решать, какой из нескольких снимков «плохой» | | Сторона бедра | при единственном снимке бедра берётся единственный заполненный столбец | в 71 из 72 исследований с двумя бёдрами столбцы совпадают с именами файлов; в 7 исследованиях с одним снимком заполнена противоположная сторона. Факт переноса фиксируется флагом `laterality_mirrored`; теги `Laterality` в DICOM пусты | | Тип нарушения | только из структурированных критериев | комментарии («сколиоз», «эндопротезирование ТБС») сохранены дословно: перекладывать свободный текст в код — догадка | ## 4. Правило метки и почему оно такое Метка могла строиться двумя способами: только из таблицы или с добавлением пометок, которые вручную проставлялись в именах файлов (суффикс `_bad`). Пометки в именах оказались ненадёжными: они расходились с оценкой эксперта в **15 случаях из 252**. Выбор сделан измерением, а не по вкусу. **Постановка.** Разбиение по исследованиям зафиксировано один раз, оба варианта обучены пятью 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.6764** [0.6309, 0.7218] | 0.6199 [0.5840, 0.6559] | | PR-AUC | **0.4759** [0.4141, 0.5377] | 0.4046 [0.3702, 0.4391] | | F1 | **0.5676** [0.5270, 0.6082] | 0.5426 [0.5073, 0.5778] | | Recall | 0.7000 | 0.8625 | | Precision | 0.4857 | 0.4043 | Парная разница («только таблица» − «с суффиксами»): | Метрика | Δ, среднее [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] | `+++++` | | Recall | −0.1625 [−0.2715, −0.0535] | `--0--` | **Решение: принято правило «только экспертная таблица».** Дополнительные пометки из имён файлов ухудшали согласие модели с экспертом на невиданных исследованиях: вариант с ними чаще срабатывал (recall 0.86), но за счёт точности, а по беспороговым метрикам проигрывал на всех пяти seed'ах. Оговорка: эталон — та же экспертная таблица, поэтому вариант, обучавшийся непосредственно на ней, находится в выигрышном положении. Значимо здесь другое: добавление ненадёжных пометок **снижает** согласие с экспертом, что и служит аргументом против них. ## 5. Словарь типов нарушений | Код | Подпись | Область | Источник | |---|---|---|---| | `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. Словарь один на всё решение (`src/dxa/violations.py`): коды используют инференс, отчёт DICOM SR и веб-интерфейс, подписи отдаёт сервер, копий в JavaScript нет. ## 6. Результат разметки `labels/labels_images.csv` (и XLSX) — по одной строке на уникальный снимок: | | позвоночник | бедро R | бедро L | неопред. | всего | |---|---|---|---|---|---| | качественных | 66 | 58 | 51 | 0 | 175 | | с нарушением | 33 | 21 | 22 | 1 | 77 | | **итого** | **99** | **79** | **73** | **1** | **252** | Помимо метки в 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` (эталон: только снимки с экспертной оценкой, 249 строк) и `split_expert_seed42.json` (зафиксированное разбиение). ## 7. Гигиена данных: имена файлов Имена проставлялись вручную и разошлись: `spine_1` и `spine_01`, `Spine_01`, `r_spine_03`, `r_hip03`, `r_hop_02` (опечатка), `spine-1`. Они приведены к виду `<область>_[_good|_bad].dcm` инструментом `src/dxa/rename_files.py`; переименовано 344 файла из 548, карта отката — `labels/rename_map.csv`. Переименование сделано **после** того, как разметка и метрики были посчитаны, и проверено, что оно на них не влияет: набор из 252 пиксельных групп идентичен до и после, разметка не изменилась ни в одной строке. Суффиксы `_good`/`_bad` сохранены как были и в метках не участвуют — только как диагностический столбец. ## 8. Оценка качества модели Разбиение по исследованиям (по умолчанию seed 42): обучение 199 снимков / 81 исследование, валидация 53 снимка / 19 исследований, 16 нарушений. | Метрика | Значение | Как получено | |---|---|---| | ROC-AUC | **0.6764** [0.6309, 0.7218] | 5 seed'ов на фиксированном разбиении, эталон — вердикт эксперта | | PR-AUC | 0.4759 [0.4141, 0.5377] | там же | | F1 | 0.5676 [0.5270, 0.6082] | там же; порог подобран по F1 на валидации, поэтому смещён вверх | | ROC-AUC по областям | позвоночник 0.943, бедро R 0.576, бедро L 0.550 | рабочий чекпоинт, его собственная валидация | Рабочий чекпоинт — обычный прогон с seed по умолчанию (эпоха 39, порог логита −0.4930 → вероятность 0.379), его собственная валидационная ROC-AUC 0.6706 близка к среднему по seed'ам, то есть результат не отобран по удачности. Проверка, что модель смотрит на снимок, а не угадывает анатомию: внутри областей она даёт AUC 0.85–0.93, правило «позвоночник значит нарушение» — ровно 0.50. Числа считаются на всём наборе, включая обучающие снимки, поэтому смещены вверх и отвечают на вопрос «есть ли вклад содержимого», а не «каково качество на новых данных». ## 9. Ограничения 1. **Разметка унаследована от исследования.** Таблица оценивает исследование, а не снимок; перенос однозначен, потому что область встречается один раз, но исходная оценка всё равно не поштучная. 2. **Мало данных:** 252 снимка, 77 нарушений. Интервалы широкие. 3. **Эталон — та же таблица.** Независимой истины нет; вариант, обучавшийся на таблице, в сравнении в выигрышном положении. 4. **Тип нарушения — эвристика**, а не вывод модели: 5 снимков имеют только `unspecified`, у остальных тип приходит из критериев таблицы. 5. **Три снимка без экспертной оценки** размечены по пометке в имени файла и помечены `filename_fallback`. 6. **Сторона бедра в 7 исследованиях не проверяема:** теги латеральности пусты. 7. **Корректность областей интереса наследуется из таблицы:** разметки ROI в DICOM нет, сравнить её напрямую не с чем. ## 10. Отрицательный результат: локальная vision-модель Планировалась визуальная разметка локальной vision-моделью (9 млрд параметров, офлайн), чтобы не зависеть от таблицы. На калибровке по 14 снимкам, из которых 8 заведомо с нарушениями, модель вынесла «непригоден» всем 14, включая все качественные, с шаблонными формулировками и выдуманными имплантами. Разделяющая способность — на уровне случайной, поэтому как разметчик модель непригодна. Вывод, который стоит зафиксировать: разделяющую способность инструмента нужно проверять **до** того, как строить на нём пайплайн. Инструменты рендера снимков и контактных листов остались в `src/dxa/render.py` — они полезны для выборочной ручной проверки. ## 11. Воспроизведение ```bash ./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 ``` ## 12. Что дальше - Поштучная разметка снимков специалистом — снимет ограничение №1. - Мультилейбл по типам нарушений вместо эвристики. - Больше исследований (500+), чтобы сузить интервалы. - Калибровка порога определения области под конкретное оборудование.