Эволюция токенизации – кодирование пар байтов в НЛП

Обработка естественного языка, возможно, появилась в игре с искусственным интеллектом с опозданием, но такие компании как Google и OpenAI сегодня творят чудеса с техниками НЛП.

Эти компании выпустили самые современные языковые модели, такие как BERT и GPT-2 и GPT-3. А GitHub Copilot и OpenAI Codex являются одними из популярных приложений, которые в последнее время появляются в новостях.

Как человек, мало знакомый с НЛП, я решил рассмотреть это как область исследования, чтобы узнать больше об этом. Мои следующие несколько статей и видео будут сосредоточены на том, чтобы поделиться тем, что я вызнал после разбора некоторых важных компонентов НЛП.

Основные составляющие НЛП

Системы НЛП имеют три основных компонента, помогающих машинам понимать естественный язык:

  1. Токенизация
  2. Встраивание
  3. Архитектуры моделей

Лучшие модели глубокого обучения, такие как BERT, GPT-2 и GPT-3, имеют одинаковые компоненты, но с разными архитектурами, отличающими одну модель от другой.

В этой статье (и в прилагаемой к нему блокноте) мы сосредоточимся на основах первого компонента конвейера НЛП, который токенизации. Это понятие, которое часто не замечают, но само по себе является полем исследования.

Мы так далеко ушли от традиционного процесса токенизации NLTK. И хотя у нас есть самые современные алгоритмы для токенизации, полезно понимать ее эволюцию и то, как мы добрались до того места, где мы сейчас.

Итак, вот что мы рассмотрим:

  • Что такое токенизация?
  • Зачем нам токенизатор?
  • Типы токенизации – слово, знак и подсловие.
  • Алгоритм кодирования пар байтов – версия, которая сегодня используется большинством моделей НЛП.

В следующей части этого руководства мы рассмотрим более продвинутые (или расширенные версии кодирования байтовой пары) алгоритмы:

  • Алгоритм униграммы
  • WordPiece – трансформатор BERT
  • SentencePiece – сквозная система токенизации

Что такое токенизация?

Токенизация – это процесс представления необработанного текста в меньших единицах, называемых токенами. Эти токены могут затем быть сопоставлены с числами для дальнейшего представления модели НЛП.

Вот слишком упрощенный пример того, что делает токенизатор:

## read the text and enumerate the tokens in the text
text = open('example.txt', 'r').read(). # read a text file

words = text.split(" ") # split the text on spaces

tokens = {v: k for k, v in enumerate(words)} # generate a word to index mapping
https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fcaa2e479-181a-4703-afb6-9276

Здесь мы просто сопоставили каждое слово в тексте с числовым индексом. Это, конечно, очень простой пример, и мы не рассматривали грамматику, пунктуацию или сложные слова (например test, test-ify, test-ing и т.д.).

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

Существует несколько применений токенизации. Одним из вариантов использования является дизайн компилятора, когда вам может понадобиться разобрать компьютерные приложения для преобразования необработанных символов в ключевые слова языка программирования.

В глубоком обучении, Токенизация – это процесс преобразования последовательности символов в последовательность лексем, которые в дальнейшем необходимо преобразовать в последовательность числовых векторов, которые могут быть обработаны нейронной сетью.

Зачем нам нужен Tokenizer?

Потребность в токенизаторе возникла из вопроса «Как мы можем заставить машины читать?»

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

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

Достаточно задачи, верно?

Люди изучают язык, соединяя звук со значением, а затем мы учимся читать и писать на этом языке. Машины не могут этого сделать, поэтому им нужно дать самые простые единицы текста, чтобы начать обработку текста.

Вот здесь и вступает в игру токенизация. Он разбивает текст на меньшие единицы, называемые «токенами».

И есть разные способы токенизации текста, о чем мы сейчас узнаем.

Различные способы токенизации текста

Чтобы модель глубокого обучения училась в тексте, нам нужен двухэтапный процесс:

https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fff7fafb7-a127-4e41-a050-cb31
  1. Tokenize – определить алгоритм, который мы будем использовать для создания маркеров.
  2. Кодируйте токены в векторы

Токенизация на основе слова

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

Проблемы с токенизатором Word

Существует высокий риск пропуска слов в данных обучения. С помощью маркеров слов ваша модель не распознает варианты слов, не являющихся частью данных, на которых училась модель.

Итак, если ваша модель видела foot и ball в данных обучения, но окончательный текст имеет footballмодель не сможет распознать это слово, и оно будет обработано с помощью <UNK> токен.

Также пунктуация создает еще одну проблему. Например, let или let's понадобятся отдельные токены, являющиеся неэффективным решением. Это будет требуют огромного словарного запаса чтобы убедиться, что вы продумали каждый вариант этого слова.

