Автор: Эллиот Хофман, специалист по анализу данных в Zelros

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

  • Производительность (насколько хороша модель?)
  • Время вывода (насколько быстро модель?)
  • Масштабируемость и простота подхода (насколько легкий и обслуживаемый подход, когда нам нужно будет его адаптировать, переобучать или объяснять нашим клиентам)

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

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

Подход «прямо к катастрофе»

В нашей задаче есть два возможных состояния флажков: они отмечены или не отмечены. Казалось естественным изолировать каждый флажок, чтобы обучить им модель бинарной классификации. Такой подход предполагает, что мы можем сначала найти и обрезать каждый флажок. Поскольку у нас уже был модуль OCR для анализа различных текстовых зон документа, мы решили использовать их, чтобы найти флажки.

Точнее, в отчете об аварии каждому ящику присваивается фиксированная текстовая метка, например, ящик номер 1 соответствует «* en stationnement / à l'arrêt» (припаркованный / стационарный) ярлык, поля номер 2 до ярлыка «* quittait un stationnement / ouvrait une portière» (оставление парковочного места / открытие двери) и т. д. Используя текстовые зоны, возвращенные из OCR, мы можем вычислить отношения Левенштейна, идентифицировать метки по их количеству, а затем вычислить некоторые относительные смещения от текстовых координат, чтобы найти флажки.

Чтобы использовать это решение, необходимо сначала вручную вычислить каждое смещение для каждой из 17 меток и 2 драйверов, что приводит к 34 функциям смещения, которые необходимо определить. Конечно, это дорогостоящий процесс, но его нужно проделать только один раз. Хотя этот подход может показаться немного сложным, было довольно эффективно правильно обрезать все флажки в наших отчетах об авариях.

Теперь нам остается классифицировать их как отмеченные или нет. Как мы собираемся это сделать?

Всегда полезно стараться не внедрять модели машинного обучения там, где они не нужны. Здесь мы сначала подумали о подсчете пикселей, поскольку отмеченное поле означает больше черных пикселей, чем пустое. Однако для эффективного подсчета пикселей изображения должны быть преобразованы в двоичную форму, чтобы входные данные были чисто черно-белыми. В зависимости от процесса получения отчета об аварии (отсканированный, фотография, фотография отсканированного документа,…), молнии, контраста и шума изображения, типа отметки (галочка, крестик, круг,…) и толщины пера, могут быть некоторые важные различия в отношении оптимальных значений порога пикселей. Это затрудняет поиск параметров бинаризации, которые работали бы для всех обрезков флажков, даже при использовании расширенных методов, таких как Gaussian Blur или OTSU Adaptative Thresholding.

Поэтому мы попытались сгладить изображение и обучить неглубокую модель машинного обучения на векторизованных входных данных, таких как SVM или XGBoost. Поступая таким образом, мы, по сути, заставляем модель учиться интеллектуальному подсчету пикселей, но мы сталкиваемся с теми же проблемами, что и выше, даже при векторизации изображений с помощью методов, учитывающих визуальные свойства (векторы Гистограмма ориентированных градиентов, SIFT * дескрипторы,…)

Как часто при решении задач компьютерного зрения, модели глубокого обучения оказываются наиболее эффективными. Действительно, сверточные слои позволяют модели создавать свои собственные элементы и понимать пространственную структуру изображений (углы, линии, кривые, формы и т. Д.). В нашем случае нет необходимости вызывать полный ResNet50, несколько уровней Convolution и Dropout позволили быстро получить точность проверки, близкую к 1, ошибки обычно допускаются при неоднозначных входных данных.

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

  • Определение текстовых зон на изображении напрямую зависит от первого шага распознавания текста. Это означает, что каждый раз, когда модулю OCR не удается идентифицировать какой-либо текст, мы не сможем предоставить прогноз для соответствующих флажков.
  • Он не устойчив к изменениям шаблона, даже если в новом шаблоне есть незначительные отличия. Это особенно верно, когда язык отчета об аварии меняется: все слова переведены, и поэтому мы теряем все маркеры, используемые для определения местоположения флажков. Все смещения необходимо снова вычислить вручную!
  • Подход можно легко обмануть, когда входной документ повернут или показывает некоторую деформацию, что очень часто бывает, когда отчет об аварии был отсканирован на неровной поверхности или снят с неплоской точки зрения.

Было потрачено достаточно времени на попытки использовать нестабильные методы, пришлось искать другое решение!

Подход «мы должны были сделать это с самого начала»

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

Мы решили, что не будем думать о проблеме в масштабе одного «флажка», а предоставим модели весь раздел флажков и позволим магии разобраться сам галочки или нет. Это означает, что теперь проблема заключается в задаче классификации с несколькими метками с 17 * 2 = 34 классами. На этот раз цели - это векторы с горячим кодированием размером 34, с 1 для флажков, которые действительно отмечены.

Поскольку входное изображение стало более сложным, мы выбрали более глубокую архитектуру, а именно EfficientNet B3, с сигмоидной активацией для каждой координаты выходного вектора и обученной двоичной кросс-энтропии. Хотя этот подход немного дольше, чем первый, по прошествии достаточного количества эпох мы достигли тех же почти идеальных характеристик.

Но эта новая архитектура была намного лучше первой!

  • Он не зависит от другого модуля OCR, поэтому риски отказа значительно снижаются, а также делает его независимым от языка отчета об аварии.
  • Он намного лучше адаптируется к вариациям шаблонов, а также к возможным поворотам и углам среза. Фактически, эти вариации можно обрабатывать непосредственно во время обучения с помощью случайного увеличения данных.
  • Взглянув на общую картину, он учится моделировать ассоциации между различными флажками. То есть большинство из них являются взаимоисключающими (например, водитель не может одновременно поворачивать влево и вправо), а некоторые комбинации флажков на практике невозможны. Первый подход никак не мог это понять, потому что он смотрел только на отдельные флажки.
  • Когда нам нужно переобучить модель, у нас будет почти нулевая дополнительная работа. В первом подходе нам нужно было бы сначала извлечь новые флажки с экстрактами OCR, а затем повторно обучить веса классификации.
  • Во время вывода модели необходимо выполнить одно прямое прогнозирование вместо 34 отдельных прогнозов.

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

Однако выбор архитектуры модели - не единственная проблема, с которой вы столкнетесь в своих проектах Data Science. На самом деле проблемы могут возникнуть, как только вы получите данные! Ваши данные могут быть неполными, искаженными, сильно предвзятыми, недостаточными ... Посмотрите в следующей главе, как мы боролись с предвзятостью отчетов об авариях с помощью нашего генератора синтетических данных!

* Срок действия патента SIFT US6711293B1 истек в марте 2020 года