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

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

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

Что внутри статьи:

Контекст

Суть задачи

Требования к модели

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

Этапы работы над моделью и результаты

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

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

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

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

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

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

Вместо выводов 

Что даёт декомпозиция

Суть задачи

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

Так, чтобы разместить объявление о продаже машины на Авито, мы просим продавцов добавлять в объявление фото машины, VIN и госномер.

Поля на подаче объявления, куда пользователи вводят данные об авто
Поля на подаче объявления, куда пользователи вводят данные об авто

Все данные, которые добавляют пользователи, мы проверяем на соответствие. 

VIN и госномер — это длинные последовательности символов, в которых легко ошибиться при ручном вводе. Но эти данные важны, так как, например, по VIN-номеру мы смотрим историю автомобиля, а потом сверяем его с госномером.

Часть пользователей уставали заполнять форму отправки объявления. Часть заполняли всё, но объявления не проходили модерацию из-за ошибок в VIN или госномерах. Из всех отказов в публикации объявлений 8% мы отклоняли именно по этой причине. 

Многие пользователи обращались в поддержку, когда заполнить данные не получалось, и нагрузка на сотрудников саппорта росла.

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

Этим решением стала модель, которая автоматически заполняет поля для VIN и госномера по фотографии свидетельства транспортного средства — СТС.

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

Было четыре основных требования:

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

Переносимость на другие домены — чтобы мы или коллеги в дальнейшем могли решать запросы на распознавание данных с фото по уже проработанному пайплайну.

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

Устойчивость к вариативности данных — об этом расскажу дальше.

Кликни здесь и узнаешь

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

Для распознавания данных мы решили взять свидетельство транспортного средства (СТС). Это обязательный документ для автовладельцев, который подтверждает, что машина зарегистрирована и может законно находиться на дороге.

Выглядит это так:

Пример свидетельства транспортного средства с указанием нужных нам полей — госномер, VIN, номер кузова
Пример свидетельства транспортного средства с указанием нужных нам полей — госномер, VIN, номер кузова

Дисклеймер: все фотографии документов предоставили для статьи мои коллеги. Мы не публикуем персональные данные пользователей.

В процессе работы мы поняли, что разные СТС могут отличаться друг от друга. И из-за этого возникли некоторые сложности.

Первая сложность — в участках нанесения номеров. Хотя СТС — это документ с чёткой структурой, конкретные области с нужными номерами могут отличаться. 

Есть ещё одна особенность — различия в VIN или идентификационном номере транспортного средства. У большинства машин — обычный VIN, который состоит из 17 символов и совпадает с номером кузова. Но у старых японских машин в графе VIN часто пишут слово «Отсутствует», а вместо него в качестве идентификатора используют номер кузова:

Так выглядит «японский» СТС без идентификационного номера
Так выглядит «японский» СТС без идентификационного номера

И хотя нам нужны только VIN и госномер, модель всё равно должна уметь распознавать ещё и номер кузова:

  • в случае с «обычным» СТС, номер кузова поможет точнее распознать VIN, если с нужной области корректно распознать не получилось;

  • в ситуации с «японским» СТС, мы будем использовать номер кузова вместо отсутствующего VIN.

У самих номеров тоже есть особенности и чёткая структура:

Характеристики и примеры разных типов данных — госномера, «обычного» и «японского» VIN
Характеристики и примеры разных типов данных — госномера, «обычного» и «японского» VIN

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

Перед разработкой своей модели мы попробовали поработать с тремя популярными end-to-end решениями, которые подходят под задачу, а после сравнили результаты. 

Требования к решениям: точность > 95%, полнота > 90%. Оценку точности свели к бинарным кейсам: распознали / не распознали.

Библиотеки, которые мы использовали, с документацией на GitHub: 

? PaddleOCR 

? DocTR

? EasyOCR

Сравнили результаты:

Модель

Точность — госномер

Полнота — госномер

Точность — VIN

Полнота — 

VIN

PaddleOCR

94,3%

78,7%

74,1%

85,6%

DocTR

95,4%

85,8%

43,0%

89,6%

EasyOCR

25,3%

79,6%

30,9%

30,7%

Лидером стал PaddleOCR, но даже это решение не вписывалось в требования. Мы разобрали ошибки и обнаружили, что модель:

  • пропускала нужные номера на этапе детекции;

  • допускала ошибки в одиночных символах;

  • делала ошибки на концах номеров из-за наложения другого текста или близкого соприкосновения;

  • склеивала два слова из строки в одно.

