Buckets:
| # Создание токенизатора, блок за блоком[[building-a-tokenizer-block-by-block]] | |
| <CourseFloatingBanner chapter={6} | |
| classNames="absolute z-10 right-0 top-0" | |
| notebooks={[ | |
| {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter6/section8.ipynb"}, | |
| {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter6/section8.ipynb"}, | |
| ]} /> | |
| Как мы уже видели в предыдущих разделах, токенизация состоит из нескольких этапов: | |
| - Нормализация (любая необходимая очистка текста, например, удаление пробелов или подчеркиваний, нормализация Unicode и т. д.) | |
| - Предварительная токенизация (разделение входного текста на слова). | |
| - Прогон входных данных через модель (использование предварительно токенизированных слов для создания последовательности токенов) | |
| - Постобработка (добавление специальных токенов токенизатора, генерация маски внимания и идентификаторов типов токенов) | |
| В качестве напоминания вот еще один взгляд на общий процесс: | |
| <div class="flex justify-center"> | |
| <img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter6/tokenization_pipeline.svg" alt="The tokenization pipeline."> | |
| <img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter6/tokenization_pipeline-dark.svg" alt="The tokenization pipeline."> | |
| </div> | |
| Библиотека 🤗 Tokenizers была создана для того, чтобы предоставить несколько вариантов каждого из этих шагов, которые вы можете смешивать и сочетать между собой. В этом разделе мы рассмотрим, как можно создать токенизатор с нуля, а не обучать новый токенизатор на основе старого, как мы делали в [разделе 2](../chapter6/2). После этого вы сможете создать любой токенизатор, который только сможете придумать! | |
| <Youtube id="MR8tZm5ViWU"/> | |
| Точнее, библиотека построена вокруг центрального класса `Tokenizer`, а строительные блоки сгруппированы в подмодули: | |
| - `normalizers` содержит все возможные типы нормализаторов текста `Normalizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/api/normalizers)). | |
| - `pre_tokenizers` содержит все возможные типы предварительных токенизаторов `PreTokenizer`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/api/pre-tokenizers)). | |
| - `models` содержит различные типы моделей `Model`, которые вы можете использовать, такие как `BPE`, `WordPiece` и `Unigram` (полный список [здесь](https://huggingface.co/docs/tokenizers/api/models)). | |
| - `trainers` содержит все различные типы `Trainer`, которые вы можете использовать для обучения модели на корпусе (по одному на каждый тип модели; полный список [здесь](https://huggingface.co/docs/tokenizers/api/trainers)). | |
| - `post_processors` содержит различные типы постпроцессоров `PostProcessor`, которые вы можете использовать (полный список [здесь](https://huggingface.co/docs/tokenizers/api/post-processors)). | |
| - `decoders` содержит различные типы декодеров `Decoder`, которые вы можете использовать для декодирования результатов токенизации (полный список [здесь](https://huggingface.co/docs/tokenizers/components#decoders)). | |
| Весь список блоков вы можете найти [здесь](https://huggingface.co/docs/tokenizers/components). | |
| ## Получение корпуса текста[[acquiring-a-corpus]] | |
| Для обучения нашего нового токенизатора мы будем использовать небольшой корпус текстов (чтобы примеры выполнялись быстро). Шаги по сбору корпуса аналогичны тем, что мы делали в [начале этой главы](../chapter6/2), но на этот раз мы будем использовать набор данных [WikiText-2](https://huggingface.co/datasets/wikitext): | |
| ```python | |
| from datasets import load_dataset | |
| dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train") | |
| def get_training_corpus(): | |
| for i in range(0, len(dataset), 1000): | |
| yield dataset[i : i + 1000]["text"] | |
| ``` | |
| Функция `get_training_corpus()` - это генератор, который выдает батч из 1000 текстов, которые мы будем использовать для обучения токенизатора. | |
| 🤗 Токенизаторы также можно обучать непосредственно на текстовых файлах. Вот как мы можем сгенерировать текстовый файл, содержащий все тексты/входы из WikiText-2, который мы можем использовать локально: | |
| ```python | |
| with open("wikitext-2.txt", "w", encoding="utf-8") as f: | |
| for i in range(len(dataset)): | |
| f.write(dataset[i]["text"] + "\n") | |
| ``` | |
| Далее мы покажем вам, как блок за блоком построить собственные токенизаторы BERT, GPT-2 и XLNet. Это даст нам пример каждого из трех основных алгоритмов токенизации: WordPiece, BPE и Unigram. Начнем с BERT! | |
| ## Создание токенизатора WordPiece с нуля[[building-a-wordpiece-tokenizer-from-scratch]] | |
| Чтобы создать токенизатор с помощью библиотеки 🤗 Tokenizers, мы начнем с инстанцирования объектов `Tokenizer` и `model`, затем установим для их атрибутов `normalizer`, `pre_tokenizer`, `post_processor` и `decoder` нужные нам значения. | |
| Для этого примера мы создадим `Tokenizer` с моделью WordPiece: | |
| ```python | |
| from tokenizers import ( | |
| decoders, | |
| models, | |
| normalizers, | |
| pre_tokenizers, | |
| processors, | |
| trainers, | |
| Tokenizer, | |
| ) | |
| tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]")) | |
| ``` | |
| Мы должны указать `unk_token`, чтобы модель знала, что возвращать, когда она встречает символы, которых раньше не видела. Другие аргументы, которые мы можем задать здесь, включают `vocab` нашей модели (мы собираемся обучать модель, поэтому нам не нужно его задавать) и `max_input_chars_per_word`, который определяет максимальную длину для каждого слова (слова длиннее переданного значения будут разбиты на части). | |
| Первым шагом токенизации является нормализация, поэтому начнем с нее. Поскольку BERT широко используется, существует `BertNormalizer` с классическими параметрами, которые мы можем установить для BERT: `lowercase` и `strip_accents`, которые не требуют пояснений; `clean_text` для удаления всех управляющих символов и замены повторяющихся пробелов на один; и `handle_chinese_chars`, который расставляет пробелы вокруг китайских символов. Чтобы повторить токенизатор `bert-base-uncased`, мы можем просто установить этот нормализатор: | |
| ```python | |
| tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) | |
| ``` | |
| Однако, как правило, при создании нового токенизатора у вас не будет доступа к такому удобному нормализатору, уже реализованному в библиотеке 🤗 Tokenizers, поэтому давайте посмотрим, как создать нормализатор BERT вручную. Библиотека предоставляет нормализатор `Lowercase` и нормализатор `StripAccents`, и вы можете комбинировать несколько нормализаторов с помощью `Sequence`: | |
| ```python | |
| tokenizer.normalizer = normalizers.Sequence( | |
| [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()] | |
| ) | |
| ``` | |
| Мы также используем нормализатор Unicode `NFD`, поскольку в противном случае нормализатор `StripAccents` не сможет правильно распознать акцентированные символы и, следовательно, не удалит их. | |
| Как мы уже видели ранее, мы можем использовать метод `normalize_str()` нормализатора, чтобы проверить, как он влияет на данный текст: | |
| ```python | |
| print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) | |
| ``` | |
| ```python out | |
| hello how are u? | |
| ``` | |
| > [!TIP] | |
| > **Далее** если вы протестируете две версии предыдущих нормализаторов на строке, содержащей символ Unicode `u"\u0085"`, то наверняка заметите, что эти два нормализатора не совсем эквивалентны. | |
| > Чтобы не усложнять версию с `normalizers.Sequence`, мы не включили в нее Regex-замены, которые требует `BertNormalizer`, когда аргумент `clean_text` установлен в `True`, что является поведением по умолчанию. Но не волнуйтесь: можно получить точно такую же нормализацию без использования удобного `BertNormalizer`, добавив два `normalizers.Replace` в последовательность нормализаторов. | |
| Далее следует этап предварительной токенизации. Опять же, есть готовый `BertPreTokenizer`, который мы можем использовать: | |
| ```python | |
| tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() | |
| ``` | |
| Или мы можем создать его с нуля: | |
| ```python | |
| tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() | |
| ``` | |
| Обратите внимание, что токенизатор `Whitespace` разделяет пробельные символы и все символы, которые не являются буквами, цифрами или символом подчеркивания, поэтому технически он разделяет пробельные символы и знаки пунктуации: | |
| ```python | |
| tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") | |
| ``` | |
| ```python out | |
| [('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), | |
| ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] | |
| ``` | |
| Если вы хотите выполнять разделение только по пробельным символам, то вместо этого следует использовать предварительный токенизатор `WhitespaceSplit`: | |
| ```python | |
| pre_tokenizer = pre_tokenizers.WhitespaceSplit() | |
| pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") | |
| ``` | |
| ```python out | |
| [("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))] | |
| ``` | |
| Как и в случае с нормализаторами, вы можете использовать `Sequence` для комбинирования нескольких предварительных токенизаторов: | |
| ```python | |
| pre_tokenizer = pre_tokenizers.Sequence( | |
| [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()] | |
| ) | |
| pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") | |
| ``` | |
| ```python out | |
| [('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), | |
| ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] | |
| ``` | |
| Следующий шаг в конвейере токенизации - обработка входных данных с помощью модели. Мы уже указали нашу модель в инициализации, но нам все еще нужно обучить ее, для чего потребуется `WordPieceTrainer`. Главное, что нужно помнить при инстанцировании тренера в 🤗 Tokenizers, это то, что вам нужно передать ему все специальные токены, которые вы собираетесь использовать - иначе он не добавит их в словарь, поскольку их нет в обучающем корпусе: | |
| ```python | |
| special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] | |
| trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens) | |
| ``` | |
| Помимо указания `vocab_size` и `special_tokens`, мы можем задать `min_frequency` (количество раз, которое должен встретиться токен, чтобы быть включенным в словарь) или изменить `continuing_subword_prefix` (если мы хотим использовать что-то отличное от `##`). | |
| Чтобы обучить нашу модель с помощью итератора, который мы определили ранее, достаточно выполнить эту команду: | |
| ```python | |
| tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) | |
| ``` | |
| Мы также можем использовать текстовые файлы для обучения нашего токенизатора, что будет выглядеть следующим образом (предварительно мы повторно инициализируем модель с пустым `WordPiece`): | |
| ```python | |
| tokenizer.model = models.WordPiece(unk_token="[UNK]") | |
| tokenizer.train(["wikitext-2.txt"], trainer=trainer) | |
| ``` | |
| В обоих случаях мы можем проверить работу токенизатора на тексте, вызвав метод `encode()`: | |
| ```python | |
| encoding = tokenizer.encode("Let's test this tokenizer.") | |
| print(encoding.tokens) | |
| ``` | |
| ```python out | |
| ['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.'] | |
| ``` | |
| Полученное `encoding` представляет собой `Encoding`, которое содержит все необходимые результаты работы токенизатора в разных атрибутах: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask` и `overflowing`. | |
| Последний шаг в конвейере токенизации - постобработка. Нам нужно добавить токен `[CLS]` в начале и токен `[SEP]` в конце (или после каждого предложения, если у нас есть пара предложений). Для этого мы будем использовать `TemplateProcessor`, но сначала нам нужно узнать идентификаторы токенов `[CLS]` и `[SEP]` в словаре: | |
| ```python | |
| cls_token_id = tokenizer.token_to_id("[CLS]") | |
| sep_token_id = tokenizer.token_to_id("[SEP]") | |
| print(cls_token_id, sep_token_id) | |
| ``` | |
| ```python out | |
| (2, 3) | |
| ``` | |
| Чтобы написать шаблон для `TemplateProcessor`, мы должны указать, как обрабатывать одно предложение и пару предложений. Для обоих случаев мы указываем специальные токены, которые мы хотим использовать; первое (или одиночное) предложение представлено `$A`, а второе предложение (если кодируется пара) представлено `$B`. Для каждого из них (специальных токенов и предложений) мы также указываем соответствующий идентификатор типа токена (token type ID) после двоеточия. | |
| Таким образом, классический шаблон BERT определяется следующим образом: | |
| ```python | |
| tokenizer.post_processor = processors.TemplateProcessing( | |
| single=f"[CLS]:0 $A:0 [SEP]:0", | |
| pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1", | |
| special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)], | |
| ) | |
| ``` | |
| Обратите внимание, что нам нужно передать идентификаторы специальных токенов, чтобы токенизатор мог правильно преобразовать их в их идентификаторы. | |
| Как только это будет добавлено, вернемся к нашему предыдущему примеру: | |
| ```python | |
| encoding = tokenizer.encode("Let's test this tokenizer.") | |
| print(encoding.tokens) | |
| ``` | |
| ```python out | |
| ['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]'] | |
| ``` | |
| И на паре предложений мы получаем правильный результат: | |
| ```python | |
| encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.") | |
| print(encoding.tokens) | |
| print(encoding.type_ids) | |
| ``` | |
| ```python out | |
| ['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]'] | |
| [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] | |
| ``` | |
| Мы почти закончили создание этого токенизатора с нуля - остался последний шаг - добавить декодер: | |
| ```python | |
| tokenizer.decoder = decoders.WordPiece(prefix="##") | |
| ``` | |
| Давайте проверим его на нашем предыдущем `encoding`: | |
| ```python | |
| tokenizer.decode(encoding.ids) | |
| ``` | |
| ```python out | |
| "let's test this tokenizer... on a pair of sentences." | |
| ``` | |
| Отлично! Мы можем сохранить наш токенизатор в единственном JSON-файле следующим образом: | |
| ```python | |
| tokenizer.save("tokenizer.json") | |
| ``` | |
| Затем мы можем загрузить этот файл в объект `Tokenizer` с помощью метода `from_file()`: | |
| ```python | |
| new_tokenizer = Tokenizer.from_file("tokenizer.json") | |
| ``` | |
| Чтобы использовать этот токенизатор в 🤗 Transformers, мы должны обернуть его в `PreTrainedTokenizerFast`. Мы можем использовать либо общий класс, либо, если наш токенизатор соответствует существующей модели, использовать этот класс (здесь `BertTokenizerFast`). Если вы используете этот урок для создания нового токенизатора, вам придется использовать первый вариант. | |
| Чтобы обернуть токенизатор в `PreTrainedTokenizerFast`, мы можем либо передать собранный нами токенизатор как `tokenizer_object`, либо передать сохраненный файл токенизатора как `tokenizer_file`. Главное помнить, что нам придется вручную задавать все специальные токены, поскольку класс не может определить из объекта `tokenizer`, какой токен является токеном маски, токеном `[CLS]` и т. д.: | |
| ```python | |
| from transformers import PreTrainedTokenizerFast | |
| wrapped_tokenizer = PreTrainedTokenizerFast( | |
| tokenizer_object=tokenizer, | |
| # tokenizer_file="tokenizer.json", # В качестве альтернативы можно загрузить из файла токенизатора. | |
| unk_token="[UNK]", | |
| pad_token="[PAD]", | |
| cls_token="[CLS]", | |
| sep_token="[SEP]", | |
| mask_token="[MASK]", | |
| ) | |
| ``` | |
| Если вы используете определенный класс токенизатора (например, `BertTokenizerFast`), вам нужно будет указать только специальные токены, которые отличаются от токенов по умолчанию (здесь их нет): | |
| ```python | |
| from transformers import BertTokenizerFast | |
| wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) | |
| ``` | |
| Затем вы можете использовать этот токенизатор, как и любой другой токенизатор 🤗 Transformers. Вы можете сохранить его с помощью метода `save_pretrained()` или загрузить на хаб с помощью метода `push_to_hub()`. | |
| Теперь, когда мы рассмотрели, как создать токенизатор WordPiece, давайте сделаем то же самое для токенизатора BPE. Мы будем двигаться немного быстрее, поскольку вы знаете все шаги, и подчеркнем только различия. | |
| ## Создание токенизатора BPE с нуля[[building-a-bpe-tokenizer-from-scratch]] | |
| Теперь давайте создадим токенизатор GPT-2. Как и в случае с токенизатором BERT, мы начнем с инициализации `Tokenizer` с моделью BPE: | |
| ```python | |
| tokenizer = Tokenizer(models.BPE()) | |
| ``` | |
| Также, как и в случае с BERT, мы могли бы инициализировать эту модель словарем, если бы он у нас был (в этом случае нам нужно было бы передать `vocab` и `merges`), но поскольку мы будем обучать с нуля, нам не нужно этого делать. Нам также не нужно указывать `unk_token`, потому что GPT-2 использует byte-level BPE, который не требует этого. | |
| GPT-2 не использует нормализатор, поэтому мы пропускаем этот шаг и переходим непосредственно к предварительной токенизации: | |
| ```python | |
| tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) | |
| ``` | |
| Опция, которую мы добавили к `ByteLevel`, заключается в том, чтобы не добавлять пробел в начале предложения (в противном случае это происходит по умолчанию). Мы можем посмотреть на предварительную токенизацию примера текста, как было показано ранее: | |
| ```python | |
| tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") | |
| ``` | |
| ```python out | |
| [('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)), | |
| ('tokenization', (15, 27)), ('!', (27, 28))] | |
| ``` | |
| Далее следует модель, которую нужно обучить. Для GPT-2 единственным специальным токеном является токен конца текста: | |
| ```python | |
| trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"]) | |
| tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) | |
| ``` | |
| Как и в случае с `WordPieceTrainer`, а также `vocab_size` и `special_tokens`, мы можем указать `min_frequency`, если хотим, или если у нас есть суффикс конца слова (например, `</w>`), мы можем задать его с помощью `end_of_word_suffix`. | |
| Этот токенизатор также может быть обучен на текстовых файлах: | |
| ```python | |
| tokenizer.model = models.BPE() | |
| tokenizer.train(["wikitext-2.txt"], trainer=trainer) | |
| ``` | |
| Давайте посмотрим на пример токенизации текста: | |
| ```python | |
| encoding = tokenizer.encode("Let's test this tokenizer.") | |
| print(encoding.tokens) | |
| ``` | |
| ```python out | |
| ['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.'] | |
| ``` | |
| Мы применяем постобработку на уровне байтов для токенизатора GPT-2 следующим образом: | |
| ```python | |
| tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) | |
| ``` | |
| Опция `trim_offsets = False` указывает постпроцессору, что мы должны оставить смещения токенов, начинающихся с 'Ġ', как есть: таким образом, начало смещения будет указывать на пробел перед словом, а не на первый символ слова (поскольку пробел технически является частью токена). Давайте посмотрим на результат с текстом, который мы только что закодировали, где `'Ġtest'` - это токен с индексом 4: | |
| ```python | |
| sentence = "Let's test this tokenizer." | |
| encoding = tokenizer.encode(sentence) | |
| start, end = encoding.offsets[4] | |
| sentence[start:end] | |
| ``` | |
| ```python out | |
| ' test' | |
| ``` | |
| Наконец, мы добавляем декодер на уровне байтов: | |
| ```python | |
| tokenizer.decoder = decoders.ByteLevel() | |
| ``` | |
| и мы сможем перепроверить, правильно ли он работает: | |
| ```python | |
| tokenizer.decode(encoding.ids) | |
| ``` | |
| ```python out | |
| "Let's test this tokenizer." | |
| ``` | |
| Отлично! Теперь, когда мы закончили, мы можем сохранить токенизатор, как раньше, и обернуть его в `PreTrainedTokenizerFast` или `GPT2TokenizerFast`, если мы хотим использовать его в 🤗 Transformers: | |
| ```python | |
| from transformers import PreTrainedTokenizerFast | |
| wrapped_tokenizer = PreTrainedTokenizerFast( | |
| tokenizer_object=tokenizer, | |
| bos_token="<|endoftext|>", | |
| eos_token="<|endoftext|>", | |
| ) | |
| ``` | |
| или: | |
| ```python | |
| from transformers import GPT2TokenizerFast | |
| wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer) | |
| ``` | |
| В качестве последнего примера мы покажем вам, как создать токенизатор Unigram с нуля. | |
| ## Создание токенизатора Unigram с нуля[[building-a-unigram-tokenizer-from-scratch]] | |
| Теперь давайте построим токенизатор XLNet. Как и в предыдущих токенизаторах, мы начнем с инициализации `Tokenizer` с моделью Unigram: | |
| ```python | |
| tokenizer = Tokenizer(models.Unigram()) | |
| ``` | |
| Опять же, мы могли бы инициализировать эту модель словарем, если бы он у нас был. | |
| Для нормализации XLNet использует несколько замен (которые пришли из SentencePiece): | |
| ```python | |
| from tokenizers import Regex | |
| tokenizer.normalizer = normalizers.Sequence( | |
| [ | |
| normalizers.Replace("``", '"'), | |
| normalizers.Replace("''", '"'), | |
| normalizers.NFKD(), | |
| normalizers.StripAccents(), | |
| normalizers.Replace(Regex(" {2,}"), " "), | |
| ] | |
| ) | |
| ``` | |
| Он заменяет <code>``</code> и <code>''</code> with <code>"</code> и любую последовательность из двух или более пробелов на один пробел, а также удаляет ударения в токенезируемых текстах. | |
| Предварительный токенизатор, который должен использоваться для любого токенизатора SentencePiece, - это `Metaspace`: | |
| ```python | |
| tokenizer.pre_tokenizer = pre_tokenizers.Metaspace() | |
| ``` | |
| Мы можем посмотреть на предварительную токенизацию примера текста, как было показано ранее: | |
| ```python | |
| tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") | |
| ``` | |
| ```python out | |
| [("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))] | |
| ``` | |
| Далее следует модель, которую нужно обучить. В XLNet довольно много специальных токенов: | |
| ```python | |
| special_tokens = ["<cls>", "<sep>", "<unk>", "<pad>", "<mask>", "<s>", "</s>"] | |
| trainer = trainers.UnigramTrainer( | |
| vocab_size=25000, special_tokens=special_tokens, unk_token="<unk>" | |
| ) | |
| tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) | |
| ``` | |
| Очень важный аргумент, который не стоит забывать для `UnigramTrainer` - это `unk_token`. Мы также можем передавать другие аргументы, специфичные для алгоритма Unigram, такие как `shrinking_factor` для каждого шага удаления токенов (по умолчанию 0.75) или `max_piece_length` для указания максимальной длины данного токена (по умолчанию 16). | |
| Этот токенизатор также может быть обучен на текстовых файлах: | |
| ```python | |
| tokenizer.model = models.Unigram() | |
| tokenizer.train(["wikitext-2.txt"], trainer=trainer) | |
| ``` | |
| Давайте посмотрим на токенизацию примера текста: | |
| ```python | |
| encoding = tokenizer.encode("Let's test this tokenizer.") | |
| print(encoding.tokens) | |
| ``` | |
| ```python out | |
| ['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.'] | |
| ``` | |
| Особенностью XLNet является то, что он помещает токен `<cls>` в конец предложения с идентификатором типа 2 (чтобы отличить его от других токенов). В результате он помещается слева. Мы можем разобраться со всеми специальными токенами и идентификаторами типов токенов с помощью шаблона, как в BERT, но сначала нам нужно получить идентификаторы токенов `<cls>` и `<sep>`: | |
| ```python | |
| cls_token_id = tokenizer.token_to_id("<cls>") | |
| sep_token_id = tokenizer.token_to_id("<sep>") | |
| print(cls_token_id, sep_token_id) | |
| ``` | |
| ```python out | |
| 0 1 | |
| ``` | |
| Шаблон выглядит следующим образом: | |
| ```python | |
| tokenizer.post_processor = processors.TemplateProcessing( | |
| single="$A:0 <sep>:0 <cls>:2", | |
| pair="$A:0 <sep>:0 $B:1 <sep>:1 <cls>:2", | |
| special_tokens=[("<sep>", sep_token_id), ("<cls>", cls_token_id)], | |
| ) | |
| ``` | |
| И мы можем проверить, как это работает, закодировав пару предложений: | |
| ```python | |
| encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!") | |
| print(encoding.tokens) | |
| print(encoding.type_ids) | |
| ``` | |
| ```python out | |
| ['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '<sep>', '▁', 'on', '▁', 'a', '▁pair', | |
| '▁of', '▁sentence', 's', '!', '<sep>', '<cls>'] | |
| [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] | |
| ``` | |
| Наконец, мы добавляем декодер `Metaspace`: | |
| ```python | |
| tokenizer.decoder = decoders.Metaspace() | |
| ``` | |
| и мы закончили работу с этим токенизатором! Мы можем сохранить токенизатор, как и раньше, и обернуть его в `PreTrainedTokenizerFast` или `XLNetTokenizerFast`, если мы хотим использовать его в 🤗 Transformers. При использовании `PreTrainedTokenizerFast` следует обратить внимание на то, что помимо специальных токенов, нам нужно указать библиотеке 🤗 Transformers на то, чтобы они располагались слева: | |
| ```python | |
| from transformers import PreTrainedTokenizerFast | |
| wrapped_tokenizer = PreTrainedTokenizerFast( | |
| tokenizer_object=tokenizer, | |
| bos_token="<s>", | |
| eos_token="</s>", | |
| unk_token="<unk>", | |
| pad_token="<pad>", | |
| cls_token="<cls>", | |
| sep_token="<sep>", | |
| mask_token="<mask>", | |
| padding_side="left", | |
| ) | |
| ``` | |
| Или альтернативно: | |
| ```python | |
| from transformers import XLNetTokenizerFast | |
| wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer) | |
| ``` | |
| Теперь, когда вы увидели, как различные блоки используются для создания существующих токенизаторов, вы должны быть в состоянии написать любой токенизатор, который вы хотите, с помощью библиотеки 🤗 Tokenizers и использовать его в 🤗 Transformers. | |
| <EditOnGithub source="https://github.com/huggingface/course/blob/main/chapters/ru/chapter6/8.mdx" /> |
Xet Storage Details
- Size:
- 35.7 kB
- Xet hash:
- a548356e6aa3dcb1b19502370565fb8ece58374282473b9d35100665f7ef4ecc
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.