Навчальний посібник: Як тренувати мовну модель RoBERTa для іспанської мови

SpanBERTa: Як ми з нуля навчили мовну модель RoBERTa для іспанської мови

    Originally published by Skim AI's Machine Learning Research Intern, Chris Tran.



spanberta_підготовка_берта_з_нуля





Запустіть в Google Colab

Вступ

Методи самонавчання за допомогою моделей-трансформерів досягли найсучасніших результатів у виконанні більшості завдань НЛП. Однак, оскільки їхнє навчання вимагає значних обчислювальних витрат, більшість доступних на сьогоднішній день моделей-трансформерів доступні лише для англійської мови. Тому, щоб покращити ефективність виконання завдань НЛП в наших проектах іспанською мовою, моя команда в Скіммі ШІ вирішив тренувати Роберта мовну модель для іспанської мови з нуля і назвали її SpanBERTa.

SpanBERTa має такий самий розмір, як і RoBERTa-base. Ми використовували схему навчання RoBERTa, щоб навчити модель на 18 ГБ дискового простору ОСКАРіспанського корпусу за 8 днів на 4 графічних процесорах Tesla P100.

У цьому блозі ми розглянемо наскрізний процес навчання BERT-подібної мовної моделі з нуля, використовуючи трансформатори і токенізатори бібліотеки Hugging Face. Існує також блокнот Google Colab для безпосереднього запуску кодів у цій статті. Ви також можете модифікувати блокнот відповідним чином, щоб навчити BERT-подібну модель для інших мов або налаштувати її на вашому власному наборі даних.

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

Налаштування

1. Встановлення залежностей

У [0]:

%%capture
!pip uninstall -y tensorflow
!pip install transformers==2.8.0

2. Дані

Ми попередньо навчили SpanBERTa ОСКАРіспанського корпусу. Повний розмір набору даних становить 150 ГБ, і ми використали частину з 18 ГБ для тренування.

У цьому прикладі, для простоти, ми використаємо набір даних іспанських субтитрів до фільмів з OpenSubtitles. Цей набір даних має розмір 5.4 ГБ, і ми будемо тренуватися на підмножині розміром ~300 МБ.
У [0]:

import os
# Download and unzip movie substitle dataset
if not os.path.exists('data/dataset.txt'):
  !wget "https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2016/mono/es.txt.gz" -O dataset.txt.gz
  !gzip -d dataset.txt.gz
  !mkdir data
  !mv dataset.txt data
--2020-04-06 15:53:04-- https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2016/mono/es.txt.gz
Вирішення проблеми object.pouta.csc.fi (object.pouta.csc.fi)... 86.50.254.18, 86.50.254.19
Підключення до object.pouta.csc.fi (object.pouta.csc.fi)|86.50.254.18|:443... встановлено.
HTTP-запит відправлено, чекаємо на відповідь... 200 OK
Довжина: 1859673728 (1.7G) [application/gzip]
Збереження до: 'dataset.txt.gz'

dataset.txt.gz 100%[===================>] 1.73G 17.0MB/s за 1m 46s

2020-04-06 15:54:51 (16.8 МБ/с) - 'dataset.txt.gz' збережено [1859673728/1859673728]

У [0]:

# Total number of lines and some random lines
!wc -l data/dataset.txt
!shuf -n 5 data/dataset.txt
179287150 data/dataset.txt
Sabes, pensé que tenías más pelotas que para enfrentarme a través de mi hermano.
Supe todos los encantamientos en todos las lenguas de los Elfos hombres y Orcos.
Anteriormente en Blue Bloods:
Я хочу, щоб ви пообіцяли, що не матимете жодних справ з Деніелом Стаффордом.
Fue comiquísimo.

У [0]:

# Get a subset of first 1,000,000 lines for training
TRAIN_SIZE = 1000000 #@param {type:"integer"}
!(head -n $TRAIN_SIZE data/dataset.txt) > data/train.txt

У [0]:

# Get a subset of next 10,000 lines for validation
VAL_SIZE = 10000 #@param {type:"integer"}
!(sed -n {TRAIN_SIZE + 1},{TRAIN_SIZE + VAL_SIZE}p data/dataset.txt) > data/dev.txt

3. Навчити токенізаторів

