Все

Как декомпозиция повышает точность распознавания текста: опыт с фотографиями СТС

2025-05-14 15:00 Статьи machine learning
Привет! Меня зовут Наталия Вареник, я DS-инженер в Авито, занимаюсь моделями распознавания изображений. Расскажу про один из наших проектов — пайплайн для распознавания номеров с фотографии свидетельства транспортного средства (СТС). В статье описала особенности задачи и рассказала, как мы решали её с помощью декомпозиции.
Материал будет полезен начинающим и мидл-DS-инженерам, которые хотят узнать больше про декомпозицию задачи на этапах разметки и построения моделей.
А еще материал стоит прочитать тем, кто работает с доменами, где нужно иметь дело с задачами распознавания информации с документов — наш подход прекрасно переносится на другие категории. В целом рекомендую статью всем, кто интересуется компьютерным зрением и его применимостью в разных сферах.

Суть задачи

Пользователям сложно проходить проверки на Авито — мы требуем много информации с документов, в которой легко ошибиться, если вводить вручную. Мы следим за качеством контента на площадке, поэтому на этапе подачи объявления просим много подтверждённых данных.
Так, чтобы разместить объявление о продаже машины на Авито, мы просим продавцов добавлять в объявление фото машины, VIN и госномер.
Поля на подаче объявления, куда пользователи вводят данные об авто
Все данные, которые добавляют пользователи, мы проверяем на соответствие.
VIN и госномер — это длинные последовательности символов, в которых легко ошибиться при ручном вводе. Но эти данные важны, так как, например, по VIN-номеру мы смотрим историю автомобиля, а потом сверяем его с госномером.
Часть пользователей уставали заполнять форму отправки объявления. Часть заполняли всё, но объявления не проходили модерацию из-за ошибок в VIN или госномерах. Из всех отказов в публикации объявлений 8% мы отклоняли именно по этой причине.
Многие пользователи обращались в поддержку, когда заполнить данные не получалось, и нагрузка на сотрудников саппорта росла.
Мы хотели найти решение, чтобы повысить процент объявлений, которые успешно проходят модерацию, упростить процесс ввода данных для пользователей и снизить нагрузку на саппорт.
Этим решением стала модель, которая автоматически заполняет поля для VIN и госномера по фотографии свидетельства транспортного средства — СТС.

Проанализировали задачу и сформулировали требования к модели

Было четыре основных требования:
Высокая точность. На основе данных про авто принимаются важные решения, поэтому ради точности мы были готовы пожертвовать ресурсами.
Переносимость на другие домены — чтобы мы или коллеги в дальнейшем могли решать запросы на распознавание данных с фото по уже проработанному пайплайну.
Масштабируемость под продовую нагрузку — чтобы мы легко могли увеличить пропускную способность и скорость обработки, и модель не легла под большим потоком пользователей. Например, это будет полезно, если другие команды тоже начнут использовать нашу модель для распознавания данных.
Устойчивость к вариативности данных — об этом расскажу дальше.

Что мы знаем о данных

Для распознавания данных мы решили взять свидетельство транспортного средства (СТС). Это обязательный документ для автовладельцев, который подтверждает, что машина зарегистрирована и может законно находиться на дороге.
Выглядит это так:
Пример свидетельства транспортного средства с указанием нужных нам полей — госномер, VIN, номер кузова
Дисклеймер: все фотографии документов предоставили для статьи мои коллеги. Мы не публикуем персональные данные пользователей.
В процессе работы мы поняли, что разные СТС могут отличаться друг от друга. И из-за этого возникли некоторые сложности.
Первая сложность — в участках нанесения номеров. Хотя СТС — это документ с чёткой структурой, конкретные области с нужными номерами могут отличаться.
Есть ещё одна особенность — различия в VIN или идентификационном номере транспортного средства. У большинства машин — обычный VIN, который состоит из 17 символов и совпадает с номером кузова. Но у старых японских машин в графе VIN часто пишут слово «Отсутствует», а вместо него в качестве идентификатора используют номер кузова:
Так выглядит «японский» СТС без идентификационного номера
И хотя нам нужны только VIN и госномер, модель всё равно должна уметь распознавать ещё и номер кузова:
  • в случае с «обычным» СТС, номер кузова поможет точнее распознать VIN, если с нужной области корректно распознать не получилось;
  • в ситуации с «японским» СТС, мы будем использовать номер кузова вместо отсутствующего VIN.