Пример распознавания текста с помощью PaddleOCR — слева фотография СТС, справа — текст, который распознала модель
Пример распознавания текста с помощью PaddleOCR — слева фотография СТС, справа — текст, который распознала модель

После всех тестов мы решили не докручивать опенсорсное решение, а сделать свой лёгкий в использовании пайплайн под конкретную задачу.

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

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

Пайплайн состоит из трёх этапов:

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

  • детектор — выделяет и вырезает области с нужными номерами из исходных фотографий;

  • OCR — распознаёт номера.

Пайплайн модели распознавания данных по фотографии СТС
Пайплайн модели распознавания данных по фотографии СТС

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

Первый шаг после того, как пользователь загрузил фотографию документа — проверить снимок с помощью классификаторов. Они определяют:

  • какой тип документа на фото — если это не СТС;

  • видно ли в кадре СТС полностью; 

  • насколько далеко находится СТС на фото.

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

Ещё определяем, под каким углом сфотографировали СТС. Если фото сделали под углом или с перспективой, исправляем до нормального положения. На этом этапе можно добавить дополнительные параметры проверки — например, размытость, тени и блики в важных местах.

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

Детектор мы обучали на собственной разметке — датасете из фотографий документов, где руками были выделены области с номерами. 

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

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

Два проекта с асессорами
Два проекта с асессорами

Затем контролировали точность разметки во втором проекте. Для этого использовали голден — набор примеров, где мы знаем эталонные ответы. Эти примеры случайно подмешивали асессорам, после чего сравнивали эталонные ответы с теми, что дали асессоры. Считали долю правильных ответов и ошибок. 

Жми сюда!

Таким образом мы оценивали качество работы как отдельных асессоров, так и разметки в целом. 

Благодаря декомпозиции получилась очень точная разметка. 

Для детекции использовали сегментационную модель U-Net, потому что она позволяла очень тонко выделить область с номером. Обучили модель на два класса: 1 — пиксель принадлежит маске одного из номеров, 0 — часть фона. На выходе получаем маску, которая накладывается на изображения и показывает, где расположены номера:

Фотографии СТС с масками, сделанными архитектурой U-Net
Фотографии СТС с масками, сделанными архитектурой U-Net

Для повышения точности провели аугментацию — добавляли на фотографии размытие, засветы, затемняли их. Это помогло получить более точные границы на размытых фотографиях и исключить разрезы маски из-за бликов на номерах.

Значение надписей на плашке в верхнем правом углу: plate — госномер, vin — вин, body — номер кузова
Значение надписей на плашке в верхнем правом углу: plate — госномер, vin — вин, body — номер кузова

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

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

Добавили блок для выравнивания документа перед этапом детектирования. Если пользователь присылает фотографию под углом или с перспективой — мы поворачиваем её до нормального положения и корректируем перспективу. 

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

Для коррекции перспективы применяем warpPerspective. Это функция в OpenCV Python, которая применяет аффинное преобразование к картинке, которое убирает перспективу. 

Нам она нужна, чтобы убрать перспективу на фотографиях СТС, которые были сделаны не строго сверху:

 На выходе получаем документ в нормальном положении с обрезанным фоном
 На выходе получаем документ в нормальном положении с обрезанным фоном
Фотография до и после выравнивания с помощью RetinaNET
Фотография до и после выравнивания с помощью RetinaNET

? Документация для архитектуры RetinaNET на GitHub

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

На последнем этапе модель распознаёт номера на кусочках из исходной картинки, которые вырезали по маске из детектора. Для распознавания текста мы обучили свёрточно-рекуррентную архитектуру CRNN с CTC-декодером и датасетом из пар: «картинка + текст». 

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

Обрезаем и выравниваем фотографию по маске от детектора
Обрезаем и выравниваем фотографию по маске от детектора

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

Все этапы распознавания номеров на одной картинке
Все этапы распознавания номеров на одной картинке

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

Провели тесты нашей модели и смогли побить пороги, которые ставили ещё до разработки. Получили такие значения:

Точность

Полнота

Госномер

97,5%

90,1%

VIN

98,5%

90,3%

Также мы собрали данные по ошибкам после внедрения модели. На графике видно, что она не смогла распознать текст только у 8% фотографий. В остальных случаях модель либо распознала всё успешно, либо мы дали подсказки, как исправить ошибки, и она распознала нужные данные после этого.