Оригінальна реалізація BERT використовує токенізатор WordPiece зі словником на 32 тисячі підслівників. Цей метод, однак, може вводити "невідомі" лексеми при обробці рідкісних слів.

У цій реалізації ми використовуємо байтовий токенізатор BPE зі словником 50 265 одиниць підслівників (так само, як і в RoBERTa-base). Використання байтового рівня BPE дозволяє вивчити словник підслівників невеликого розміру, який може кодувати будь-які вхідні дані без отримання "невідомих" токенів.

Тому що ByteLevelBPETokenizer створює 2 файли ["vocab.json", "merges.txt"]. в той час як BertWordPieceTokenizer створює лише 1 файл vocab.txtце призведе до помилки, якщо ми використаємо BertWordPieceTokenizer для завантаження виходів токенізатора BPE.
У [0]:

%%time
from tokenizers import ByteLevelBPETokenizer
path = "data/train.txt"
# Initialize a tokenizer
tokenizer = ByteLevelBPETokenizer()
# Customize training
tokenizer.train(files=path,
                vocab_size=50265,
                min_frequency=2,
                special_tokens=["<s>", "<pad>", "</s>", "<unk>", "<mask>"])
# Save files to disk
!mkdir -p "models/roberta"
tokenizer.save("models/roberta")
Час роботи процесора: користувач 1хв 37с, sys: 1.02 с, всього: 1хв 38с
Час роботи на стіні: 1хв 38с

Супершвидко! Поїздка на 10 мільйонах ліній займає лише 2 хвилини.

Модель мови навчання з нуля

1. Архітектура моделі

RoBERTa має точно таку ж архітектуру, як і BERT. Єдина відмінність полягає в наступному:

  • RoBERTa використовує токенізатор BPE байтового рівня з більшим словником підслівників (50k проти 32k).
  • RoBERTa реалізує динамічне маскування слів і відкидає завдання передбачення наступного речення.
  • Гіперпараметри тренування RoBERTa.

Інші конфігурації архітектури можна знайти в документації (Роберта, БЕРТ).
У [0]:

import json
config = {
    "architectures": [
        "RobertaForMaskedLM"
    ],
    "attention_probs_dropout_prob": 0.1,
    "hidden_act": "gelu",
    "hidden_dropout_prob": 0.1,
    "hidden_size": 768,
    "initializer_range": 0.02,
    "intermediate_size": 3072,
    "layer_norm_eps": 1e-05,
    "max_position_embeddings": 514,
    "model_type": "roberta",
    "num_attention_heads": 12,
    "num_hidden_layers": 12,
    "type_vocab_size": 1,
    "vocab_size": 50265
}
with open("models/roberta/config.json", 'w') as fp:
    json.dump(config, fp)
tokenizer_config = {"max_len": 512}
with open("models/roberta/tokenizer_config.json", 'w') as fp:
    json.dump(tokenizer_config, fp)

2. Гіперпараметри тренування

Гіперпараметр BERT-база RoBERTa-base
Довжина послідовності 128, 512 512
Розмір партії 256 8K
Пікова швидкість навчання 1e-4 6e-4
Макс Степс 1M 500K
Етапи розминки 10K 24K
Зниження ваги 0.01 0.01
Adam $epsilon$ 1e-6 1e-6
Adam $beta_1$ 0.9 0.9
Adam $beta_2$ 0.999 0.98
Градієнтне відсікання 0.0 0.0

Зауважте, що розмір партії при навчанні RoBERTa становить 8000. Таким чином, хоча RoBERTa-base була навчена на 500 тис. кроків, обчислювальні витрати на її навчання в 16 разів перевищують витрати на навчання BERT-base. У розділі Папір RoBERTaпоказано, що навчання з великими партіями покращує складність задачі моделювання замаскованої мови, а також точність виконання кінцевого завдання. Більший розмір партії можна отримати, налаштувавши крок_накопичення_градієнта.

Через обчислювальні обмеження ми скористалися схемою навчання BERT-base і навчили нашу модель SpanBERTa на 4 графічних процесорах Tesla P100 за 8 днів, виконавши 200 тис. кроків за 8 днів.

3. Почніть тренування

