Сравнение токенов, сгенерированных алгоритмами токенизации SOTA с использованием пакета токенизаторов Hugging Face

Продолжая глубокое погружение в море НЛП, этот пост посвящен обучению токенизаторов с нуля с использованием пакета токенизаторов Hugging Face.

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

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

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

BPE - частотная модель

  • Кодирование пар байтов использует частоту шаблонов подслов, чтобы составить короткий список для их объединения.
  • Недостатком использования частоты в качестве движущего фактора является то, что в конечном итоге вы можете получить неоднозначные окончательные кодировки, которые могут оказаться бесполезными для нового входного текста.
  • Он все еще нуждается в улучшении с точки зрения генерации однозначных токенов.

Юниграмма - вероятностная модель

  • Поставляется в модели Unigram, которая подходит к решению проблемы слияния путем вычисления вероятности каждой комбинации подслов, а не выбора наиболее частого шаблона.
  • Он вычисляет вероятность каждого токена подслова, а затем отбрасывает его на основе функции потерь, которая объясняется в этой исследовательской статье.
  • На основе определенного порога значения потерь вы можете затем запустить модель, чтобы отбросить нижние 20–30% токенов подслов.
  • Unigram - это полностью вероятностный алгоритм, который выбирает как пары символов, так и окончательное решение объединить (или нет) на каждой итерации на основе вероятности.

WordPiece

  • С выпуском BERT в 2018 году появился новый алгоритм токенизации подслов под названием WordPiece, который можно рассматривать как посредник между алгоритмами BPE и Unigram.
  • WordPiece также является жадным алгоритмом, который использует вероятность, а не частоту подсчета, чтобы объединить лучшую пару на каждой итерации, но выбор символов для пары основан на частоте подсчета.
  • Таким образом, он похож на BPE с точки зрения выбора персонажей для объединения и аналогичен Unigram с точки зрения выбора лучшей пары для слияния.

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

Обучение алгоритмов BPE, Unigram и WordPiece

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

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

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

Наборы данных для обучения

Я выбрал два разных набора данных для обучения этих моделей: один - это бесплатная книга от Гутенберга, которая служит небольшим набором данных, а другой - wikitext-103, который занимает 516 Мб текста.

В Colab вы можете сначала загрузить наборы данных и разархивировать их (при необходимости),

!wget http://www.gutenberg.org/cache/epub/16457/pg16457.txt
!wget https://s3.amazonaws.com/research.metamind.io/wikitext/wikitext-103-raw-v1.zip
!unzip wikitext-103-raw-v1.zip

Импортируйте необходимые модели и кроссовки.

Просматривая документацию, вы обнаружите, что основным API пакета является класс Tokenizer.

Затем вы можете создать экземпляр любого токенизатора с выбранной моделью (BPE / Unigram / WordPiece).

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

## importing the tokenizer and subword BPE trainer
from tokenizers import Tokenizer
from tokenizers.models import BPE, Unigram, WordLevel, WordPiece
from tokenizers.trainers import BpeTrainer, WordLevelTrainer, \
                                WordPieceTrainer, UnigramTrainer
## a pretokenizer to segment the text into words
from tokenizers.pre_tokenizers import Whitespace

Трехэтапный процесс для автоматизации обучения и токенизации

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

Итак, как выглядят эти функции?

Шаг 1 - Подготовьте токенизатор

Подготовка токенизатора требует, чтобы мы создали экземпляр класса Tokenizer с моделью по нашему выбору, но поскольку у нас есть четыре модели (также добавлен простой алгоритм уровня Word) для тестирования, мы напишем случаи if / else для создания экземпляра токенизатора с помощью правильная модель.

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

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

Вы также можете указать здесь размер словаря других аргументов обучения или минимальную частоту.

unk_token = "<UNK>"  # token for unknown words
spl_tokens = ["<UNK>", "<SEP>", "<MASK>", "<CLS>"]  # special tokens
def prepare_tokenizer_trainer(alg):
    """
    Prepares the tokenizer and trainer with unknown & special tokens.
    """
    if alg == 'BPE':
        tokenizer = Tokenizer(BPE(unk_token = unk_token))
        trainer = BpeTrainer(special_tokens = spl_tokens)
    elif alg == 'UNI':
        tokenizer = Tokenizer(Unigram())
        trainer = UnigramTrainer(unk_token= unk_token, special_tokens = spl_tokens)
    elif alg == 'WPC':
        tokenizer = Tokenizer(WordPiece(unk_token = unk_token))
        trainer = WordPieceTrainer(special_tokens = spl_tokens)
    else:
        tokenizer = Tokenizer(WordLevel(unk_token = unk_token))
        trainer = WordLevelTrainer(special_tokens = spl_tokens)
    
    tokenizer.pre_tokenizer = Whitespace()
    return tokenizer, trainer

