Как мы обучали категоризатор фискальных чеков DataCheckEngine

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

8c5b0ea74392f504e7b22e13d8296185.jpg

Банки и интерес к чекам

Предприниматели обязаны передавать информацию по чекам в ФНС — это требование 54-ФЗ. Посредниками в этом процессе выступают операторы фискальных данных (ОФД). Они же перепродают информацию о покупках банкам, которые собирают статистику об интересах клиентов и на её основе делают персональные предложения. Но есть нюанс — данные по чекам приходят в сыром текстовом виде. Каждый магазин описывает товары в произвольном формате (с сокращениями и собственными аббревиатурами), поскольку эта процедура не регламентирована 54-ФЗ. В итоге перед банками стоит нетривиальная задача по выделению и структурированию категорий товаров и брендов.

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

Последовательность действий

Мы разбили проблему на три подзадачи. Во-первых, по каждой позиции в чеке необходимо определить наименование продукта, однозначно отражающее его содержание — например, не «палочки», а «кукурузные палочки». Во-вторых, нужно определить категорию товара. В-третьих, вычленить объем (вес), единицы измерения и бренд. Например, вот так может выглядеть схема категорий для литровой бутылки кефира:

1af5e91ac305ad9c2388b45d9a15bdd1.jpg

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

Тогда мы взяли случайную выборку позиций чеков и разметили её вручную, придерживаясь двух принципов — категории должны быть уникальны и иметь всего два уровня вложенности. Разметку проводили внутренними ресурсами команды — по нашему опыту, так она получается качественнее, по сравнению с результатами сторонних сервисов. Вообще, такой практики придерживаются многие известные компании — например, Tesla. Автопроизводитель перенес разметку данных для беспилотников в in-house формат, когда специалисты по системам ИИ работают плечом к плечу с «разметчиками».

Далее, мы начали обогащать тренировочную выборку. Возник вопрос — как добавить в неё данные по недостающим категориям, если мы еще не знаем категории позиций чеков. Проблему решили двумя способами: а) вручную искали необходимые позиции по ключевым словам, б) передавали ML-модели новые порции данных и самостоятельно категоризировали ответы с низким уровнем уверенности.

Расширяя выборку, важно не допустить переобучения модели. Иначе она просто запомнит конкретный список чеков и начнет ошибаться. Баланс точности и полноты алгоритма отражает F1-мера. Оптимальное значение метрики зависит от конкретной задачи — в нашем случае она составила 0,95.

В итоге финальная версия справочника содержит двадцать две категории первого уровня:

Авто

Одежда, обувь, аксессуары

Товары для животных

Алкоголь

Подарки и сувениры

Товары для здоровья

Бытовая техника

Продукты

Товары для красоты

Дача, сад и огород

Прочее

Услуги

Детские товары

Спорт и отдых

Хобби и творчество

Досуг и развлечения

Строительство и ремонт

Электроника

Канцтовары

Табачная продукция

Кафе, ресторан, доставка

Товары для дома

На практике они покрывают значительную часть потребительской корзины среднестатистического россиянина. Каждая категория имеет детализацию второго уровня. Она менялась по мере понимания содержимого чеков. Например, в них стали попадаться снэки, джемы и варенья — отнести эти продукты в существующие категории было проблематично. В итоге мы добавили отдельные подкатегории — «Снэки» и «Джем, мёд, варенье, сиропы и топпинги».

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

Вот так выглядит итоговая детализация самой многочисленной категории «Продукты» — тридцать пять подкатегорий:

Безалкогольное пиво и вино

Мясная гастрономия

Биойогурты и кисломолочные продукты

Полуфабрикаты

Блюда быстрого приготовления

Рыбная гастрономия

Всё для выпечки

Снэки

Детское питание

Соки и нектары

Джем, мёд, варенье, сиропы и топпинги

Соль, специи, сахар

Диетическое и спортивное питание

Соусы, растительные масла

Замороженные продукты

Сухофрукты, семечки, орехи

Йогурты и молочные напитки

Сырная продукция

Кондитерские изделия

Торты, пирожные, суфле, десерты

Консервация

Фрукты, овощи и грибы