Ми навчимо нашу модель з нуля, використовуючи run_language_modeling.pyскрипт, наданий Hugging Face, який буде попередньо обробляти, токенізувати корпус і навчати модель на Масковане мовне моделювання завдання. Скрипт оптимізовано для навчання на одному великому корпусі. Тому, якщо ваш набір даних великий і ви хочете розбити його для послідовного навчання, вам потрібно буде модифікувати скрипт, або бути готовим отримати монструозну машину з великим обсягом пам'яті.
У [0]:

# Update April 22, 2020: Hugging Face updated run_language_modeling.py script.
# Please use this version before the update.
!wget -c https://raw.githubusercontent.com/chriskhanhtran/spanish-bert/master/run_language_modeling.py
--2020-04-24 02:28:21-- https://raw.githubusercontent.com/chriskhanhtran/spanish-bert/master/run_language_modeling.py
Вирішення проблеми raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.0.133, 151.101.64.133, 151.101.128.133, ...
Підключення до raw.githubusercontent.com (raw.githubusercontent.com)|151.101.0.133|:443... підключено.
HTTP-запит відправлено, чекаємо на відповідь... 200 OK
Довжина: 34328 (34K) [text/plain]
Збереження до: 'run_language_modeling.py'

run_language_modeling 100%[===================>] 33.52K --.-KB/s за 0.003s

2020-04-24 02:28:21 (10.1 МБ/с) - 'run_language_modeling.py' збережено [34328/34328].

Важливі аргументи

  • --line_by_line Чи обробляти окремі рядки тексту в наборі даних як окремі послідовності. Якщо кожен рядок у вашому наборі даних довгий і містить ~512 токенів або більше, вам слід використовувати цей параметр. Якщо кожен рядок короткий, стандартна попередня обробка тексту об'єднає всі рядки, токенізує їх і розділить токенізовані результати на блоки по 512 токенів. Ви також можете розбити ваші набори даних на невеликі фрагменти і обробити їх окремо. Обробка 3 ГБ тексту займе ~50 хвилин за замовчуванням TextDataset клас.
  • --should_continue Чи продовжувати з останньої контрольної точки в каталозі output_dir.
  • --назва_моделі_або_шлях Контрольна точка моделі для ініціалізації ваг. Залиште значення None, якщо ви хочете навчити модель з нуля.
  • --mlm Тренуйтеся з маскованим мовним моделюванням втрат замість мовного моделювання.
  • --config_name, --tokenizer_name Необов'язковий попередньо навчений конфіг та ім'я або шлях до токенізатора, якщо вони не збігаються з ім'ям_моделі_або_шляхом. Якщо обидва параметри не вказано, ініціалізуйте новий конфіг.
  • --per_gpu_train_batch_size Розмір партії на GPU/CPU для навчання. Виберіть найбільшу кількість, яку ви можете вмістити на своїх графічних процесорах. Ви побачите помилку, якщо розмір партії занадто великий.
  • --gradient_accumulation_steps Кількість кроків оновлення, яку потрібно накопичити перед виконанням проходу назад/оновлення. Ви можете використовувати цей трюк для збільшення розміру пакета. Наприклад, якщо per_gpu_train_batch_size = 16 і gradient_accumulation_steps = 4то загальна кількість поїздів буде дорівнювати 64.
  • --overwrite_output_dir Перезапишіть вміст вихідного каталогу.
  • --no_cuda, --fp16, --fp16_opt_level Аргументи на користь навчання на GPU/CPU.
  • Іншими аргументами є шляхи моделі та гіперпараметри навчання.

Наполегливо рекомендується вказувати тип моделі (наприклад, "roberta", "bert", "gpt2" і т.д.) у шляху до моделі, оскільки скрипт використовує АвтоМоделі щоб вгадати конфігурацію моделі, використовуючи шаблонний пошук за вказаним шляхом.
У [0]:

# Model paths
MODEL_TYPE = "roberta" #@param ["roberta", "bert"]
MODEL_DIR = "models/roberta" #@param {type: "string"}
OUTPUT_DIR = "models/roberta/output" #@param {type: "string"}
TRAIN_PATH = "data/train.txt" #@param {type: "string"}
EVAL_PATH = "data/dev.txt" #@param {type: "string"}

У цьому прикладі ми будемо тренуватися лише 25 кроків на графічному процесорі Tesla P4, наданому Colab.
У [0]:

!nvidia-smi
Пн Квітень 6 15:59:35 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.64.00 Версія драйвера: 418.67 Версія CUDA: 10.1 | |Версія драйвера: 418.67 |Версія CUDA: 10.1
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage| GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla P4 вимкнено | 00000000:00:04.0 вимкнено | 0
| N/A 31C P8 7W / 75W | 0MiB / 7611MiB | 0% За замовчуванням
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Процеси:                                                       Пам'ять графічного процесора
| GPU PID Тип GPU Назва процесу Використання
|=============================================================================|
| Процеси не знайдено.
+-----------------------------------------------------------------------------+

У [0]:

# Command line
cmd = """python run_language_modeling.py 
    --output_dir {output_dir} 
    --model_type {model_type} 
    --mlm 
    --config_name {config_name} 
    --tokenizer_name {tokenizer_name} 
    {line_by_line} 
    {should_continue} 
    {model_name_or_path} 
    --train_data_file {train_path} 
    --eval_data_file {eval_path} 
    --do_train 
    {do_eval} 
    {evaluate_during_training} 
    --overwrite_output_dir 
    --block_size 512 
    --max_step 25 
    --warmup_steps 10 
    --learning_rate 5e-5 
    --per_gpu_train_batch_size 4 
    --gradient_accumulation_steps 4 
    --weight_decay 0.01 
    --adam_epsilon 1e-6 
    --max_grad_norm 100.0 
    --save_total_limit 10 
    --save_steps 10 
    --logging_steps 2 
    --seed 42
"""

У [0]:

# Arguments for training from scratch. I turn off evaluate_during_training,
#   line_by_line, should_continue, and model_name_or_path.
train_params = {
    "output_dir": OUTPUT_DIR,
    "model_type": MODEL_TYPE,
    "config_name": MODEL_DIR,
    "tokenizer_name": MODEL_DIR,
    "train_path": TRAIN_PATH,
    "eval_path": EVAL_PATH,
    "do_eval": "--do_eval",
    "evaluate_during_training": "",
    "line_by_line": "",
    "should_continue": "",
    "model_name_or_path": "",
}

Якщо ви тренуєтеся на віртуальній машині, ви можете встановити tensorboard для моніторингу процесу навчання. Ось наша Тензорна дошка за навчання SpanBERTa.

pip install tensorboard==2.1.0
tensorboard dev upload --logdir runs

Після 200 тис. кроків втрати досягли 1.8, а розгубленість - 5.2.

А тепер почнемо тренування!
У [ ]:

!{cmd.format(**train_params)}
    04/06/2020 15:59:55 - INFO - __main__ - Створення функцій з файлу набору даних за адресою data
    04/06/2020 16:04:43 - INFO - __main__ - Збереження функцій у кешований файл data/roberta_cached_lm_510_train.txt
    04/06/2020 16:04:46 - INFO - __main__ - ***** Тренування з бігу *****
    04/06/2020 16:04:46 - INFO - __main__ - Num examples = 165994
    04/06/2020 16:04:46 - INFO - __main__ - Кількість епох = 1
    04/06/2020 16:04:46 - INFO - __main__ - Миттєвий розмір пакету на GPU = 4
    04/06/2020 16:04:46 - INFO - __main__ - Загальний розмір партії поїздів (з паралельним, розподіленим та накопиченням) = 16
    04/06/2020 16:04:46 - INFO - __main__ - Кроки градієнтного накопичення = 4
    04/06/2020 16:04:46 - INFO - __main__ - Всього кроків оптимізації = 25
    Епоха: 0% 0/1 [00:00<?, ?it/s]
    Ітерація:   0% 0/41499 [00:00<?, ?it/s]
    Ітерація:   0% 1/41499 [00:01<13:18:02, 1.15s/it]
    Ітерація:   0% 2/41499 [00:01<11:26:47, 1.01it/s]
    Ітерація:   0% 3/41499 [00:02<10:10:30, 1.13it/s]
    Ітерація:   0% 4/41499 [00:03<9:38:10, 1.20it/s]
    Ітерація:   0% 5/41499 [00:03<8:52:44, 1.30it/s]
    Ітерація:   0% 6/41499 [00:04<8:22:47, 1.38it/s]
    Ітерація:   0% 7/41499 [00:04<8:00:55, 1.44it/s]
    Ітерація:   0% 8/41499 [00:05<8:03:40, 1.43it/s]
    Ітерація:   0% 9/41499 [00:06<7:46:57, 1.48it/s]
    Ітерація:   0% 10/41499 [00:06<7:35:35, 1.52it/s]
    Ітерація:   0% 11/41499 [00:07<7:28:29, 1.54it/s]
    Ітерація:   0% 12/41499 [00:08<7:41:41, 1.50it/s]
    Ітерація:   0% 13/41499 [00:08<7:34:28, 1.52it/s]
    Ітерація:   0% 14/41499 [00:09<7:28:46, 1.54it/s]
    Ітерація:   0% 15/41499 [00:10<7:23:29, 1.56it/s]
    Ітерація:   0% 16/41499 [00:10<7:38:06, 1.51іт/с]
    Ітерація:   0% 17/41499 [00:11<7:29:13, 1.54it/s]
    Ітерація:   0% 18/41499 [00:12<7:24:04, 1.56іт/с]
    Ітерація:   0% 19/41499 [00:12<7:21:59, 1.56it/s]
    Ітерація:   0% 20/41499 [00:13<7:38:06, 1.51іт/с]
    04/06/2020 16:06:23 - INFO - __main__ - ***** Оцінка виконання *****
    04/06/2020 16:06:23 - INFO - __main__ - Кількість прикладів = 156
    04/06/2020 16:06:23 - INFO - __main__ - Розмір пакету = 4
    Оцінюємо: 100% 39/39 [00:08<00:00, 4.41it/s]
    04/06/2020 16:06:32 - INFO - __main__ - ***** Результати перевірки *****
    04/06/2020 16:06:32 - INFO - __main__ - perplexity = tensor(6077.6812)

