Как обучить новую языковую модель с нуля, используя трансформеры и токенизаторы.
За последние несколько месяцев мы внесли ряд улучшений в наши библиотеки трансформеров и токенизаторов с целью максимально упростить обучение новой языковой модели с нуля .
В этом посте мы продемонстрируем, как обучить «небольшую» модель (84 млн параметров = 6 слоев, размер скрытого слоя 768, 12 механизмов внимания) — это такое же количество слоев и механизмов внимания, как в DistilBERT — на примере эсперанто . Затем мы дообучим модель на задаче определения частей речи.
Эсперанто — это искусственный язык, цель которого — сделать его простым в изучении. Мы выбрали его для этой демонстрации по нескольким причинам:
- Это язык с относительно небольшими ресурсами (хотя на нём говорят около 2 миллионов человек), поэтому эта демонстрация менее скучна, чем обучение ещё одной модели английского языка 😁
- Его грамматика отличается высокой регулярностью (например, все нарицательные существительные оканчиваются на -o, все прилагательные — на -a), поэтому мы должны получить интересные лингвистические результаты даже на небольшом наборе данных.
- Наконец, главная цель, лежащая в основе языка, — сближение людей (содействие миру во всем мире и международному взаимопониманию), что, как можно утверждать, совпадает с целью сообщества НЛП 💚
Примечание: Вам не нужно знать эсперанто, чтобы понять этот пост, но если вы хотите его выучить, у Duolingo есть отличный курс с 280 тысячами активных пользователей.
Наша модель будет называться… подождите… ЭсперБерто 😂

1. Найдите набор данных.
Для начала найдем корпус текста на эсперанто. Здесь мы будем использовать эсперанто-часть корпуса OSCAR от INRIA. OSCAR — это огромный многоязычный корпус, полученный путем классификации и фильтрации данных, собранных в результате сканирования веб-страниц (Common Crawl dumps).