Даже если добавить a лемматизатор чтобы решить эту проблему, вы добавляете дополнительный шаг в конвейер обработки.

Также тяжело справиться со сленгом и сокращениями. Сегодня мы используем много сленга и сокращений в тексте, например FOMO, LOL, tl;dr и т.д. Что мы делаем с этими словами?

Наконец, что делать, если язык не использует пробел для сегментации? Для такого языка, как китайский, не использующий пробелы для разделения слов, этот токенизатор полностью откажется.

Столкнувшись с этими проблемами, исследователи рассмотрели другой подход, предполагавший токенизацию всех персонажей.

Токенизация на основе символов

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

Это решило проблему пропущенных слов, поскольку сейчас мы имеем дело с символами, которые можно закодировать с помощью ASCII или Unicode. Теперь он может создавать встраивание для любого слова.

Каждому символу, будь то пробел, апостроф, двоеточие или что угодно, теперь можно назначить символ для создания последовательности векторов.

Но у такого подхода были свои минусы.

Проблемы с моделями на основе символов

Во-первых, этот подход требует больше вычислительных ресурсов. Модели на основе символов будут рассматривать каждого персонажа как маркер. А больше маркеров означает большее входное вычисление для обработки каждого токена, что, в свою очередь, требует больше вычислительных ресурсов.

К примеру, для длинного предложения из 5 слов вам может понадобиться обработать 30 лексем вместо 5 лексем на основе слов.

Кроме того, это сужает количество задач и приложений НЛП. С длинными последовательностями символов можно использовать только тип архитектуры нейронной сети.

Это ограничивает тип задач НЛП, которые мы можем делать. Для таких программ, как распознавание сущностей или классификация текста, кодирование на основе символов может оказаться неэффективным подходом.

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

Интересно то, что для такой, казалось бы, простой задачи было написано несколько алгоритмов, чтобы найти оптимальную политику токенизации.

После понимания преимуществ и недостатков этих методов токенизации есть смысл искать подход, предлагающий средний путь. Нам необходим такой, который сохраняет семантику с ограниченным словарем, который может генерировать все слова в тексте при объединении.

Токенизация подсказки

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

Следовательно, целью было разработать алгоритм, который мог бы:

  1. Сохранять семантические особенности лексемы, то есть информацию на токене.
  2. Токенизируйте, не требуя слишком большого словарного запаса с ограниченным набором слов.

Чтобы устранить эту проблему, можно подумать о разбивке слов на основе набора префиксов и суффиксов. Например, мы можем написать систему, основанную на правилах, для определения подсказок, как "##s", "##ing", "##ify", "un##" и так далее, где позиция двойного хеша обозначает префикс и суффикс.

Итак, слово вроде "unhappily" токенизировано с помощью таких подсказок, как "un##", "happ"и "##ily".

Модель изучает лишь немного подсказок, а затем объединяет их, чтобы создать другие слова. Это решает проблемы потребности в памяти и усилиях, необходимых для создания большого словарного запаса.

Проблемы с алгоритмом токенизации подсказки:

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

Кроме того, для каждого языка нам нужно будет определить другой набор правил создания подсказок.

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

Другим важным фактором, играющим важную роль в этом процессе, является размер словарного запаса, который задает пользователь. Большой словарный запас позволяет лексемизировать более распространенные слова, в то время как меньший словарный запас требует создания больше подсловов для создания каждого слова в тексте без использования <UNK> токен.

Здесь ключевое соблюдение правильного баланса для вашей программы.

Алгоритм кодирования пар байтов (BPE).

BPE первоначально являлся алгоритмом сжатия данных, который вы используете, чтобы найти наилучший способ представления данных путем определения общих пар байтов. Теперь мы используем его в НЛП, чтобы найти лучшее представление текста, используя наименьшее количество токенов.

Вот как это работает:

  1. Добавьте идентификатор (</w>) в конце каждого слова, чтобы определить конец слова, а затем вычислить частоту слов в тексте.
  2. Разделите слово на символы и вычислите частоту символов.
  3. Из маркеров символов для предварительно определенного количества итераций подсчитайте частоту последовательных пар байтов и объедините наиболее часто встречающиеся пары байтов.
  4. Продолжайте повторять, пока не достигнете лимита итераций (установленного вами) или пока не достигнете лимита маркеров.

Давайте рассмотрим каждый шаг (в коде) для примера текста. Чтобы написать это, я обратился за помощью к очень минималистичному блогу Лея Мао о BPE. Я призываю вас проверить это!

Шаг 1: Добавьте идентификаторы слов и вычислите частоту слов

Вот наш образец текста:

"There is an 80% chance of rainfall today. We are pretty sure it is going to rain."
## define the text first
text = "There is an 80% chance of rainfall today. We are pretty sure it is going to rain."
## get the word frequency and add the end of word (</w>) token ## at the end of each word

