Токенизация на подслова (Subword Tokenization)

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

subword

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

Например, немецкое слово «Abwasserbehandlungsanlange» означает «станция очистки сточных вод» и является конкатенацией соответствующих слов. В идеале, перед подачей в какую-нибудь рекуррентную/attention-сеть желательно разбить слово на соответствующие подслова. Даже в английском языке, например, слово «subword» напрашивается разбить на «sub» + «word». Этот приём, кстати, может помочь с проблемой OOV (out of vocabulary) — в обучающей выборке может не быть слова «subtask», но поскольку «subtask» = «sub» + «task», а эти слова (подслова), допустим, есть в обучении, мы можем надеяться, что сеть будет правильно обрабатывать / генерировать и слово «subtask».

Для решения проблемы OOV, прежде всего в машинном переводе (но затем и в распознавании речи и языковых моделях), стали использовать т.н. Subword Tokenization — токенизацию на подслова. Ниже рассмотрим популярные методы такой токенизации.

Byte Pair Encoding (BPE)

Идея похожа на коды Хафмана, собственно сам термин пошёл из работы по кодированию [Philip Gage, 1994].

Обучение BPE

  1. Слово = последовательность токенов (пока символов, изначально использовались unicode-символы)
  2. Словарь = все токены (на нулевой итерации — символы)
  3. Повторять пока не достигли ограничения на размер словаря
    • Назначаем новым токеном объединение двух существующих токенов, которое встречается чаще других пар в корпусе (имеется в виду: встречаются вместе).

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

bpe

Упрощённая иллюстрация BPE показана на рисунке: здесь нет слов, просто цепочка символов. Мы выписываем частоты (на рис. — числа вхождений) пар символов, которые встречаются в тексте, заменяем самую частую пару на новый символ (вне словаря), и продолжаем этот процесс. Словарь у нас увеличивается в объёме, а цепочка сокращается в длине. Когда нам покажется, что словарь достаточно большой (ну или частоты очень маленькие), мы становимся.

На практике:

  • К словам добавляется спецсимвол «конец слова».
  • Различают изолированные токены (слова) и токены-подслова. Например,
    «I</w> like</w> ke</w>» → «I</w>», «li», «##ke</w>», «ke</w>»

    здесь «ke» кодируется по-разному, в зависимости от того, изолированное это слово или часть слова «like».

  • В GPT2 этот метод использован над байтами!
  • В GPT2 запрещалось склеивание пар токенов разных типов (изначально каждому токену приписывался тип), например, нельзя склеивать букву и знак препинания, т.е. токен «a?» мы никогда не получим.

Метод описан в статье

Из интересного, обратите внимание, что одна из метрик качества там CHRF3 – a character  n-gram F3-score, которая очень хороша для оценки машинного перевода, поскольку согласуется с мнениями ассесоров.

WordPiece

Если кратко, то WordPiece – это BPE, в котором при слиянии токенов мы максимизируем правдоподобие, а не частоту. Изначально этот метод использовался в BERT, но авторы RoBERTa показали, что особых преимуществ перед BPE не видно.

Метод был предложен в работе

В рассматривоемой там задаче в текстах было очень мало пробелов (собственно, почему и потребовалось расщеплять цепочки символов на элементарные). Заметим, что формально метод появился до BPE (в машинном обучении).

Unigram Language Model (ULM)

В отличие от описанных выше методов, здесь получается целое распределение над сегментациями (из которого можно сэмплировать). Предполагается, что все подслова независимые, поэтому вероятность p(x) слова x равна произведению вероятностей входящих слов p(xi), ищется подходящая сегментация. Метод применяется так:

  1. Создать большой словарь (любой эвристикой – например, буквы + наиболее частые подслова, или Enhanced Suffix Array algorithm [Nong et al., 2009], можно также использовать BPE).
  1. Повторять, пока размер словаря не достигнет порога:
    • Зафиксировав словарь, максимизировать p(x) с помощью EM-алгоритма
    • Для каждого подслова w вычислить lossw – насколько уменьшится правдоподобие при удалении слова из словаря
    • Оставить 80% слов с максимальным lossw (символы оставлять всегда, чтобы не было OOV)

Подробное описание лучше смотреть в оригинальной статье:

Sentencepiece

По сути это не метод, а библиотека с открытым кодом, которая описана в работе

в ней, собственно, реализованы наработки автора ULM из компании Google. Из некоторых фишек:

  • есть возможность рассматривать пробелы как отдельные символы и не схлопывать при токенизации

Использовать библиотеку в своих проектах очень просто, ниже пример кода:

# загружаем библиотеку
import sentencepiece as spm
# обучение из файла text.txt
spm.SentencePieceTrainer.Train('--input=test/text.txt --model_prefix=m --vocab_size=1000')
# загружаем обученную модель
sp = spm.SentencePieceProcessor()
sp.Load("m.model")
# теперь кодируем текст
sp.EncodeAsIds("I like ke")

BPE-Dropout

Это метод от ребят из Яндекса, опубликованный месяц назад:

Статья получилась очень хорошая. Во-первых, интересна сама идея, которая, скорее всего, была позаимствована из работ автора ULM (он писал о связи своего метода с Dropout). Во-вторых, в ней сделан большой объём экспериментов (очень качественно продуманных).

Метод пытается бороться со следующими недостатками BPE:

  • каждое слово имеет однозначную сегментацию,
  • подслова редких слов не очень интерпретируемы.

Для этого предлагается следующее: использовать словарь и таблицу слияний BPE, но на каждом шаге слияния случайно его пропускать («дропать»).  Это показано на рис. из статьи:

BPE-DROPOUT

Слева — результат слияний в BPE, справа — три варианта результата при пропуске некоторых слияний. Если задаться вероятностью пропуска p (кстати, в экспериментах авторов оптимальное значение p=0.1), то при p=0 получаем BPE, а при p=1 — сегментацию по буквам. На практике BPE-Dropout показал себя лучше BPE и ULM.

В заключение можно привести иллюстрацию из статьи

в которой вложения (embeddings), полученные с помощью BPE, сравнивались с вложениями токенов (word2vec), посимвольным (character) и FastText-ом при использовании разных типов нейронных сетей.

embeddings

Другие ссылки

 

Токенизация на подслова (Subword Tokenization): 6 комментариев

  1. Здравствуйте, Александр!

    Скажите, пожалуйста, есть ли смысл погружаться в принцип работы кода библиотеки sklearn? Можете порекомендовать ссылки на материалы, где этот вопрос изучался (если таковые есть)?

    Спасибо!

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

      Материалов я не знаю:(

      П.С. Только это не имеет отношения к содержанию поста;)

Оставьте комментарий