4. Прогнозування замаскованих слів

Після тренування мовної моделі ви можете завантажити її та поділитися нею зі спільнотою. Ми завантажили нашу модель SpanBERTa на сервер Hugging Face. Перш ніж оцінювати модель на наступних завданнях, давайте подивимося, як вона навчилася заповнювати замасковані слова з урахуванням контексту.
У [0]:

%%capture
%%time
from transformers import pipeline
fill_mask = pipeline(
    "fill-mask",
    model="chriskhanhtran/spanberta",
    tokenizer="chriskhanhtran/spanberta"
)

Я вибираю речення зі статті Вікіпедії про COVID-19.

Оригінальне речення звучить так: "Часто мийте руки водою та ополіскувачем,"що означає"Часто мийте руки з милом."

Замасковане слово - це "jabón" (мило) і топ-5 прогнозів такі мило, сіль, пар, лимон і оцет. Цікаво, що модель якимось чином засвоює, що ми повинні мити руки речами, які можуть вбивати бактерії або містять кислоту.
У [0]:

fill_mask("Lavarse frecuentemente las manos con agua y <mask>.")

Out[0]:

[{'score': 0.6469631195068359,
  'sequence': ' Lavarse frecuentemente las manos con agua y jabón.',
  'token': 18493},
 {'score': 0.06074320897459984,
  'послідовність': ' Lavarse frecuentemente las manos con agua y sal.',
  'token': 619},
 {'score': 0.029787985607981682,
  'послідовність': ' Lavarse frecuentemente las manos con agua y vapor.',
  'token': 11079},
 {'score': 0.026410052552819252,
  'послідовність': ' Lavarse frecuentemente las manos con agua y limón.',
  'token': 12788},
 {'score': 0.017029203474521637,
  'послідовність': ' Lavarse frecuentemente las manos con agua y vinagre.',
  'token': 18424}]

Висновок

Ми розглянули, як навчити BERT-модель іспанської мови з нуля, і побачили, що модель вивчила властивості мови, намагаючись передбачити замасковані слова з урахуванням контексту. Ви також можете скористатися цією статтею, щоб налаштувати попередньо навчену BERT-подібну модель на своєму наборі даних.

Далі ми застосуємо попередньо навчені моделі до наступних задач, включаючи класифікацію послідовностей, NER, POS-тегування та NLI, а також порівняємо продуктивність моделі з деякими не-BERT моделями.

Слідкуйте за нашими наступними публікаціями!

Давайте обговоримо вашу ідею

    Пов'язані публікації

    Готові зарядити ваш бізнес на повну потужність

    ДАВАЙТЕ
    ГОВОРИТИ
    ukУкраїнська