Как мы обучали категоризатор фискальных чеков DataCheckEngine
Задача актуальна для фин. организаций и ретейла. Расскажем, как мы подошли к ней и почему выбрали для обучения уменьшенную версию модели DistilBert.
Банки и интерес к чекам
Предприниматели обязаны передавать информацию по чекам в ФНС — это требование 54-ФЗ. Посредниками в этом процессе выступают операторы фискальных данных (ОФД). Они же перепродают информацию о покупках банкам, которые собирают статистику об интересах клиентов и на её основе делают персональные предложения. Но есть нюанс — данные по чекам приходят в сыром текстовом виде. Каждый магазин описывает товары в произвольном формате (с сокращениями и собственными аббревиатурами), поскольку эта процедура не регламентирована 54-ФЗ. В итоге перед банками стоит нетривиальная задача по выделению и структурированию категорий товаров и брендов.
Именно с таким кейсом к нам обратилась крупная финансовая организация. Проблема показалась нам интересной, плюс мы увидели в этом возможность прокачать NLP-экспертизу и поработать с новыми подходами к машинному обучению. Сегодня хотим разобрать задачу подробнее и рассказать, как мы подошли к разработке системы категоризации чеков DataCheckEngine.
Последовательность действий
Мы разбили проблему на три подзадачи. Во-первых, по каждой позиции в чеке необходимо определить наименование продукта, однозначно отражающее его содержание — например, не «палочки», а «кукурузные палочки». Во-вторых, нужно определить категорию товара. В-третьих, вычленить объем (вес), единицы измерения и бренд. Например, вот так может выглядеть схема категорий для литровой бутылки кефира:
Категории товаров. Первый справочник категорий решили собрать, опираясь на интернет-каталоги магазинов, но столкнулись с проблемами. Блоки в них зачастую пересекались друг с другом и имели различное количество уровней вложенности, что в перспективе снизило бы эффективность модели машинного обучения.
Тогда мы взяли случайную выборку позиций чеков и разметили её вручную, придерживаясь двух принципов — категории должны быть уникальны и иметь всего два уровня вложенности. Разметку проводили внутренними ресурсами команды — по нашему опыту, так она получается качественнее, по сравнению с результатами сторонних сервисов. Вообще, такой практики придерживаются многие известные компании — например, 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. Дистилляцией и уменьшением числа параметров модели можно добиться внушительных скоростей при приемлемой точности. Также существует тренд на экстремальную дистилляцию архитектур больших моделей.
Уже есть решения вроде MiniLM и XtremeDistil-l6-h256, которые в пять-девять раз быстрее обычного BERT. К сожалению, кода обучения этих моделей нет в открытом доступе. Тюнинговать нашу модель на английской или мультиязычной версиях не очень хотелось, так как страдает точность. Поэтому мы и остановились на классическом, но надежном DistilBert.
Что в итоге
DataCheckEngine преобразует наименования позиций чеков в понятный формат. Получили достойные значения метрик категоризации на примере чеков среднестатистического потребителя с фиксированным списком категорий. В зависимости от задачи и вводных наше решение можно адаптировать для иного заказчика. В идеальном случае достаточно подставить в модель новый справочник категорий, и она заработает без переобучения. Для реализации более глубокой аналитики вроде анализа спроса на товар в конкретный момент времени потребуются дополнительные работы.
Возможно, у вас возник вопрос, откуда для этого брать «живые чеки»? И как финансовые организации связывают с ними покупки клиентов? У нас есть опыт реализации таких проектов, и мы поделимся им в следующих материалах.