Объем эсперанто-части набора данных составляет всего 299 МБ, поэтому мы объединим его с подкорпусом эсперанто из Лейпцигской коллекции корпусов, который состоит из текстов из различных источников, таких как новости, литература и Википедия.
Итоговый обучающий корпус имеет размер 3 ГБ, что все еще мало — для вашей модели вы получите лучшие результаты, чем больше данных вы сможете использовать для предварительного обучения.
2. Обучить токенизатор
Мы решили обучить токенизатор, кодирующий пары байтов на уровне байтов (аналогичный GPT-2), с теми же специальными токенами, что и RoBERTa. Давайте произвольно выберем его размер равным 52 000.
Мы рекомендуем обучать BPE на уровне байтов (а не, скажем, токенизатор WordPiece, такой как BERT), потому что он начнет формировать свой словарь с алфавита из отдельных байтов, поэтому все слова будут разлагаться на токены (больше никаких токенов
#! pip install tokenizers from pathlib import Path from tokenizers import ByteLevelBPETokenizer paths = [ str (x) for x in Path( «./eo_data/» ).glob( «**/*.txt» )] # Инициализация токенизатора tokenizer = ByteLevelBPETokenizer() # Настройка обучения tokenizer.train(files=paths, vocab_size= 52_000 , min_frequency= 2 , special_tokens=[ «« , «
А вот немного ускоренная запись результата:
На нашем наборе данных обучение заняло около 5 минут.
🔥🔥 Вау, как быстро! ⚡️🔥
Теперь у нас есть и файл vocab.json, представляющий собой список наиболее часто встречающихся токенов, ранжированных по частоте, и файл merges.txt, содержащий список слияний.
{ «« : 0 , «
Замечательно то, что наш токенизатор оптимизирован для эсперанто. По сравнению с универсальным токенизатором, обученным для английского языка, больше слов, принадлежащих к этому языку, представлены одним неразделённым токеном. Диакритические знаки, то есть символы с ударением, используемые в эсперанто – ĉ, ĝ, ĥ, ĵ, ŝ и ŭ – кодируются естественным образом. Мы также представляем последовательности более эффективно. В этом корпусе средняя длина закодированных последовательностей примерно на 30% меньше, чем при использовании предварительно обученного токенизатора GPT-2.
Вот как его можно использовать в токенизаторах, включая обработку специальных токенов RoBERTa — разумеется, вы также сможете использовать его напрямую из трансформеров.
from tokenizers.implementations import ByteLevelBPETokenizer from tokenizers.processors import BertProcessing tokenizer = ByteLevelBPETokenizer( «./models/EsperBERTo-small/vocab.json» , «./models/EsperBERTo-small/merges.txt» , ) tokenizer._tokenizer.post_processor = BertProcessing( ( «« , tokenizer.token_to_id( «« )), ( «« , tokenizer.token_to_id( «« )), ) tokenizer.enable_truncation(max_length= 512 ) print ( tokenizer.encode( «Mi estas Julien.» ) ) # Encoding(num_tokens=7, …) # tokens: ['', 'Mi', 'Ġestas', 'ĠJuli', 'en', '.', '']
3. Обучить языковую модель с нуля.
Обновление: В связанном блокноте Colab используется наш новый инструмент обучения напрямую, а не через скрипт. Вы можете выбрать тот подход, который вам больше нравится.
Теперь мы будем обучать нашу языковую модель, используя скрипт run_language_modeling.py из библиотеки transformers (переименованный из run_lm_finetuning.py, поскольку теперь он более удобно поддерживает обучение с нуля). Просто не забудьте оставить параметр —model_name_or_path в значении None, чтобы обучать модель с нуля, а не с использованием существующей модели или контрольной точки.
Мы будем обучать модель, похожую на RoBERTa, которая, в свою очередь, является моделью, аналогичной BERT, с некоторыми изменениями (подробнее см. в документации).
Поскольку модель похожа на BERT, мы будем обучать её на задаче маскированного языкового моделирования, то есть на предсказании того, как заполнить произвольные токены, которые мы случайным образом маскируем в наборе данных. Это предусмотрено в примере скрипта.
Нам нужно сделать всего две вещи:
- Реализуйте простой подкласс класса Dataset, который загружает данные из наших текстовых файлов.
- В зависимости от ваших задач, вам может даже не понадобиться писать собственный подкласс Dataset, если один из предоставленных примеров (TextDataset и LineByLineTextDataset) работает — но существует множество пользовательских настроек, которые вы можете добавить в зависимости от структуры вашего корпуса.
- Выберите и поэкспериментируйте с различными наборами гиперпараметров.
Вот упрощенная версия нашего набора данных EsperantoDataset.
from torch.utils.data import Dataset class EsperantoDataset ( Dataset ): def __init__ ( self, evaluate: bool = False ): tokenizer = ByteLevelBPETokenizer( «./models/EsperBERTo-small/vocab.json» , «./models/EsperBERTo-small/merges.txt» , ) tokenizer._tokenizer.post_processor = BertProcessing( ( «« , tokenizer.token_to_id( «« )), ( «« , tokenizer.token_to_id( «« )), ) tokenizer.enable_truncation(max_length= 512 ) # или используйте RobertaTokenizer из `transformers` напрямую. self.examples = [] src_files = Path( «./data/» ).glob( «*-eval.txt» ) if evaluate else Path( «./data/» ).glob( «*-train.txt» ) for src_file in src_files: print ( «🔥» , src_file) lines = src_file.read_text(encoding= «utf-8» ).splitlines() self.examples += [x.ids for x in tokenizer.encode_batch(lines)] def __len__ ( self ): return len (self.examples) def __getitem__ ( self, i ): # Мы будем дополнять на уровне пакета. return torch.tensor(self.examples[i])
Если ваш набор данных очень большой, вы можете выбрать загрузку и токенизацию примеров на лету, а не в качестве этапа предварительной обработки.
Вот один из конкретных наборов гиперпараметров и аргументов, которые мы передаем скрипту:
—output_dir ./models/EsperBERTo-small-v1 —model_type roberta —mlm —config_name ./models/EsperBERTo-small —tokenizer_name ./models/EsperBERTo-small —do_train —do_eval —learning_rate 1e-4 —num_train_epochs 5 —save_total_limit 2 —save_steps 2000 —per_gpu_train_batch_size 16 —evaluate_during_training —seed 42
Как обычно, выбирайте максимальный размер партии, который поместится на вашей видеокарте (картах).
🔥🔥🔥 Начнём тренировку!! 🔥🔥🔥
Здесь вы можете посмотреть наш Tensorboard для одного конкретного набора гиперпараметров:

В наших примерах скрипты по умолчанию записывают данные в формат Tensorboard в папку runs/. Затем, чтобы просмотреть свою доску, просто выполните команду tensorboard dev upload —logdir runs – это настроит tensorboard.dev, управляемую Google версию, которая позволяет делиться вашим экспериментом машинного обучения с кем угодно.
4. Убедитесь, что LM действительно прошел обучение.
Помимо анализа снижения ошибок обучения и оценки, самый простой способ проверить, учится ли наша языковая модель чему-либо интересному, — это использовать FillMaskPipeline.
Конвейеры обработки данных — это простые обертки над токенизаторами и моделями, и конвейер 'fill-mask' позволит вам ввести последовательность, содержащую замаскированный токен (здесь
from transformers import pipeline fill_mask = pipeline( «fill-mask» , model= «./models/EsperBERTo-small» , tokenizer= «./models/EsperBERTo-small» ) # Солнце <маска>. # => result = fill_mask( «La suno La suno brilis.', 'token': 10820} # {'score': 0.0999930202960968, 'sequence': ' La suno lumis.', 'token': 23833} # {'score': 0.04382849484682083, 'sequence': ' La suno brilas.', 'token': 15006} # {'score': 0.026011141017079353, 'sequence': ' La suno falas.', 'token': 7392} # {'score': 0.016859788447618484, 'sequence': ' La suno pasis.', 'token': 4552}
Хорошо, простой синтаксис/грамматика подойдут. Давайте попробуем чуть более интересный вариант:
fill_mask( «Jen la komenco de bela Jen la komenco de bela vivo.' # 'token':1099 # } # { # 'score':0.0421181358397007 # 'sequence':' Jen la komenco de bela vespero.' # 'token':5100 # } # { # 'score':0.024884626269340515 # 'sequence':' Джен ла коменко де бела трудо.' # 'token':1570 # } # { # 'score':0.02324388362467289 # 'sequence':' Джен ла коменко де бела таго.' # 'token':1688 # } # { # 'score':0.020378097891807556 # 'sequence':' Джен ла коменко де бела фесто.' # 'token':4580 # }
« Jen la komenco de bela tago », действительно!
При использовании более сложных запросов вы можете проверить, насколько ваша языковая модель отражает семантические знания или даже какие-либо (статистические) рассуждения, основанные на здравом смысле.
5. Доработайте свою языковую модель для выполнения последующей задачи.
Теперь мы можем доработать нашу новую модель языка эсперанто для решения задачи определения частей речи.
Как уже упоминалось, эсперанто — это язык с высокой степенью регулярности, где окончания слов обычно определяют грамматическую часть речи. Используя набор данных аннотированных тегов частей речи эсперанто, отформатированных в формате CoNLL-2003 (см. пример ниже), мы можем использовать скрипт run_ner.py из библиотеки transformers.
POS-тегирование — это задача классификации токенов, как и NER, поэтому мы можем использовать тот же самый скрипт.

Вот снова размещенная таблица Tensorboard для этой тонкой настройки. Мы обучаем модель в течение 3 эпох, используя размер пакета 64 на каждый графический процессор.
Потери при обучении и оценке сходятся к небольшим остаточным значениям, поскольку задача довольно простая (язык регулярный) – и все равно интересно иметь возможность обучать ее от начала до конца 😃.
На этот раз воспользуемся TokenClassificationPipeline:
from transformers import TokenClassificationPipeline, pipeline MODEL_PATH = «./models/EsperBERTo-small-pos/» nlp = pipeline( «ner» , model=MODEL_PATH, tokenizer=MODEL_PATH, ) # или создать экземпляр TokenClassificationPipeline напрямую. nlp( «Mi estas viro kej estas tago varma.» ) # {'entity': 'PRON', 'score': 0.9979867339134216, 'word': ' Mi'} # {'entity': 'VERB', 'score': 0.9683094620704651, 'word': ' estas'} # {'entity': 'VERB', 'score': 0.9797462821006775, 'word': ' estas'} # {'entity': 'NOUN', 'score': 0.8509314060211182, 'word': ' tago'} # {'entity': 'ADJ', 'score': 0.9996201395988464, 'word': 'varma'}
Похоже, всё получилось! 🔥
Для более сложного набора данных для распознавания именованных сущностей @stefan-it порекомендовал использовать для обучения стандартный набор данных от WikiANN.
6. Поделитесь своей моделью 🎉
Наконец, если у вас есть хорошая модель, пожалуйста, подумайте о том, чтобы поделиться ею с сообществом:
- Загрузите свою модель с помощью CLI: transformers-cli upload
- Напишите файл README.md с описанием модели и добавьте его в репозиторий в папку model_cards/. В идеале ваша карточка модели должна включать:
- описание модели,
- Параметры обучения (набор данных, предварительная обработка, гиперпараметры),
- результаты оценки,
- предполагаемое использование и ограничения
- Всё остальное, что может пригодиться! 🤓
ТАДА!
➡️ Ваша модель размещена на странице https://huggingface.co/models, и каждый может загрузить её, используя AutoModel.from_pretrained(«username/model_name»).

Если вы хотите посмотреть модели на разных языках, перейдите по ссылке https://huggingface.co/models

Спасибо!


Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.