Крупы, бобовые, макаронные изделия

Хлеб и выпечка

Лимонады и газированные напитки

Хлопья, мюсли, сухие завтраки

Минеральная и питьевая вода

Холодный чай и кофе

Яйца

Чай, кофе, какао

Молоко и молочные продукты

Чай, кофе с собой

Мороженое

Энергетические напитки

Морсы, кисели, компоты

Наименования продуктов и бренды. Первым делом необходимо было разобраться, какую часть позиции чека считать названием продукта. Например, бумага может быть офисной и туалетной, а перчатки — медицинскими или кожаными. Также чеки содержали словосочетания вида «бумага для …» или «салат с …». Можно было разметить продукты в виде словосочетаний, но это трудоемкая задача. Мы применили метод n-грамм с отбросом ненужных слов.

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

Например, для слова «батончик» мы получили вот такие n-граммы:

'шоколадный батончик', 'батончик злаковый', 'батончик протеиновый', 
'мороженое батончик', 'батончик с арахисом', 'батончик молочный', 
'батончик фруктово-ореховый'

Для слова «сливки»:

'сливки питьевые', 'сливки для кофе', 'сливки для взбивания'

Для слова «бальзам»:

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

Помимо развернутого описания продукта в виде n-грамм, мы возвращаем и ключевое слово, образующее название продукта. Так, для «шоколадного батончика» мы возвратим слово «батончик». Оно может служить тегом для поиска товаров в банковском приложении. Что касается брендов, то в плане разметки мы поступили похожим образом. Написали функцию на regex, которая ищет бренды в списке из 200 тыс. наименований. Через regex также определяем меры и объемы.

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

Нап с/а RED DEVIL ИнаяСила7,2% ж/б0.45L

Система восстановит как:

НАПИТОК СЛАБОАЛКОГОЛЬНЫЙ RED DEVIL ИНАЯ СИЛА 7.2% ЖЕСТЯНАЯ БАНКА 0,45 ЛИТРОВ

Если говорить о точности моделей, то:

  • F1-мера по категориям — 95.0817% (кол-во обучение — 225415, тест — 50357)

  • F1-мера по продуктам — 96.1165% (кол-во обучение — 763348, тест — 84817)

  • F1-мера по брендам — 96.4335% (кол-во обучение — 841214, тест — 93469)

Код для обучения языковой модели на выборке из 10 тыс. чеков мы выложили в открытый доступ в виде Jupyter Notebook. Там же можно найти семпл из 3 тыс. размеченных брендов для дообучения текстового категоризатора чеков в Pytorch.

Железо и алгоритмы

Предобучение модели проходило на 7,3 млн чеков. Для обучения применили уменьшенную версию DistilBert и библиотеку Transformers.

Мы пробовали использовать CNN-модели c эмбеддингами GloVe. Да, они работают очень быстро — на один запрос уходит порядка 10 мс —, но проигрывают по точности, что нас не устраивало. В свою очередь, Bi-LSTM дают сопоставимый результат по точности, но уступают по скорости — 40 мс на запрос. Измерения мы проводили на CPU в Pytorch. Библиотека зарекомендовала себя как более быстрая, по сравнению с TensorFlow.

Сфера NLP уходит от классических моделей LSTM и CNN в сторону attention based models. Дистилляцией и уменьшением числа параметров модели можно добиться внушительных скоростей при приемлемой точности. Также существует тренд на экстремальную дистилляцию архитектур больших моделей.

48374e988b2d1c277abc466d328ed18e.png

Уже есть решения вроде MiniLM и XtremeDistil-l6-h256, которые в пять-девять раз быстрее обычного BERT. К сожалению, кода обучения этих моделей нет в открытом доступе. Тюнинговать нашу модель на английской или мультиязычной версиях не очень хотелось, так как страдает точность. Поэтому мы и остановились на классическом, но надежном DistilBert.

Что в итоге

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

Возможно, у вас возник вопрос, откуда для этого брать «живые чеки»? И как финансовые организации связывают с ними покупки клиентов? У нас есть опыт реализации таких проектов, и мы поделимся им в следующих материалах.

© Habrahabr.ru