У самих номеров тоже есть особенности и чёткая структура:
Характеристики и примеры разных типов данных — госномера, «обычного» и «японского» VIN

Начали с тестирования опенсорсных-решений

Перед разработкой своей модели мы попробовали поработать с тремя популярными end-to-end решениями, которые подходят под задачу, а после сравнили результаты.
Требования к решениям: точность > 95%, полнота > 90%. Оценку точности свели к бинарным кейсам: распознали / не распознали.
Библиотеки, которые мы использовали, с документацией на GitHub:
🔗 DocTR
🔗 EasyOCR
Сравнили результаты:
Лидером стал PaddleOCR, но даже это решение не вписывалось в требования. Мы разобрали ошибки и обнаружили, что модель:
  • пропускала нужные номера на этапе детекции;
  • допускала ошибки в одиночных символах;
  • делала ошибки на концах номеров из-за наложения другого текста или близкого соприкосновения;
  • склеивала два слова из строки в одно.
Пример распознавания текста с помощью PaddleOCR — слева фотография СТС, справа — текст, который распознала модель
После всех тестов мы решили не докручивать опенсорсное решение, а сделать свой лёгкий в использовании пайплайн под конкретную задачу.

Решили разработать своё решение и разбили его на 3 этапа: проверочные модели, детектор, OCR

Очень высокой точности распознавания мы добились с помощью декомпозиции. Это значит, что решение состоит не из одной модели, которая делает все задачи по распознаванию, а из нескольких моделей с узкой «зоной ответственности». При этом каждая из этих промежуточных моделей готовит данные для следующего этапа.
Пайплайн состоит из трёх этапов:
  • проверочные модели — проверяют исходную фотографию свидетельства и, если она некачественная, возвращают её пользователю с подсказками по улучшению. Так мы не будем плодить ошибки распознавания на некачественных данных и поможем автору объявления дойти до публикации;
  • детектор — выделяет и вырезает области с нужными номерами из исходных фотографий;
  • OCR — распознаёт номера.
Пайплайн модели распознавания данных по фотографии СТС

Сделали проверочные модели для анализа пользовательских снимков СТС

Первый шаг после того, как пользователь загрузил фотографию документа — проверить снимок с помощью классификаторов. Они определяют:
  • какой тип документа на фото — если это не СТС;
  • видно ли в кадре СТС полностью;
  • насколько далеко находится СТС на фото.
Во всех этих случаях, если фото не удовлетворяет нашим требованиям, мы отказываем в распознавании и даём пользователю подсказку.
Ещё определяем, под каким углом сфотографировали СТС. Если фото сделали под углом или с перспективой, исправляем до нормального положения. На этом этапе можно добавить дополнительные параметры проверки — например, размытость, тени и блики в важных местах.

Внедрили детектор для распознавания положения номеров на фото

Детектор мы обучали на собственной разметке — датасете из фотографий документов, где руками были выделены области с номерами.
Поскольку текст на самом документе может быть под углом, для выделения нужных областей мы использовали ориентированные четырёхугольники — так в области не попадёт лишний текст.
Разделили разметку на два проекта, чтобы проверить качество работы асессоров. В рамках первого просили выделить номера, во втором — просили проверить качество по критериям.
Два проекта с асессорами
Затем контролировали точность разметки во втором проекте. Для этого использовали голден — набор примеров, где мы знаем эталонные ответы. Эти примеры случайно подмешивали асессорам, после чего сравнивали эталонные ответы с теми, что дали асессоры. Считали долю правильных ответов и ошибок.
Таким образом мы оценивали качество работы как отдельных асессоров, так и разметки в целом.
Благодаря декомпозиции получилась очень точная разметка.
Для детекции использовали сегментационную модель U-Net, потому что она позволяла очень тонко выделить область с номером. Обучили модель на два класса: 1 — пиксель принадлежит маске одного из номеров, 0 — часть фона. На выходе получаем маску, которая накладывается на изображения и показывает, где расположены номера:
Фотографии СТС с масками, сделанными архитектурой U-Net
Для повышения точности провели аугментацию — добавляли на фотографии размытие, засветы, затемняли их. Это помогло получить более точные границы на размытых фотографиях и исключить разрезы маски из-за бликов на номерах.
Значение надписей на плашке в верхнем правом углу: plate — госномер, vin — вин, body — номер кузова
Мы получили улучшенный результат на данных с размытостью и засветами, так как модель видела это на обучении и училась, как работать в таком случае.
Эта модель хорошо работала на большинстве фотографий, но давала неточности на изображениях с большой перспективой, отдалённостью, или, если снимки были сделаны под углом. Мы пытались добавлять фотографии под углом в данные, но этого было недостаточно — маски всё равно искажались.
Добавили блок для выравнивания документа перед этапом детектирования. Если пользователь присылает фотографию под углом или с перспективой — мы поворачиваем её до нормального положения и корректируем перспективу.
Для выравнивания используем архитектуру RetinaNET — находим четыре координаты углов документа, по ним определяем границы, обрезаем фон и выравниваем.
Для коррекции перспективы применяем warpPerspective. Это функция в OpenCV Python, которая применяет аффинное преобразование к картинке, которое убирает перспективу.
Нам она нужна, чтобы убрать перспективу на фотографиях СТС, которые были сделаны не строго сверху:
На выходе получаем документ в нормальном положении с обрезанным фоном
Фотография до и после выравнивания с помощью RetinaNET

