Разборы

Разберём вашу задачу

Опишите её в двух-трёх предложениях. Я отвечу, что проверить первым и нужен ли здесь ИИ.

Написать в Telegram →
Материал Выберите статью
9 минут
Computer Vision

Почему одной модели недостаточно: как устроен поиск нарушений благоустройства по фотографии

От VLM-прототипа к fail-closed системе: quality, relevance и viewpoint gates, task-aware обучение, blind acceptance и CPU-инференс.

Обложка статьи «Почему одной модели недостаточно: как устроен поиск нарушений благоустройства по фотографии»

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

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

Я начал проект с Vision-Language Model. По фотографии она проходила пункты формализованного чек-листа и возвращала структурированный JSON: выполнено, нарушено или невозможно определить. Такой прототип быстро показал, какие требования вообще наблюдаемы через камеру. Он же заставил ввести полезное состояние null. Если объект отсутствует в кадре или ракурс ничего не доказывает, система не должна сочинять ответ.

Для исследования этого хватало. Производственный контур потребовал другой архитектуры.

VLM помог поставить задачу

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

Например, яму в покрытии можно увидеть на обычном кадре. Работоспособность оборудования или устойчивый запах по нему не определить. Состояние объекта ночью нельзя честно оценить по дневной фотографии.

Этот этап дал карту наблюдаемости и язык результата. Вместо универсального «модель уверена» появились три исхода: норма, нарушение и недостаточно данных.

Дальше задача сузилась до повторяемых категорий благоустройства. Среди них дефекты покрытия, складирование материалов, защита зелёных насаждений, состояние ландшафтных объектов и бортового камня. Для каждой категории появился специализированный бинарный классификатор, собственный размер входа, preprocessing и пороги.

Ещё одна категория осталась выключенной. Для неё не было достаточных данных. В production это нормальный результат. Отсутствие модели безопаснее модели, обученной на фантазии.

Решение начинается до классификатора

Бинарная модель живёт в закрытом мире. Она умеет различать норму и нарушение среди кадров, похожих на обучающую выборку. Если отправить ей фотографию комнаты, собаки или другого дорожного объекта, она всё равно выберет один из двух классов.

Поэтому производственный пайплайн выглядит так:

quality → relevance → viewpoint → classifier → policy

Fail-closed пайплайн: quality, relevance, viewpoint, classifier и policy с переводом неопределённых случаев на ручную проверку
Fail-closed пайплайн: quality, relevance, viewpoint, classifier и policy с переводом неопределённых случаев на ручную проверку

Каждый этап отвечает на свой вопрос.

Quality guard проверяет разрешение, размытие и яркость. Плохой снимок не удаляется и не получает случайный ответ. Он помечается как небезопасный для автоматического действия.

Relevance gate проверяет, присутствует ли в кадре объект выбранной категории. Для одного из сложных сценариев я обучил отдельную трёхклассовую модель: допустимая норма, нарушение и нерелевантное фото. Между уверенно релевантным и уверенно нерелевантным состоянием оставлена серая зона. Она ведёт к оператору.

Viewpoint gate нужен для заданий «до/после». Система должна убедиться, что два кадра показывают сопоставимую сцену. В исследовательском контуре используются локальные признаки и геометрическое сопоставление XFeat/LighterGlue. Недостаток совпадений блокирует автоматическое закрытие.

Только после этих проверок запускается классификатор нарушения. Последний слой, production policy, переводит вероятности и статусы gates в разрешённое бизнес-действие.

У пайплайна есть важное свойство. Ошибка или недоступность защитного модуля дают manual review. Автоматическое решение требует полного набора доказательств.

Почему одиночная фотография теряет контекст

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

Для такого формата я добавил task-aware правило. В группе фотография с минимальной вероятностью нарушения считается нормой, остальные относятся к нарушению. Истинные метки в момент решения не используются. Для неполного задания остаётся обычный порог классификатора.

Это простое правило заметно изменило результат на расширенной тестовой выборке. В ней было 1 227 фотографий из 621 задания. Совокупная balanced accuracy достигла 97,89%. Минимальное значение среди пяти категорий составило 96,71%. Осталось 26 ошибочных кадров.

Balanced accuracy здесь равна среднему между recall нарушения и specificity нормы. Она полезнее обычной accuracy при несбалансированных классах.

У цифры 97,89% есть ограничение. Один из вариантов модели выбирался после сравнения на текущем holdout. Поэтому результат имеет статус development. Он подтверждает полезность структуры задания, но ещё не разрешает замену production-моделей. Для этого нужен новый слепой набор и shadow-прогон.

Как не дать модели подсмотреть ответ

В задачах «до/после» утечка возникает легко. Два почти одинаковых кадра одного задания могут попасть в train и test. Модель узнает место, сезон, геометку или интерфейсную плашку. Метрика вырастет, а способность находить нарушение останется прежней.

Я разделяю данные целыми заданиями. Для нового домена в train вошли 4 901 изображение из 2 482 задач, в расширенный test вошли 1 227 изображений из 621 задачи. Пересечений по task ID и SHA между ними нет.

Точные дубликаты удаляются между train, validation и diagnostic. Для слепой приёмки создан immutable lock. Он фиксирует веса, пороги, evaluator, task-aware правило и критерии до получения новой поставки. Инвентарь запрещает повторное использование 30 653 уже виденных SHA и 3 132 task ID.

