ИИ‑Стоматолог
Как я обучал YOLO искать патологии на панорамных снимках и обнаружил проблему в датасете
За месяц я собрал MVP системы для анализа панорамных рентгенограмм. Идея была простой: врач загружает снимок, а модель выделяет области, которые стоит изучить внимательнее.
Я не ставил задачу заменить стоматолога. На этом этапе речь шла только о вспомогательном инструменте, который может работать как второе мнение и подсвечивать подозрительные участки на ОПТГ.
В процессе эксперимента выяснилось, что главная проблема была не в выборе модели и не в мощности видеокарты. В датасете оказались изображения, которые вообще не должны были участвовать в обучении. Из‑за этого модель начала выдавать детекции на цветных фотографиях полости рта.
Сначала это выглядело как странная ошибка. Потом стало понятно, что именно такие случаи лучше всего показывают ограничения системы.
Что должна была делать модель
Панорамный снимок удобен тем, что на нём видны обе челюсти и большая часть зубного ряда. Но анализировать его не всегда просто:
изображение двумерное;
структуры перекрывают друг друга;
на снимках встречаются артефакты;
пломбы, коронки и металлические конструкции меняют вид отдельных участков;
небольшие поражения могут быть плохо различимы.
В конце смены врач также может пропустить деталь, которая при свежем взгляде была бы заметнее. Поэтому я решил проверить, насколько компактная модель объектной детекции сможет помочь с предварительным анализом.
В первой версии было четыре класса:
Caries— кариес;Deep Caries— глубокий кариес;Impacted— ретинированные зубы;Periapical Lesion— периапикальные поражения.
На выходе модель должна была возвращать исходный снимок с рамками вокруг найденных областей и названием класса.
Датасет и обучение
Для эксперимента я собрал собственный архив анонимизированных изображений. Всего получилось около 18 тысяч файлов из разных источников.
Разметка выполнялась вручную. Её проверяли рентгенологи и стоматологи. Разрешение на использование данных было получено.
Модель обучалась 100 эпох. Для обучения я использовал RunPod с Tesla A100 на 80 ГБ. Проверку готовых весов проводил в Google Colab на Tesla T4.
В качестве модели взял компактную YOLO26n. Мне была важна не только точность, но и скорость инференса: в дальнейшем результат хотелось показывать через веб‑сервис, а не запускать только на отдельной исследовательской машине.
Почему смотрел на recall
В медицинском проекте одной общей точности недостаточно. Если патологий мало по сравнению с нормальными участками, модель может показать хорошую среднюю метрику и при этом пропускать значительную часть нужных объектов.
Поэтому основной метрикой я выбрал полноту, или recall. Она отвечает на вопрос:
Какую долю размеченных патологий модель смогла обнаружить?
Для предварительного анализа пропуск особенно критичен. Ложное срабатывание означает, что врачу придётся дополнительно проверить участок. Пропущенная область может вообще не попасть в поле зрения.
На тестовой выборке получились такие значения:
Класс | Recall |
|---|---|
| 0,966 |
| 0,837 |
| 0,768 |
| 0,581 |
Лучший результат получился для ретинированных зубов. Наиболее сложным оказался обычный кариес: небольшие изменения на двумерном панорамном изображении часто трудно отличить от артефактов и особенностей снимка.
Отдельно уточню: эти значения получены на тестовой выборке моего эксперимента. Это не клиническая валидация и не доказательство того, что модель готова самостоятельно использоваться для постановки диагноза.
Первые результаты
На части снимков модель корректно выделяла ретинированные зубы, глубокий кариес и периапикальные поражения.

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

