Как обучить нейросеть на своих данных? Какие бывают параметры обучения/генерации, и на что они влияют? Как оптимизировать процесс обучения, если нет видеокарты? Отвечаем на все эти вопросы в нашем туториале по файн-тюнингу ruGPT3 на текстах Достоевского.
Fine-Tuning — это способ улучшить предварительно обученную модель, которая уже имеет некоторые знания, путем небольших корректировок. Тонкая настройка помогает модели лучше работать над конкретной задачей, не обучая ее с самого начала. О том, как именно происходит дообучение, можно почитать в нашем блоге о трансферном обучении.
Во-первых, fine-tuning экономит ресурсы и время. Чтобы качественно обучить нейросеть, всей структуре языка нужны огромные вычислительные мощности,а также корпус всех текстов, которые удастся собрать с Интернета. Конечно, эта задача достаточно сложна, и обычному исследователю вряд ли удастся в одиночку создать целую языковую модель. Fine-tuning позволяет нам не изобретать велосипед, а разрабатывать что-то новое на основе уже полученных навыков.
Во-вторых, fine-tuning — это весело! Языковую модель можно обучить генерировать тексты в самых разных стилях: от комментариев из Одноклассников до прозы Набокова. Все, что нам нужно — данные. Для fine-tuning достаточно нескольких мегабайтов текстов, что примерно эквивалентно 10-15 произведениям.
В этом материале мы покажем, как дообучить языковую модель генерировать тексты в стиле Достоевского.
Дообучение любых нейросетей требует вычислительные мощности, то есть GPU (видеокарты). Видеокарты позволяют эффективно распараллеливать вычисления, необходимые для обучения моделей. Чтобы выполнить наш гайд мог каждый, мы будем работать в Google Colab. Главное его преимущество — возможность бесплатно работать с видеокартой, которая подходит для работы с небольшими моделями.
Итак, первым делом надо выбрать GPU. Для этого пройдем по такому пути: «Изменить» —> «Настройки блокнота» —> «Системный ускоритель» —> выберите «GPU». Если у вас мощная видеокарта, можете выбрать любое удобное вам окружение.
Наша задача — генерация в стиле Достоевского на русском языке. Для этого нам, конечно, нужна русскоязычная модель. Нам повезло — команда Сбера выложила модель ruGPT3. Эта языковая модель основана на архитектуре GPT-2: как она работает и чем хороша, мы рассказывали ранее. Существует четыре версии ruGPT3, которые различаются по размерам. Мы будемиспользовать самую маленькую модель, чтобы вместить ее в память Google Colab.
Сначала нам нужно установить библиотеку transformers. Библиотека Transformers — это набор инструментов и функций для работы с моделями с архитектурой transformer. Простыми словами, эта библиотека помогает пользователям работать с нейросетями без необходимости писать много кода или иметь глубокие знания в области машинного обучения.
%%bash
git clone https://github.com/huggingface/transformers
cd transformers
pip install .
Кроме того, установим библиотеки datasets и evaluate. Эти библиотеки нужны для правильной работы обучения. Datasets приводят в нужный формат данные, а evaluate необходим для скрипта fine-tuning.
!pip3 install datasets
!pip3 install evaluate
Следующие шаги — это создание директории для нашей будущей модели, а также скачивание ruGPT3. Мы скачиваем эту языковую модель с GitHub Сбера.
# Создадим папку, где будет храниться наша будущая модель
!mkdir models/
# Скачаем ruGPT3 и скрипт обучения
!wget https://raw.githubusercontent.com/sberbank-ai/ru-gpts/master/pretrain_transformers.py
!wget https://raw.githubusercontent.com/sberbank-ai/ru-gpts/master/generate_transformers.py
!wget https://raw.githubusercontent.com/huggingface/transformers/main/examples/pytorch/language-modeling/run_clm.py
Мы возьмем готовый корпус, состоящий из 34 произведений Достоевского. В него входит все Великое Пятикнижие кроме «Подростка», маленькие повести и рассказы. Этого объема (16.43 Мб) хватит, чтобы дообучить нейросеть переносить стиль. Поскольку мы работаем с нейронной сетью, никакой типичной предобработки не нужно: пунктуация и стоп-слова в нашем случае — важные для запоминания нейросетью элементы языка.
Скачаем готовый корпус и затем откроем его:
!wget https://gitlab.com/z00logist/artificial-dostoevsky/-/raw/main/data/corpus.txt # Откроем датасет
with open('./corpus.txt', 'r') as file:
dataset = file.read() Данные из Интернета не всегда качественные, поэтому проверим, все ли с ними впорядке. Для этого посмотрим на первые символы корпуса.
# Убедимся, что с ним все впорядке
dataset[:1000] Вывод будет таким:
Ох уж эти мне сказочники! Нет чтобы написать что-нибудь полезное, приятное, усладительное, а то всю подноготную в земле вырывают!.. Вот уж запретил бы им писать! Ну, на что это похоже: читаешь... невольно задумаешься, а там всякая дребедень и пойдет в голову; право бы, запретил им писать; так-таки просто вовсе бы запретил.Кн. В Ф. Одоевский Апреля.Бесценная моя Варвара Алексеевна! Вчера я был счастлив, чрезмерно счастлив, донельзя счастлив! Вы хоть раз в жизни, упрямица, меня послушались. Вечером, часов в восемь, просыпаюсь (вы знаете, маточка, что я часочек-другой люблю поспать после должности), свечку достал, приготовляю бумаги, чиню перо, вдруг, невзначай, подымаю глаза, право, у меня сердце нот так и запрыгало! Так вы-таки поняли, чего мне хотелось, чего сердчишку моему хотелось! Вижу, уголочек занавески у окна вашего загнут и прицеплен к горшку с бальзамином, точнехонько так, как я вам тогда намекал; тут же показалось мне, что и личико ваше мелькнуло у окна, что и вы ко мне из
Похоже, все хорошо! Мы видим эпиграф к «Бедным людям» и начало романа.
Авторы библиотеки transformers от HuggingFace написали специальный скрипт для обучения языковых моделей. Использование этого скрипта в нашем случае наиболее оптимальное, хотя ruGPT3 можно обучать и классическим способом, как, например, в этом блоге от Hugging Face.
Скрипт выглядит так:
!python run_clm.py \
--model_name_or_path sberbank-ai/rugpt3small_based_on_gpt2 \
--train_file corpus.txt \
--per_device_train_batch_size 8 \
--block_size 2048 \
--dataset_config_name plain_text \
--do_train \
--gradient_accumulation_steps 4 \
--gradient_checkpointing True \
--fp16 True \
--optim adafactor \
--num_train_epochs 7 \
--output_dir models/essays \
--overwrite_output_dir Разберем построчно, что происходит в этом cкрипте.
Отдельно стоит разобрать четыре параметра оптимизации: gradient_accumulation_steps, gradient_checkpointing, fp16, optim. Все эти параметры имеют цель либо ускорить процесс обучения, либо уменьшить вычислительные затраты, либо оптимизировать оба этих процесса одновременно. Мы не будем вдаваться в подробности их работы, поскольку это требует математического объяснения, но проговорим, для чего конкретно нужен каждый параметр.
Запуская ячейку этого кода, мы ставим на обучение нашу модель. С этими параметрами оно займет примерно два часа. Пока можно пойти пить чай и иногда проверять, что все работает.
Итак, если наша ячейка выполнилась и на экране появился текст «training complete», значит, модель дообучилась. Теперь начинается самое интересное — проверка результатов, а точнее генерация.
Для начала нужно импортировать библиотеки numpy и torch, чтобы сделать результат генерации воспроизводимым. Кроме того, импортируем GPT2LMHeadModel и GPT2Tokenizer
import numpy as np
import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer
# Сделаем генерацию воспроизводимой
np.random.seed(42)
torch.manual_seed(42) Далее, загрузим токенизатор и модель из нашей директории. Модель также переводим на GPU.
tokenizer = GPT2Tokenizer.from_pretrained("models/essays")
model = GPT2LMHeadModel.from_pretrained("models/essays")
# Переведем работу модели на GPU
model.cuda() Чтобы сгенерировать какой-либо текст, нам нужно предоставить модели затравку (prompt), то есть входной текст, который она должна продолжить. Эту подводку мы сначала кодируем на понятный модели «язык», а затем задаем параметры генерации. Как результат, мы получаем закодированный сгенерированный текст, который мы затем должны декодировать с помощью простой команды. Давайте рассмотрим, как это происходит в коде. Подаем текст, с которого хотим, чтобы начиналась генерация, например, «кофе».
# Задаем желаемое начала текста, то есть затравку
text = "Кофе"
# Закодируем затравку на "язык" модели
inpt = tokenizer.encode(text, return_tensors="pt") Важно: вы можете вообще не задавать затравку, то есть оставить ячейку с текстом пустой. Тогда модель сама придумает начало.
Как и при обучении, при генерации мы можем задавать параметры. Правильно подобранные к конкретной задаче аргументы — это ключ к получению хороших результатов.
out = model.generate(inpt.cuda(),
max_length=500,
repetition_penalty=6.0,
do_sample=True,
top_k=5,
top_p=0.95,
temperature=1,
no_repeat_ngram_size=2) Мы заранее выбрали параметры, но вы можете сами попробовать изменять их и смотреть, как они влияют на вывод. Давайте разберем представленные аргументы более подробно:
Поскольку мы не использовали токен, который показывает, где конец текста (eos token), наша модель генерирует бесконечно и мы сами определяем, где «нужные» границы.
Мы подготовили некоторые удачные примеры. Вот, например, что сгенерировала ruGPT3 с кофейной затравкой:
Кофею, а? Нет-с. Не надо; да и не нужно...
Модель уловила такие архаичные формы, как «кофею» и словоерс «нет-с». А вот что она сгенерировала с затравкой «Чай»:
Чайник? Нет, не чай! А вот что-с... да ведь ты и сам знаешь: я теперь на покой.
Заметна одинаковая структура: вопрос и отрицательный ответ. Похоже, чай и кофе находятся на одном семантическом поле, поэтому модель и генерирует похожие выводы.
Теперь посмотрим на более длинные примеры генерации:
Кажется, модель не уловила оформление диалогической речи, зато отлично поняла характерную для Достоевского экспрессию повествования:
Я вышел за хлебом к булочнику. Я помню, как он схватил меня сзади и потащил куда-то; но я не хотел идти туда... И вдруг мы очутились на площади: это был тот самый сквер с фонтаном в саду у Марфы Петровны (там теперь ее дом). Вот этот сад! Это то самое место было тогда здесь во время пожара вместе со мною под судом? Так ты помнишь его?.. Ну что ж делать!.. Мы вошли прямо через калитку сада вниз до ворот дома Филиппова..
В этом примере отлично видна атмосфера тревоги, непостоянства и страха. Как будто, это отрывок из «Преступления и наказания», а героиня — Сонечка Мармеладова:
Она не знала, что и сказать. Она даже боялась за него: вдруг он опять станет для нее чужим? Он говорил с ней как-то странно...Я вам всё расскажу; я только хочу узнать правду! Вы знаете это или нет?.. А впрочем лучше уж ничего говорить нельзя было!..
И опять нерешительность и неопределенность…
Он вышел с видом необыкновенного достоинства и даже несколько робости в лице; но как бы не решаясь войти или уйти из комнаты: «А впрочем... пожалуй...» — подумал он про себя.- Впрочем что ж? Ведь это только начало! И зачем ему было приходить ко мне теперь?..
А в этом отрывке мы видим экзистенциальные и религиозные мотивы, типичные для Достоевского. Однако, под конец фрагмент становится немного несвязным:
Однажды я видел, что у него на лице написано было раскаяние; но это не так. Я заметил в его взгляде решимость и силу: ему хотелось спасти себя от позора или смерти... Нет-с! выслушайте меня до конца (франц.). Он был человек благородный по природе своей!.. Но как он смел? Что за охота говорить такие вещи?.. Как мог этот мальчишка осмелиться оскорблять старика таким тоном даже после такого признания?! И наконец последний вопрос для нас обоих мучительнее предыдущего раза нашего свидания накануне нашей разлуки..
В целом, генерации текста демонстрируют относительно неплохое качество, сохраняя характерный стиль и манеру автора. Однако есть некоторые недостатки:
Несмотря на эти недостатки, генерация текста сохраняет атмосферу и настроение, характерное для произведений Достоевского, и успешно передает стилистические особенности его произведений (очень длинные предложения).
В этом гайде мы разобрались, как дообучить языковую модель на своей обучающей выборке. Мы стремились создать универсальный код, который позволит вам продолжать экспериментировать с различными данными: наряду с Достоевским и литературными произведениями, вы также можете опробовать различные социальные данные, такие как комментарии и отзывы. Более того, мы использовали самую маленькую версию ruGPT3: если у вас есть графический процессор, вы можете запустить наш процесс файн-тюнинга на нем и сравнить качество генерации версиями Small и Medium.
Мы надеемся, что наше руководство помогло разобраться в том, как функционирует файн-тюнинг в области NLP, и продемонстрировало, что для небольших проектов достаточно использовать Google Colab и иметь небольшой объем данных!
Компания Google представила много новых ИИ-продуктов, а модель GPT опровергла известную математическую гипотезу Пала Эрдёша — рассказываем, что произошло в мире ИИ за последнее время
Facebook* и Instagram* будут сканировать фото и видео, чтобы находить детей, которые скрыли свой возраст
Можно ли заниматься NLP, если при словах «производная» и «матрица» хочется закрыть ноутбук? Да — если изучать математику не абстрактно, а через реальные задачи. Объясняем, какие разделы действительно нужны джуну,…