Использовали OCR для распознавания текста

На последнем этапе модель распознаёт номера на кусочках из исходной картинки, которые вырезали по маске из детектора. Для распознавания текста мы обучили свёрточно-рекуррентную архитектуру CRNN с CTC-декодером и датасетом из пар: «картинка + текст».
По маске с предыдущего этапа мы вырезаем области с номерами из фотографий и выравниваем их:
Обрезаем и выравниваем фотографию по маске от детектора
После распознавания текста номеров мы применили валидационные правила, чтобы проверить или скорректировать результаты. Это нужно для большей точности. Правила построили на основе знаний о структуре номеров.
Все этапы распознавания номеров на одной картинке

Результаты: попали в целевые метрики и получили показатели выше ожидаемых

Провели тесты нашей модели и смогли побить пороги, которые ставили ещё до разработки. Получили такие значения:
Также мы собрали данные по ошибкам после внедрения модели. На графике видно, что она не смогла распознать текст только у 8% фотографий. В остальных случаях модель либо распознала всё успешно, либо мы дали подсказки, как исправить ошибки, и она распознала нужные данные после этого.
График с данными об ошибках модели. В большинстве случаев модель распознавала данные успешно
Улучшили целевые метрики:
  • повысили конверсию в публикацию объявления на 4%;
  • снизили количество отказов в публикации объявлений из-за неверного номера на 55%;
  • уменьшили количество обращений в поддержку на 45%.

Вместо выводов: что даёт декомпозиция

В работе над этим проектом мы использовали её дважды.
Первый раз на этапе разметки — делили большую задачу по разметке со сложным контролем качества на подзадачи для асессоров. Чтобы датасет был более качественным, и мы смогли отобрать только самые подходящие примеры для обучения модели.
Второй раз, когда разбили задачу «распознать номер с документа» на несколько этапов и сделали отдельную модель для каждой стадии.
Вот что нам это дало:
Качество. Система становится качественнее, так как каждый шаг подготавливает данные для следующего. На каждом отдельном этапе решается узкая задача, и у нас появляется больше контроля.
В итоге мы можем использовать полученные данные либо при подготовке к распознаванию, либо чтобы возвращать фотографию пользователям на доработки.
Контролируемость. Отдельные шаги пайплайна проще проверять на качество, чем огромную модель, которая занимается сразу всем.
Интерпретируемость. Пайплайн с детализацией по шагам позволяет логировать промежуточные результаты и исследовать, где возникла проблема.
Гибкость. В зависимости от потребности можно настраивать отдельные шаги и не трогать весь пайплайн — например, докручивать детектор или добавлять новые параметры в проверочную модель.
Переносимость. Модели в пайплайне обучены под СТС, но ту же технологию можно применить для других документов — например, для кадастровых номеров в объявлениях о продаже недвижимости.
Масштабируемость. Адаптироваться к продовой нагрузке проще, если есть возможность настроить ресурсы на отдельные шаги.
Спасибо вам за уделенное статье время! На вопросы буду рада ответить в комментариях к статье.
Больше интересных кейсов и историй из мира Data Science в Авито читайте в нашем не душном, а душевном телеграм-канале — «Доска AI объявлений». Подробнее о том, какие задачи решают инженеры Авито и с помощью каких инструментов они это делают — на нашем сайте и в телеграм-канале AvitoTech. Свежие вакансии в нашу команду — вот здесь.