Всем привет! Наша команда SberIDP занимается задачей извлечения сущностей и фактов из текстовых данных. В банке исторически обрабатывается большое число неструктурированных документов, и автоматизация в этой области позволяет сэкономить много времени и ресурсов, а также улучшить клиентский путь. Например, с помощью предварительной обработки документов Сбер ускорил выдачу кредитов до 7 минут. Современные методы, основанные на глубинном обучении, требуют от сотен до тысяч примеров для получения приемлемого качества в задачах NER. Сегодня мы разберем направление Few-Shot, которое позволяет решать данную задачу всего лишь на нескольких примерах, и поделимся результатами наших экспериментов. Мы смогли достичь state-of-the-art результатов на датасете Few-NERD и выложили полученные веса на HuggingFace для всех желающих. Задача распознавания именованных сущностей (Named Entity Recognition, NER) является одной из классических задач обработки естественного языка наравне с классификацией, машинным переводом и другими. Задача NER — выделить спаны сущностей в тексте (спан — непрерывный фрагмент текста). По сути, такая задача может сводиться к классификации на уровне слов или токенов, которые затем объединяются в спаны. Основная метрика качества такой задачи, как и в большинстве задач классификации, — F-мера. Если вы ранее не слышали об извлечении именованных сущностей, можете ознакомиться с этой темой здесь. Данную задачу еще несколько лет назад неплохо решали составными моделями типа CharCNN-BLSTM-CRF. Однако в последнее время наилучшие результаты показывают модели на основе архитектуры BERT. Помимо этого, благодаря современным инструментам, таким как HuggingFace, их стало проще разрабатывать и внедрять.   Модель BERT предобучена строить контекстно-зависимые векторные представления токенов на большом корпусе текстов. Мы можем работать с этими представлениями как захотим — агрегировать, классифицировать и так далее. Для решения задачи определения классов спанов сущностей мы можем разбить текст на токены и присвоить каждому из них некоторый класс. Один из вариантов NER-разметки — BIO-схема. Каждому токену, помимо самого класса (например, локация или персона), добавляется один из трех префиксов: B (Begin), I (Inside) или O (Outside). Модель BERT используется для предсказания полученных классов, а затем токены объединяют в спаны. Но даже современные модели на основе BERT требуют очень много размеченных данных. Собирать их сложно, долго и дорого, особенно в специфических доменах (юридическом, медицинском и других). На данный момент существует несколько способов решения данной проблемы: Few-Shot подходы к      обучению. Использование огромных генеративных моделей (в том числе при помощи P-tuning). Сегодня мы расскажем о наших экспериментах с первым подходом. Few-Shot Learning — это задача машинного обучения, в которой модель надо преднастроить на тренировочном датасете так, чтобы она хорошо обучалась на ограниченном количестве новых размеченных примеров. То есть даже на новых классах или доменах данных мы сможем получить качественные предсказания. Задачи Few-Shot характеризуются двумя параметрами: N и K. Задача N-way K-shot обозначает, что нам нужно научиться решать задачу классификации на N классов по K примерам на каждый из них. Давайте рассмотрим задачу поподробнее на примере из статьи. Пусть нам требуется решить N-way K-shot задачу классификации пород собак. У нас имеется по K (например, 3) изображений собак на каждую из N пород (например, 20), но также несколько больших размеченных датасетов птиц. Для начала создается базовый датасет как объединение всех датасетов с птицами. Во время предобучения мы E раз эмулируем необходимую нам задачу, а именно: каждый из E эпизодов мы сэмплируем N видов птиц и по K изображений для каждого. Таким образом модель предобучается (learning-to-learn) по K примерам выучивать разницу N классов.    Во время тестирования, имея всего N совершенно новых классов (пород собак) и по K примеров на каждый класс, мы дообучаем модель всего по нескольким примерам решать ранее невиданную задачу (определять породу собаки). Таким образом, мы обучили модель, которая никогда не видела собак, отличать их породы между собой! Для решения задачи Few-Shot существует несколько парадигм, одна из которых — meta-learning (мета-обучение, обучение учиться). Есть 3 основных подхода к мета-обучению: Model-based (модифицировать архитектуру модели); Metric-based (схоже с KNN; решать задачу при помощи некоторой функции расстояния, опираясь на схожесть объектов); Optimization-based (модифицировать саму структуру обучения и оптимизации для более эффективного «предобучения»). Данные подходы являются общими для всех областей глубинного обучения, поэтому могут помочь нам в решении ключевой проблемы с BERT-подобными моделями для NER. Мы поставили перед собой такую задачу: определить, дает ли предобучение моделей на основе BERT прирост в задаче Few-Shot NER. Для тестирования моделей NER в постановке Few-Shot нам требовался датасет с большим количеством классов (сущностей) и примеров. Но где взять данные? Разметка текста для задачи NER является очень дорогой и трудозатратной. Открытых NER-датасетов (со свободной лицензией) не так много даже на английском языке, самые популярные: CoNLL-2012 (OntoNotes), BTC, WNUT17, CoNLL-2003, JNLPBA. В данном вопросе нам помогли коллеги из Поднебесной. В своей статье Few-NERD: A Few-Shot Named Entity Recognition Dataset (2021) они опубликовали датасет, состоящий из более чем 188 000 предложений. Авторы выделяют 8 широких категорий сущностей (coarse types), которые, в свою очередь, делятся на 66 узких категорий сущностей (fine-grained types). Авторы предлагают две постановки для задач Few-Shot NER: Inter и Intra. Процитируем: Набор данных Inter случайным образом разбит с сохранением широких категорий сущностей, т. е. каждый файл содержит все 8 широких категорий, но разные узкие. Набор данных Intra случайным образом разбит по широким категориям.    Авторы прилагают решения при помощи metric-based подходов. Для этого они используют модели ProtoBert и StructShot вместо классического решения моделью BERT с использованием кросс-энтропийной функции потерь. Мы же, в свою очередь, решили проверить, улучшатся ли их подходы, если мы воспользуемся еще одной парадигмой мета-обучения, а именно optimization-based подходом. Наш взор упал на достаточно простой, но при этом эффективный алгоритм предобучения — Reptile.  Алгоритм Reptile описан в статье On First-Order Meta-Learning Algorithms (2018) от OpenAI. Если излагать кратко, то суть алгоритма заключается в следующем: мы множество раз обучаем модель по k шагов на случайно выбранном из заготовленных датасетов. Авторы Reptile рекомендуют использовать значение между 10 и 20, причем при k=1 мы получим так называемый joint training. При таком предобучении модель находит новые веса, которые, по заявлениям авторов, помогут модели лучше обобщаться и быстрее адаптироваться к новым задачам. Мы сразу столкнулись с необходимостью проведения огромного количества экспериментов. Использование датасетов Inter и Intra привело бы к увеличению количества экспериментов вдвое, поэтому для начала мы остановились только на датасете Inter. Давайте считать: авторы Few-NERD проводят эксперименты с 2 различными моделями в 4 сетапах. Поскольку для оценки стандартного отклонения требуется хотя бы по 3 запуска, авторы проводят уже более 2*3*4=24 запусков. Помимо того, что мы хотели воспроизвести эксперименты для корректного сравнения, у нас было несколько чекпоинтов, которые мы собирались тестировать, поэтому для валидного сравнения от нас требовалось поставить как минимум по 24 эксперимента для каждого предобучения. В нотации, описанной выше (N-way K-shot), авторы сгруппировали эксперименты по четырем постановкам: 5-way 1~2-shot 5-way 5~10-shot 10-way 1~2-shot 10-way 5~10-shot Здесь количество примеров генерируется алгоритмом авторов, где K~2K означает, что примеров будет для одной задачи в промежутке от K до 2K. Это связано со спецификой задачи, а более подробно об этом можно узнать в вышеприведенной статье. В статье Few-NERD приводятся следующие результаты (F-мера):  5-way 1~2-shot 5-way 5~10-shot 10-way 1~2-shot 10-way 5~10-shot  Avg bert-base-uncased  + ProtoBert 38.83±1.49 58.79±0.44 32.45±-0.79 52.92±0.37 45.7 bert-base-uncased + StructShot 51.88±0.69 57.32±0.64 43.34±0.1 49.57±3.08 50.53 Стоит отметить, что модель ProtoBert лучше показывает себя в постановках 5~10-shot, а модель StructShot — в постановках 1~2-shot. Вслед за авторами статьи Few-NERD мы использовали bert-base-uncased из HuggingFace в качестве базовой модели. Затем мы предобучали данную модель при помощи Reptile на 5 датасетах: CoNLL-2012 (OntoNotes), BTC, WNUT17, CoNLL-2003, JNLPBA.  Для предобучения мы модифицировали официальный репозиторий от OpenAI. Была добавлена возможность работы с задачей NER, а также сэмплирование сразу из нескольких датасетов. Мы использовали 10 внутренних итераций (k в вышеприведенной нотации reptile), а для тестов в режиме Few-Shot — github авторов статьи Few-NERD. Здесь мы приводим сравнительные результаты при использовании наших весов с моделями ProtoBert и StructShot против использования весов bert-base-uncased. Для сравнения модели обучались с одинаковыми базовыми параметрами из репозитория Few-NERD.  Первая модель, которую мы протестировали, была Reptile-10s2500. Начиная с весов базовой модели BERT, она предобучалась в режиме 10-shot на протяжении 2500 итераций. Это означает, что во время предобучения имитировался режим Few-Shot с 10 примерами на сущность. Результаты приведены на графиках:  5-way 1~2-shot 5-way 5~10-shot 10-way 1~2-shot 10-way 5~10-shot Avg bert-base-uncased + ProtoBert    38.83±1.49 58.79±0.44 32.45±-0.79    52.92±0.37 45.75 Reptile-10s2500  + ProtoBert    35.02±0.76 59.9±0.34 28.37±0.16 53.61±0.13 44.22  5-way 1~2-shot 5-way 5~10-shot 10-way 1~2-shot 10-way 5~10-shot Avg bert-base-uncased  + StructShot 51.88±0.69 57.32±0.64 43.34±0.1 49.57±3.08 50.53 Reptile-10s2500 + StructShot 45.66±0.33 52.69±1.68 37.23±0.67 46.34+-0.81 45.48 Здесь мы видим, что использование наших весов для модели ProtoBert дает небольшие статистически значимые улучшения в постановках 5~10-shot, но показывает результаты хуже на 1~2-shot. Модель StructShot улучшений не показала. Но мы не отчаялись! Мы погрузились глубже в алгоритм Reptile и предобучили модели с другими гиперпараметрами. Авторы отмечают улучшение качества решения задач N-shot при предобучении в режиме 3N-shot и более. Несмотря на это, нам показалось, что для решения задачи в постановке 1~2-shot предобучение 10-shot может выступить проблемой. Поэтому мы решили предобучить модели при помощи Reptile в режиме 5-shot.  5-way 1~2-shot 5-way 5~10-shot 10-way 1~2-shot 10-way 5~10-shot Avg bert-base-uncased  + ProtoBert 38.83±1.49 58.79±0.44 32.45±-0.79 52.92±0.37 45.75 Reptile-5s1000 + ProtoBert 44.76±0.93 60.38±0.36 37.18±0.4 54.61±0.09 49.23  5-way 1~2-shot 5-way 5~10-shot 10-way 1~2-shot 10-way 5~10-shot Avg bert-base-uncased  + StructShot 51.88±0.69 57.32±0.64 43.34±0.1 49.57±3.08 50.52 Reptile-5s1000 + StructShot 56.12±0.13 62.7+-0.44 50.3±0.3 58.82+-0.32 56.98 По графикам нетрудно заметить, что веса, полученные в ходе предобучения Reptile в режиме 5-shot, статистически значимо улучшают результаты обеих моделей во всех постановках на несколько пунктов.  Для более детального анализа приведем сравнительную таблицу с результатами авторов статьи Few-NERD:  5-way 1~2-shot 5-way 5~10-shot 10-way 1~2-shot 10-way 5~10-shot Avg bert-base-uncased  + ProtoBert 38.83±1.49 58.79±0.44 32.45±-0.79 52.92±0.37 45.7 bert-base-uncased  + StructShot 51.88±0.69 57.32±0.64 43.34±0.1 49.57±3.08 50.53 Reptile-5s1000 + StructShot 56.12±0.13 62.7+-0.44 50.3±0.3 58.82+-0.32 56.985 В рамках данного блогпоста мы рассмотрели пример того, как можно улучшить качество решения задачи NER на малом объеме данных с помощью Few-Shot подходов. Наши результаты могут быть полезны всем, кто столкнется с задачей извлечения сущностей из документов на небольшом датасете. Для этих целей мы выложили нашу модель на HuggingFace. Если вам будет интересно попробовать свои силы на задаче Few-NERD, авторы сделали публичный сайт с лидербордом. В будущем мы планируем еще вернуться с новыми подходами для решения задачи NER. Спасибо за внимание! Над проектом работали: Гельван Кирилл, Гладких Прохор, Водолазский Даниил, Галицкий Игорь. Yet another DL enthusiast