words = text.strip().split(" ")

print(f"Vocabulary size: {len(words)}")
https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb90e5882-9f1f-4b05-be38-c29

Шаг 2: разделите слово на символы, затем вычислите частоту символов

char_freq_dict = collections.defaultdict(int)
for word, freq in word_freq_dict.items():
    chars = word.split()
    for char in chars:
        char_freq_dict[char] += freq

char_freq_dict
https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fecbf93c5-7fd6-4a40-a63d-bf55

Шаг 3. Объедините наиболее часто встречающиеся последовательные пары байтов.

import re

## create all possible consecutive pairs
pairs = collections.defaultdict(int)
for word, freq in word_freq_dict.items():
    chars = word.split()
    for i in range(len(chars)-1):
        pairs[chars[i], chars[i+1]] += freq
https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaf21979-946b-4dfb-b090-140

Шаг 4 — Повторите n раз, чтобы найти лучшие (с точки зрения частоты) пары для кодирования, а затем объедините их, чтобы найти подсказки

На этом шаге лучше структурировать наш код в функции. Это значит, что нам нужно выполнить следующие шаги:

  1. Найдите пары байтов, наиболее часто встречающихся на каждой итерации.
  2. Объедините эти токены.
  3. Перечислите частоту символьных маркеров с добавленной новой парной кодировкой.
  4. Продолжайте делать это до тех пор, пока не останется пар или не достигнете конца цикла for.

Чтобы получить подробный код, вам следует посмотрите мой блокнот Colab.

Вот сокращенный результат этих 4 шагов:

https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4cb7b992-1986-4dbc-a4725_16

Итак, когда мы выполняем итерацию с каждой лучшей парой, мы объединяем (конкатенируем) пару. Вы можете увидеть, что, когда мы перечисляем частоту, начальная частота лексем символов уменьшается, а новая частота парных маркеров появляется в словаре лексем.

Если вы посмотрите на количество созданных токенов, оно сначала увеличивается, поскольку мы создаем новые пары, но количество начинает уменьшаться после нескольких итераций.

Здесь мы начали с 25 токенов, поднялись до 31 токена на 14-й итерации, а затем опустились до 16 токенов на 50-й итерации. Интересно, верно?

Как улучшить алгоритм BPE

Алгоритм BPE является алчным алгоритмом, который означает, что он пытается найти лучшую пару на каждой итерации. И этот алчный подход имеет определенные ограничения.

Потому, конечно, есть плюсы и минусы алгоритма BPE.

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

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

Используем ли мы BPE в BERT или GPT?

Такие модели, как BERT или GPT-2, используют некоторую версию BPE или модели униграмм для токенизации введенного текста.

BERT включил новый алгоритм под названием WordPiece. Он подобен BPE, но имеет дополнительный уровень расчета вероятности, чтобы решить, будет ли объединенный токен окончательно разрезать.

Резюме

В этом блоге вы узнали, как машина начинает понимать язык, разбивая текст в очень маленькие единицы.

Теперь существует много способов разбить текст, и поэтому важно сравнить один подход с другим.

Мы начали с понимания токенизации, разделяя английский текст пробелами, но каждый язык пишется одинаково (т.е. используют пробелы для обозначения сегментации). Итак, мы рассмотрели разделение символов, чтобы генерировать символы.

Проблема с символами заключалась в потере семантических признаков с лексем из-за риска создания неправильных представлений слов или встраивания.

Чтобы получить лучшее из обоих миров, мы рассмотрели токенизацию подсказок, которая была более перспективной. И, наконец, мы рассмотрели алгоритм BPE для реализации токенизации подсказок.

На следующей неделе мы подробнее рассмотрим следующие шаги и расширенные токенизаторы, такие как WordPiece, SentencePiece, а также как работать с токенизатором HuggingFace.

Ссылки и примечания

На самом деле, мой пост является совокупностью следующих статей и блогов, которые я призываю вас прочитать:

  1. Нейронный машинный перевод редких слов с подсловными единицами. Исследовательская работа, в которой обсуждаются разные методы сегментации на основе алгоритма сжатия BPE.
  2. Репо GitHub на подсказке NMT (нейронный машинный перевод) – вспомогательный код для вышеуказанной статьи.
  3. Блог Лея Мао о Byte Pair Encoding – я использовал код в его блоге, чтобы реализовать и понять BPE.
  4. Как читают машины – блог Катала Хорана.

Если вы хотите начать в области науки о данных или ML, посмотрите мой курс Основы науки о данных и ML.

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

Если есть что добавить или предложить, вы можете связаться со мной с помощью:

Добавить комментарий

Ваш адрес email не будет опубликован.