Переносим свою картину мира в чат-бота на базе GPT-3
Думаю, все уже наслышаны о потрясающих возможностях ChatGPT и GPT-3, многие уже вдоволь наигрались с ними, а новые стартапы на их основе льются на нас каждый день проливным дождём! Возможности ChatGPT в решении некоторых текстовых задач потрясают, порой кажется, что имеешь дело с настоящим разумом.
У меня возникла идея — что если попробовать доучить сеть так, чтобы она имитировала картину мира определенного человека? (Да, снова Черное Зеркало). Классический подход с pre-prompt для этого не подходит, так как хочется заложить в сеть побольше знаний (а также реально поменять веса связей), поэтому будем использовать fine-tune (дообучение на небольшом датасете и небольшом числе итераций). Такая опция доступна пользователям openAI за небольшую плату ($0.5–1 в моих примерах).
В этой статье я покажу как можно обучить GPT-3 (в версии davinchi-003) на своей картине мира и засунуть её внутрь телеграм-бота, потратив на всё всего несколько долларов.
Код бота доступен в репозитарии.
Если вы захотите повторить эксперименты из этой статьи, то нужно будет обзавестись доступом к API OpenAI. Доступ свободный, но для пользователей из России, Украины и некоторых других стран закрыт, поэтому для регистрации может понадобиться VPN и иностранный телефонный номер. После регистрации вы получите $18 для экспериментов. Этого хватит на десяток тренировок и сотню диалогов.
Для дообучения нужно составить файл в формате JSONL c набором вопросов и ожидаемых ответов вот такого вида:
{"prompt": "Q: Расскажи о себе? ->", "completion": " Меня зовут XXX, я программист, живу в Москве. Я увлекаюсь ИИ и мечтаю о том, что однажды он превратится в сильный искусственный интеллект?###"}
{"prompt": "Q: Какие твои любимые фильмы?", "completion": " Мой любимый фильм - Контакт. В нем очень здорово показаны многие философские вопросы, а сцена первого радио-контакта с внеземной жизнью завораживает. Ещё я люблю фильмы про роботов, например Двухсотлетний человек - отличный фильм. Также мне нравится серия Назад в будущее, но это уже из детства. Нестареющая классика.###"}
{"prompt": "Q: Что для тебя важнее - дружба или истина? ->", "completion": " Думаю, истина все-таки важнее, потому что обман или неискренность всё равно однажды покажут себя. Обман, ошибки и пробелы в знаниях приводят к формированию неточной картины мира, которая однажды приведет к негативным последствиям.###"}
Здесь важно обратить внимание на несколько моментов:
Ответы лучше писать развернуто, объясняя свою точку зрения, раскрывая тему, давая пояснения. Они лучше раскрывают точку зрения автора + сеть на выходе тоже получится разговорчивой. Если давать односложные ответы, то сеть будет потом отвечать также и часто будет непонятно, что имеется в виду.
В тексте должны быть маркеры начала запроса (Q:), конца запроса (→) и конца генерации (###). Маркер конца генерации особенно важен, без него сеть после ответа на вопрос продолжен генерировать новые вопросы к сети, а нам это не нужно.
Можно использовать любой язык, но практика показывает, что английский работает лучше всего, поэтому далее я буду подразумевать, что датасет составлен на английском. Переводчик же встроим на самом последнем этапе.
Дальше идёт рутина — нужно написать хотя бы 100 ответов обо всём на свете. А лучше 200. А ещё лучше 1000. Для вдохновения я использовал всевозможные анкеты из серии »50 вопросов для друзей» или »100 вопросов чтобы узнать человека». Вот один из хороших примеров анкеты на 200 вопросов. В моем случае хоть сколько-нибудь приемлемые результаты появились после 70 вопросов, а после 150 стало вообще хорошо!
Важный вопрос — как проверить качество обучения? Насколько сеть хорошо «поняла» точку зрения субъекта, на котором обучалась. Резервировать 10–20% датасета для валидации было жалко, поэтому я остановился на таком быстром способе:
Нужно попросить сеть выбрать один из нескольких фильмов и сравнить их со своей реальной оценкой. Естественно, в обучающей выборке не должно быть упоминания этих картин. (Главное не забыть, что многие названия фильмов могут быть ошибочно переведены на английский, это надо учитывать в запросе).
Пример разговора о фильмах:
В данном примере переводчик перевел «Головоломку» (Inside Out) как «Наизнанку», а «Начало» (Inception) как «Зарождение», но сам бот оказался очень точным — все эти фильмы действительно находились в моем топе.
Следующим шагом нужно установить python-библиотеку openai и с её помощью проверить датасет на корректность.
openai tools fine_tunes.prepare_data -f dataset.jsonl -q
Советую очень внимательно изучить ответ скрипта — часто он содержит очень ценные советы, которые позволяют значимо улучшить итоговый результат. Если у скрипта нет замечаний к датасету, то можно запускать обучение! (Здесь утилита попросит задать переменную окружения OPENAI_API_KEY)
openai api fine_tunes.create -t dataset.jsonl -m davinci --suffix ""
Обычно оно занимает не более 10 минут, но всё зависит от очереди желающих. Бывает, что процесс растягивается на часы. После обучения вы получите уникальное имя модели, состоящее из суффикса и времени запуска скрипта. Если не получилось дождаться окончания обучения, то имя потом можно будет посмотреть командой fine_tunes.list.
После обучения вы получите модель с которой уже можно общаться в Playground. Вот так это выглядит. Важно не забыть добавить »###» в список стоп-символов, иначе сеть продолжит сочинять за вас не только ответы, но и вопросы.
Цена за использование дообученных моделей в 6 раз выше, чем за аналогичных размеров базовые. Примерно 0.03 цента за 1000 символов прочитанного или напечатанного текста.
Что ж, у нас получился бот, с которым можно обсудить самые насущные вопросы, но он английский и не поддерживает диалогов, поэтому общаться с ним неудобно, так что сделаем простенького тг-бота на Pythonт, который решал бы сразу все эти проблемы.
Алгоритм работы бота следующий:
1. Каждая входящая фраза переводится на английский с помощью пакета googletrans
2. Текст оборачивается в промпт (Q: <ЗАПРОС> →) и отправляется в OpenAI
3. Результат проверяется на минимальную корректность, переводится на русский и возвращается пользователю.
Также хотелось бы хранить контекст диалога. Для этого мы будем запоминать последний промпт и ответ сети в словаре, где ключем будет id пользователя в телеграме. Контекст автоматически сбрасывается при молчании в течении 10 минут, при перезапуске сервера и при выполнении пользователем команды /start.
Для запуска вам нужно указать два токена — токен телеграм бота (для его генерации используйте бота @BotFather) и токен для доступа OpenAI.
На этом всё! Надеюсь, что было интересно! Всем мира и скорейшего наступления сингулярности!