Это ожидаемое ограничение для датасета, в котором недостаточно похожих примеров. Модель не знает, что перед ней ортодонтическая конструкция. Она видит набор пикселей, который может сильно отличаться от тех, на которых происходило обучение.
Для следующей версии я бы отдельно собрал снимки с:
брекетами;
шинирующими конструкциями;
коронками;
имплантами;
крупными пломбами;
другими источниками засветов.
Ошибка в датасете
Самая интересная ситуация возникла из‑за ошибки при сборке архива.
В папку с чёрно‑белыми рентгеновскими изображениями случайно попали обычные цветные фотографии полости рта. Они не должны были использоваться для обучения модели, которая предназначалась для анализа ОПТГ.
Я заметил это во время тестирования и решил проверить, как модель поведёт себя на цветной фотографии.
Она выделила область мягких тканей и присвоила ей класс Deep Caries. При визуальном просмотре участок напоминал язвенное поражение.\
Здесь важно не делать слишком сильный вывод. Модель не нашла стоматит. У неё не было такого класса, соответствующей разметки и отдельного теста на язвенных поражениях.
Произошло другое: на незнакомом изображении модель всё равно попыталась найти один из известных ей паттернов и выбрала ближайший доступный класс.
С технической точки зрения это пример работы вне распределения данных. С точки зрения будущего продукта это проблема. Система должна уметь определить, что ей передали не панорамную рентгенограмму, и отказаться от анализа.
Цветные фотографии после ошибки
На некоторых цветных фотографиях модель также выдавала детекции, которые визуально совпадали с областями кариеса.
Нельзя считать это доказательством того, что модель научилась диагностировать кариес по фотографии. Скорее всего, результат связан с ошибкой в составе обучающих данных и недостаточной проверкой типа входного изображения.
После обнаружения таких файлов правильным следующим шагом будет:
удалить цветные фотографии из рентгенологической выборки;
проверить train, validation и test на повторное смешение;
найти дубликаты;
повторить обучение;
сравнить метрики до и после очистки;
отдельно проверить модель на неподходящих форматах данных.
Быстрый интерфейс для демонстрации
Для демонстрации я не стал сразу поднимать полноценный backend. Вместо этого сделал Telegram‑бота, который запускался в Google Colab.
Модель лежала на Google Drive. Пользователь отправлял боту изображение, после чего оно передавалось в YOLO. Бот возвращал снимок с нанесёнными рамками.
Упрощённая версия обработчика выглядела так:
import os
from io import BytesIO
import cv2
import telebot
from PIL import Image
from ultralytics import YOLO
MODEL_PATH = "/content/drive/MyDrive/best.pt"
BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
model = YOLO(MODEL_PATH)
bot = telebot.TeleBot(BOT_TOKEN)
@bot.message_handler(content_types=["photo"])
def handle_photo(message):
bot.send_message(
message.chat.id,
"Анализирую изображение...",
)
file_info = bot.get_file(
message.photo[-1].file_id,
)
downloaded_file = bot.download_file(
file_info.file_path,
)
with open("temp.jpg", "wb") as file:
file.write(downloaded_file)
results = model.predict(
source="temp.jpg",
conf=0.50,
verbose=False,
)
plotted = results[0].plot(line_width=2)
image = Image.fromarray(
cv2.cvtColor(
plotted,
cv2.COLOR_BGR2RGB,
),
)
buffer = BytesIO()
buffer.name = "result.jpeg"
image.save(buffer, "JPEG")
buffer.seek(0)
bot.send_photo(
message.chat.id,
photo=buffer,
caption="Анализ завершён.",
)
bot.infinity_polling()Для демонстрации этого оказалось достаточно. Пользователь отправлял снимок с телефона и примерно через две секунды получал изображение с результатом детекции.
Для реального сервиса такой вариант не подходит. Google Colab может остановить сессию, а фиксированное имя temp.jpg создаёт конфликт при одновременных запросах.
В рабочей версии понадобятся:
отдельная временная папка для каждого запроса;
проверка формата и размера файла;
фильтр, определяющий тип изображения;
удаление файлов после обработки;
очередь заданий;
защищённое хранение токена;
журналирование ошибок.
Что нужно до внедрения в клинику
Сейчас это исследовательский MVP. Для использования в клинике одной демонстрации и одной тестовой выборки недостаточно.
Перед внедрением нужно проверить:
модель на независимых данных;
снимки с других аппаратов;
изображения из других клиник;
работу на разных разрешениях;
устойчивость к металлическим конструкциям;
чувствительность и специфичность;
количество ложноположительных результатов;
количество пропущенных патологий;
согласованность результатов с врачами.
Также нужно отдельно решить вопросы хранения и обработки медицинских изображений.
В интерфейсе должно быть ясно указано, что результат модели не является диагнозом. Окончательное решение остаётся за врачом.
Что планирую дальше
Следующим этапом я вижу четыре задачи.
Очистить датасет
Нужно отделить рентгенограммы от обычных фотографий и повторно проверить структуру всех выборок.
Кроме того, стоит проверить:
дубликаты;
качество разметки;
распределение классов;
изображения одного пациента в разных подвыборках;
утечку данных между обучением и тестированием.
Повторить обучение
После очистки необходимо заново обучить модель и сравнить результаты.
Если метрики изменятся, это покажет, насколько сильно ошибочные данные влияли на обучение.
Проверить переносимость
Нужно протестировать модель на снимках из другого источника. Это поможет понять, не запомнила ли она особенности конкретного аппарата или архива. Я это уже сделал проверив на снимках из интернета модель работает корректно,но нужно больше российских истчоников
Сделать веб‑сервис
Вместо временного Telegram‑бота следующим интерфейсом должен стать веб‑сервис для рабочего места врача.
Он будет принимать ОПТГ, запускать инференс и показывать найденные области. При этом система должна работать как вспомогательный инструмент, а не как автоматический диагност.
Итоги
За месяц я собрал MVP для поиска четырёх классов стоматологических патологий на панорамных рентгенограммах.
Модель YOLO26n обучалась на собственном архиве примерно из 18 тысяч анонимизированных изображений. Разметку проверяли стоматологи и рентгенологи. Для обучения использовалась Tesla A100, а демонстрационный инференс запускался на Tesla T4 в Google Colab.
Лучший результат модель показала на классе Impacted: recall составил 0,966. Наиболее сложным оказался обычный кариес, для которого recall был заметно ниже.
Главный урок проекта связан не с самой высокой метрикой, а с ошибкой в данных. Цветные фотографии, случайно попавшие в архив, показали, что модель может выдавать уверенные детекции на неподходящих изображениях.
Это не означает, что модель научилась находить стоматит или диагностировать заболевания по обычной фотографии. Это показывает необходимость фильтрации входных данных и отдельной проверки работы вне распределения.
Сейчас систему рано называть готовым медицинским продуктом. Но эксперимент показал, что компактную модель можно использовать как основу для ассистента, который подсвечивает врачу подозрительные области на ОПТГ. Следующий шаг — очистить датасет, провести независимую валидацию и только после этого оценивать возможность интеграции в клинический процесс.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.