Порог выбирается только на validation. Исторический test остаётся diagnostic, потому что на него уже смотрели в предыдущих исследованиях. Это неприятное ограничение, зато честное.

Ещё один источник shortcut обнаружился в самих изображениях. Один классификатор реагировал на верхнюю плашку с датой вместо дефекта покрытия. Обрезка верхней части кадра убрала сигнал. Occlusion-карты после переобучения показали, что внимание перешло к повреждённой области.

Сильная метрика обязана пережить плохие данные

Внутренний holdout неизбежно похож на рабочий домен. Поэтому я отдельно собрал 200 ранее не виденных интернет-фотографий для двух категорий. Отбор был детерминированным до просмотра изображений. Пересечений с прежними SHA не было.

Результат оказался слабым. Balanced accuracy составила 54% и 70%.

Такой тест легко «исправить» после ручного просмотра. Из 76 расхождений 25 оказались подтверждёнными ошибками модели, 6 пограничными случаями, ещё 45 возникли из-за несовпадения масштаба или таксономии внешней разметки с операционным определением нарушения. Например, маленький дефект на общем плане и локальный мусор формально размечены, но не соответствуют рабочему критерию.

Исходные метрики я не пересчитывал. Набор остался внешним regression-test.

Этот эпизод полезнее очередного красивого процента. Он показал две разные проблемы. Первая находится в модели и доменном сдвиге. Вторая находится в спецификации класса. Без точного определения нарушения невозможно понять, что именно измеряет benchmark.

Перенос на CPU тоже требует доказательств

Обучение шло в PyTorch, а производственный runtime должен работать локально на CPU без Torch и облачной зависимости. Модели экспортированы в OpenVINO FP32.

Первый экспорт строгую проверку не прошёл. Максимальная разница вероятности достигла 0,083, на 6 263 кадрах появились две смены вердикта.

Причина оказалась в двух деталях. Код resize округлял длинную сторону, тогда как reference preprocessing усекал значение. Center crop на части изображений сдвигался на один пиксель. Вторая проблема была ниже уровнем: CPU plugin исполнял FP32-модель с FP16 precision hint. Принудительный FP32 на худшем кадре снизил расхождение примерно с 0,052 до 0,00000465.

После исправления exact production path проверен на 7 748 кадрах пяти категорий. Максимальная разница вероятности составила 0,00001159. Смен вердикта было ноль. Смен итогового действия тоже ноль.

Release manifest фиксирует SHA весов, XML, BIN, metadata, parity-report и конфигурации preprocessing. Если меняется crop, размер входа или порог, runtime перестаёт считать модель готовой. Одного совпадения файлов модели недостаточно.

Быстрый inference не равен готовому сервису

Полный парный поток на Apple M3 Pro CPU включал quality checks, проверку ракурса, два FP32 inference и policy. На ста повторах p50 составил 47,899 мс, p95 51,002 мс, p99 82,642 мс.

Ключевые метрики проекта: 97,89% balanced accuracy на development-выборке, 7 748 кадров parity-проверки, нулевой action drift и p95 51,002 мс на CPU
Ключевые метрики проекта: 97,89% balanced accuracy на development-выборке, 7 748 кадров parity-проверки, нулевой action drift и p95 51,002 мс на CPU

Это хороший запас относительно целевого лимита в две секунды на фотографию. Я всё равно не называю его production SLA. В замер не входили сеть, авторизация, удалённая загрузка изображения, хранилище и конкурентная нагрузка. Целевой сервер должен пройти отдельный end-to-end тест.

На уровне сервиса добавлены ограничения размера и числа пикселей, безопасная загрузка внешних изображений, защита от SSRF, дедупликация запросов и событий, retention и структурированные журналы решений. Эти детали редко попадают в демонстрацию модели. Именно они определяют, можно ли оставить сервис без присмотра.

Автоматизация включается по доказательствам

У системы три маршрута: автоматическое действие, ручная проверка и запрос нового снимка. Текущее состояние всех обученных категорий называется shadow. Модели считают вероятности и предлагают решения, но не меняют внешний статус автоматически.

Для включения действия недостаточно одного YAML-флага. Есть общий runtime gate, отдельный gate для пар и отдельное разрешение на автоматическое закрытие. Production policy проверяет lifecycle категории, quality flags, relevance, ракурс и action-specific ограничения.

Здесь полезно смотреть на доверительные интервалы. В одном исследовательском варианте точечная precision автоматического создания задачи достигла 100%. Нижняя граница Wilson была около 97,4%. Для автоматического закрытия NPV составила 98,24%, а нижняя граница упала примерно до 94,9% при требовании 99,5%.

Модель выглядела сильной. Доказательств для безопасного закрытия не хватило. Функция осталась выключенной.

Что получилось в итоге

Проект начинался как VLM-аудитор с текстовым чек-листом. Сейчас это гибридная система компьютерного зрения с пятью специализированными классификаторами, явными quality и relevance gates, геометрической проверкой пар, task-aware логикой, leakage-safe обучением, immutable приёмочными артефактами и локальным OpenVINO runtime.

Самая сложная часть находится вокруг нейросети. Нужно определить, имеет ли система право интерпретировать кадр, совпадает ли сцена, не протекли ли данные, сохранился ли вердикт после экспорта и достаточно ли статистических доказательств для конкретного действия.

Хорошая модель отвечает на вопрос о пикселях.

Хорошая система знает, когда этого ответа недостаточно.

Ваша реакция

Как вам разбор?