График с данными об ошибках модели. В большинстве случаев модель распознавала данные успешно
График с данными об ошибках модели. В большинстве случаев модель распознавала данные успешно

Улучшили целевые метрики:

  • повысили конверсию в публикацию объявления на 4%; 

  • снизили количество отказов в публикации объявлений из-за неверного номера на 55%;

  • уменьшили количество обращений в поддержку на 45%.

Кликни здесь и узнаешь

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

В работе над этим проектом мы использовали её дважды. 

Первый раз на этапе разметки — делили большую задачу по разметке со сложным контролем качества на подзадачи для асессоров. Чтобы датасет был более качественным, и мы смогли отобрать только самые подходящие примеры для обучения модели. 

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

Вот что нам это дало:

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

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

Контролируемость. Отдельные шаги пайплайна проще проверять на качество, чем огромную модель, которая занимается сразу всем.

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

Гибкость. В зависимости от потребности можно настраивать отдельные шаги и не трогать весь пайплайн — например, докручивать детектор или добавлять новые параметры в проверочную модель.

Переносимость. Модели в пайплайне обучены под СТС, но ту же технологию можно применить для других документов — например, для кадастровых номеров в объявлениях о продаже недвижимости.

Масштабируемость. Адаптироваться к продовой нагрузке проще, если есть возможность настроить ресурсы на отдельные шаги.

Спасибо вам за уделенное статье время! На вопросы буду рада ответить в комментариях к статье.

Больше интересных кейсов и историй из мира Data Science в Авито читайте в нашем не душном, а душевном телеграм-канале — «Доска AI объявлений». Подробнее о том, какие задачи решают инженеры Авито и с помощью каких инструментов они это делают — на нашем сайте и в телеграм-канале AvitoTech. Свежие вакансии в нашу команду — вот здесь.

Комментарии (4)


  1. RomanVelichkin
    15.05.2025 06:05

    Такое решение доступно лишь единицам. Огромное количество ресурсов для распознавания одного типа документов. Большой объем данных, команда разметки, отдельная модель на каждый этап.

    Кстати, в статье опущен момент производительности - насколько получившийся пайплайн медленнее/быстрее опенсорсных решений?


    1. natalia_varenik Автор
      15.05.2025 06:05

      Роман, привет! Спасибо большое за комментарии! Ты прав, мы потратили много ресурсов, но смотря в каких масштабах смотреть, для производственных масштабов разметка может быть посильной затратой, например, для обучения UNet можно начать с нескольких сотен картинок и наращивать по мере недостатка в качестве. Для OCR нужно больше данных, но можно пользоваться предзаполнением какой-то из опенсорс моделей, что сильно ускоряет и упрощает. Дальше уже обучение моделей по времени и сложности не занимает много. Нам была важна точность распознавания, ошибка в одном символе для нас уже критична, тк это данные из документа, по которым идут автоматические проверки и несовпадение влечет за собой отклонение и негативный опыт для пользователя, поэтому мы осознанно тратили больше ресурсов.

      Насчет производительности: не ставили перед собой задачу сделать быстрее чем в опенсорсе, однако по таймингам подскажу, например время ответа PaddleOCR - 150мс, наше - 300 мс на 1 картинке. Нас устроило наше время ответа, поэтому не занимались ускорением пока. Мы часто используем для ускорения и экономии гпу в продакшене наш фреймворк Акведук, который позволяет получать меньшее время ответа под нагрузкой, тут мы тоже в него обернули, не настраивали максимально, тк пока нет необходимости.


  1. RomanVelichkin
    15.05.2025 06:05

    Не думали, что дообучение PaddleOCR могло бы быть более эффективным решением в плане общих затрат и скорости инференса?


    1. natalia_varenik Автор
      15.05.2025 06:05

      Думали, мы стояли на распутье тогда, для дообучения PaddleOCR точно так же нужно было бы размечать данные. Нужно было думать как это делать, ведь он размечает весь документ, то есть нам нужно было либо тоже размечать весь документ, либо придумывать, как переобучать только под нужные нам боксы для нужных номеров, а затем думать как из всех боксов выбирать нужные уже для OCR. У нас тогда были ресурсы на разметку и мы решили попробовать сделать свой пайплайн с нуля, который архитектурно будет проще, чем у PaddleOCR и нам проще будет его внедрять и поддерживать. А в качестве второго варианта, если бы первый не заработал держали дообучение PaddleOCR.