Нам также нужно будет добавить пре-токенизатор, чтобы разделить наш ввод на слова, поскольку без пре-токенизатора мы можем получить токены, которые перекрывают несколько слов: например, мы могли бы получить токен "there is", поскольку эти два слова часто появляются рядом с друг с другом.

Использование пре-токенизатора гарантирует, что токен не будет больше слова, возвращаемого пре-токенизатором.

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

Здесь мы используем один и тот же пре-токенизатор (Whitespace) для всех моделей. Вы можете протестировать его с другими.

Шаг 2 - Обучите токенизатор

После подготовки токенизаторов и трейнеров можно приступать к тренировочному процессу.

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

  • ‘WLV’ - Алгоритм уровня слов
  • ‘WPC’ - Алгоритм WordPiece
  • ‘BPE’ - Кодирование пары байтов
  • ‘UNI’ - Юниграмма
def train_tokenizer(files, alg='WLV'):
    """
    Takes the files and trains the tokenizer.
    """
    tokenizer, trainer = prepare_tokenizer_trainer(alg)
    tokenizer.train(files, trainer) # training the tokenzier
    tokenizer.save("./tokenizer-trained.json")
    tokenizer = Tokenizer.from_file("./tokenizer-trained.json")
    return tokenizer

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

После обучения он сохраняет модель в файле JSON, загружает ее из файла и возвращает обученный токенизатор, чтобы начать кодирование нового ввода.

Шаг 3 - Токенизация входной строки

Последний шаг - начать кодирование новых входных строк и сравнить токены, сгенерированные каждым алгоритмом.

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

Строка ввода - «Это руководство по токенизации с глубоким обучением. Токенизация - это первый шаг в конвейере глубокого обучения НЛП. Мы будем сравнивать токены, генерируемые каждой моделью токенизации. Сильно взволнован?! 😍 »

small_file = ['pg16457.txt']
large_files = [f"./wikitext-103-raw/wiki.{split}.raw" for split in ["test", "train", "valid"]]
for files in [small_file, large_files]:
    print(f"========Using vocabulary from {files}=======")
    for alg in ['WLV', 'BPE', 'UNI', 'WPC']:
        trained_tokenizer = train_tokenizer(files, alg)
        input_string = "This is a deep learning tokenization tutorial. Tokenization is the first step in a deep learning NLP pipeline. We will be comparing the tokens generated by each tokenization model. Excited much?!😍"
        output = tokenize(input_string, trained_tokenizer)
        tokens_dict[alg] = output.tokens
        print("----", alg, "----")
        print(output.tokens, "->", len(output.tokens))

## вывод:

Анализ вывода:

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

  • Простой алгоритм на уровне слов создал 35 токенов независимо от того, на каком наборе данных он был обучен.
  • Алгоритм BPE создал 55 токенов при обучении на меньшем наборе данных и 47 токенов при обучении на более крупном наборе данных. Это показывает, что он смог объединить больше пар символов при обучении на более крупном наборе данных.
  • Модель Unigram создала аналогичное (68 и 67) количество токенов с обоими наборами данных. Но вы могли увидеть разницу в сгенерированных токенах:

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

  • WordPiece создал 52 токена при обучении на меньшем наборе данных и 48 при обучении на более крупном наборе данных. Сгенерированные токены имеют двойной ## для обозначения использования токена в качестве префикса / суффикса.

  • Все три алгоритма генерировали меньшие и лучшие токены подслов при обучении на более крупном наборе данных.

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

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

Поскольку количество токенов, генерируемых каждой моделью, разное, я добавил токен ‹PAD›, чтобы данные были прямоугольными и соответствовали фрейму данных.

‹PAD› - это в основном нан в фреймворке данных.

import pandas as pd
max_len = max(len(tokens_dict['UNI']), len(tokens_dict['WPC']), len(tokens_dict['BPE']))
diff_bpe = max_len - len(tokens_dict['BPE'])
diff_wpc = max_len - len(tokens_dict['WPC'])
tokens_dict['BPE'] = tokens_dict['BPE'] + ['<PAD>']*diff_bpe
tokens_dict['WPC'] = tokens_dict['WPC'] + ['<PAD>']*diff_wpc
del tokens_dict['WLV']
df = pd.DataFrame(tokens_dict)
df.head(10)

## вывод:

Вы также можете посмотреть разницу в токенах, используя наборы:

Весь код можно найти в этой записной книжке Colab.

Заключительные мысли и следующие шаги!

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

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

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

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

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

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

  1. Регуляризация подслов: улучшение моделей трансляции нейронных сетей Обучение токенизаторов BPE, WordPiece и Unigram с нуля с помощью Hugging Face
  2. Нейро-машинный перевод редких слов с подсловными единицами - исследовательская статья, в которой обсуждаются различные методы сегментации, основанные на алгоритме сжатия BPE.
  3. Пакет токенизатора Hugging Face.

Свяжитесь со мной!

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

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

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