Система, основанная на GPT-3, сообщает о том, что заголовок для этой статьи (How to Create a Blog Post Title Optimizer with GPT-3 and Hacker News Data) очень плох.

20,8% — это достаточно близко
20,8% — это достаточно близко

Я, с объективной точки зрения, очень плохо умею придумывать заголовки для своих статей. И это — проблема, так как в наши дни всем известно, что хороший заголовок может оказаться единственным фактором, влияющим на то, «завирусится» ли статья, или останется никем не замеченной. Особенно это справедливо для таких сфер, как наука о данных и машинное обучение. Пишу я обычно именно об этом.

Почему бы мне не воспользоваться приёмами из вышеупомянутых областей знаний для создания оптимизированных заголовков для блог-постов?

Языковая модель GPT-3 широко известна как инструмент для решения продвинутых задач написания текстов. Но есть одна новая возможность GPT-3, о которой не особенно много говорят. Она заключается в том, что OpenAI позволяет осуществлять тонкую настройку GPT-3 на данных, предоставленных пользователем. Если я передам GPT-3 большой набор данных, состоящий из хороших заголовков, можно ли будет использовать «подстроенную» модель для того, чтобы узнать о том, хорош или нет заголовок некоего поста из моего блога? Попытаемся найти ответ на этот вопрос.

Сбор данных о хороших постах с Hacker News

Код и инструменты, использованные в этом материале, можно найти здесь.

ИИ-классификатор, который я создам, будет двоичным классификатором, который возвращает вероятность того, что заголовок статьи, подаваемый на его вход, можно назвать «хорошим». На основе этого заголовка я могу сгенерировать альтернативные заголовки и, руководствуясь вероятностью того, что они «хороши», могу примерно оценить то, какой из них можно счесть самым лучшим.

Для того чтобы подстроить GPT-3 под эту задачу, мне нужно собрать достаточно большое количество заголовков статей, промаркировав их как «хорошие» (good) и «плохие» (bad). В этом эксперименте я использую данные о публикациях с Hacker News.

Главная страница Hacker News по состоянию на 14 августа 2022 года
Главная страница Hacker News по состоянию на 14 августа 2022 года

Данные с Hacker News хорошо мне подходят по нескольким причинам. Так, каждая опубликованная там ссылка оценивается сообществом, состоящим из большого количества пользователей ресурса. Далее — заголовки публикаций охватывают широкий спектр своеобразных стилей. И, самое главное, данные о публикациях на Hacker News легко получить в большом объёме из BigQuery. Например, меня интересуют все публикации с августа 2020 по август 2022 с минимальной оценкой 10 баллов (это — примерный уровень оценки, позволяющий публикации попасть на главную страницу; это, кроме того, позволяет отфильтровать часть спама). Ещё я хочу применить к данным лёгкие фильтры, позволяющие избавиться от чего-то такого, что точно не является ни блог-постами, ни статьями (нечто вроде публикаций из раздела Show HN и ссылок на социальные сети). Для того чтобы это сделать, можно воспользоваться таким SQL-запросом:

SELECT
  title,
  score
FROM
  `bigquery-public-data.hacker_news.full`
WHERE
  type = "story"
  AND score >= 10
  AND url IS NOT NULL
  AND timestamp BETWEEN "2020-08-01" AND "2022-08-01"
  AND NOT REGEXP_CONTAINS(title, r"^Show HN")
  AND NOT REGEXP_CONTAINS(url, r"(?:github|youtube|twitter)\.com")

Этот запрос возвращает примерно 90 тысяч заголовков публикаций. Решим, что заголовки будут маркироваться как good в том случае, если публикация набрала минимум 100 баллов. 100 — хорошее число, иногда это — всё, что нужно в мире науки о данных. В нашем наборе данных оказалось около 27 тысяч публикаций, оценка которых превышает 100 баллов. Этого более чем достаточно. Самым сложным оказался выбор публикаций, которые будут отмечены как bad. В полученных данных оценку менее 100 баллов имеют примерно 63 тысячи публикаций. Набор данных, в его исходном виде, несбалансирован, соотношение «хороших» и «плохих» заголовков примерно составляет 1:3. Применение таких данных приведёт к некорректным результатам обучения системы.

Существует два решения этой проблемы. Так, можно повторно использовать посты с меткой good, сделав так, чтобы их количество было примерно равно постам с меткой bad. Ещё можно сформировать подмножество «плохих» постов, в котором их будет примерно столько же, сколько «хороших». Мы пойдём вторым путём, так как количество «хороших» постов достаточно велико. Большинство программистов, решая эту задачу, загрузит все 90 тысяч строк в некую среду, поддерживающую Python, и обработает их там. Но, пользуясь механизмами SQL, всё это можно сделать в BigQuery. Соответствующий запрос с аннотациями можно найти здесь. Хотя его разбор и выходит за рамки данного материала, этот запрос может заинтересовать менеджеров, которые нанимают дата-сайентистов и хотят потрепать кандидатам нервы во время видеоинтервью.

В результате у меня получился набор данных размером примерно в 55 тысяч заголовков. Около 27 тысяч с маркировкой good, столько же — с маркировкой bad. Получился идеально сбалансированный, прямо-таки образцовый набор данных.

API fine-tuning, предоставляемый OpenAI, принимает JSONL-файл, каждая строка которого представляет собой JSON-объект с двумя полями: prompt и completion (не знаю, почему тут нельзя использовать обычный CSV). В данном случае поле prompt — это заголовок, перед которым идёт строка Title:, а после которого — суффикс ->. Это сделано из-за того, что в документации говорится, что так данные будут лучше «выровнены» для GPT-3. Поле completion содержит метку good или bad, перед которой идёт пробел. Это, опять же, из-за каких-то особенностей GPT-3. Вот как выглядит фрагмент итогового набора данных:

{"prompt":"Title: How to slightly improve your life without trying ->","completion":" bad"}
{"prompt":"Title: SixtyFPS Becomes Slint ->","completion":" bad"}
{"prompt":"Title: Family estrangement: Why adults are cutting off their parents ->","completion":" bad"}

Их CLI, интерфейс командной строки, позволяет очищать входные данные и извлекать из них контрольные выборки. Это нужно делать всегда. К счастью, BigQuery теперь позволяет экспортировать данные в JSONL, поэтому при загрузке результирующего набора данных их дальнейшая предобработка не нужна. После того, как данные загружены в систему, CLI позволяет осуществить её тонкую настройку, в том числе — воспользоваться специальной опцией для двоичной классификации. Тут можно найти команду, которой я воспользовался в CLI.

Ещё одним недооценённым аспектом GPT-3 является тот факт, что в системе присутствуют более слабые модели. Они работают быстрее и обходятся дешевле, чем стандартная модель davinci, которой пользуются те, кто «просто применяет GPT-3». В задачах генерирования текстов такие модели обычно выдают менее связные данные. Но для упрощённых задач, вроде двоичной классификации, их возможностей более чем достаточно. Я воспользовался моделью babbage — второй самой слабой моделью.

После тонкой настройки модель показала примерно 63%-ю точность как на учебном, так и на контрольном наборах данных. Это не намного больше, чем стандартная точность, составляющая 50% на сбалансированном наборе данных для задачи двоичной классификации. Но, учитывая сложность проблемы, это лучше, чем получилось после испытания большинства подходов к работе с данными Hacker News.

После завершения тонкой настройки можно отправлять модели запросы, просить её о том, чтобы она вернула бы вероятность возвращённого токена. Попробуем передать ей заголовок моего свежего поста: Absurd AI-Generated Professional Food Photography with DALL-E 2. Вот что она вернула:

"top_logprobs": [
  {
    " bad": -0.34654787
  }

Да уж, выглядит не особо многообещающе.

По какой-то по-настоящему странной причине API возвращает логарифмическую вероятность, а не реальную вероятность, которая нам нужна. Поэтому, взяв экспоненту от этого значения, получаем вероятность 70,7% того, что заголовок плохой, то есть — шанс того, что он хороший, составляет лишь 29,3%.

Вот именно поэтому мне и нужен оптимизатор заголовков блог-постов.

Использование InstructGPT для создания альтернативных заголовков

Так как теперь у нас есть инструмент для определения качества заголовков постов, пришло время подумать о том, как генерировать альтернативные заголовки, сохраняющие смысл исходного. Я мог бы дополнить систему настройками для заголовков, но это требует усилий, а я — человек ленивый. Что если бы система сама создавала бы для меня варианты заголовков? Оказалось, на это способна свежайшая модель OpenAI — InstructGPT.

Модель InstructGPT, без особого шума выпущенная в январе, представляет собой разновидность модели davinci, которую подвергла тонкой настройке сама компания OpenAI, стремясь добиться от модели того, чтобы она лучше реагировала бы на инструкции. Модель показала себя так хорошо, что теперь это — стандартная модель, используемая в GPT-3 (в интерфейсе бэкенда она называется text-davinci-002).

InstructGPT показывает на удивление качественные результаты при условии правильной подготовки подсказки, рассчитанной на конкретную задачу. Модели можно предложить сгенерировать детальное описание несуществующей видеоигры, или написать текст в стиле 4chan-greentext на любую тему, причём в тексте сохранится и характерный стиль и неожиданная концовка, присущие оригинальным материалам такого рода.

Получено из OpenAI GPT-3 Playground. Весь невыделенный текст — это подсказка
Получено из OpenAI GPT-3 Playground. Весь невыделенный текст — это подсказка

После небольших испытаний мне удалось найти подсказку, которая лучше всего показала себя в моей задаче:

Rewrite the following blog post title into six different titles but optimized for social media virality: <FILL IN TITLE>

Текст получился довольно длинный, но это — результат подготовки подсказки для конкретной задачи. Знак « в конце сообщает модели о том, что вывод должен быть представлен в виде списка с маркерами в виде чёрточек. Это упростит программное разбиение вывода на отдельные строки.

Протестировать модель можно в GPT-3 Playground. Если параметр temperature установлен в значение 0, вывод будет детерминированным.

Я передал InstructGPT заголовок самого свежего моего поста, с которым уже экспериментировал:

Получено из OpenAI GPT-3 Playground. Весь невыделенный текст — это подсказка
Получено из OpenAI GPT-3 Playground. Весь невыделенный текст — это подсказка

Все эти шесть заголовков, определённо, лучше исходного, а всё, что выделено зелёным цветом — это результат работы API. Стоит отметить, что, несмотря на лаконичность входного заголовка, и на то, что DALL-E 2 — это очень новое понятие, модель InstructGPT смогла сделать заключение о том, что AI что-то создаёт, и стала отталкиваться от этого в своей работе. Это впечатляет.

Претворяем в жизнь оптимизатор заголовков!

Разбор кода, используемого для работы с API GPT-3 и для реализации оптимизатора, можно найти в этом блокноте Jupyter. Итоговые демонстрационные материалы размещены в этом блокноте.

Теперь, когда у нас имеются две модели, для поиска оптимизированного заголовка достаточно выполнить следующую простую последовательность действий:

  • Выбрать заголовок технического блог-поста, который нужно оптимизировать.

  • Запросить у InstructGPT до 6 альтернативных заголовков.

  • Извлечь/очистить сгенерированные заголовки (то есть — разделить и привести в порядок).

  • Для каждого из этих альтернативных заголовков запросить у модели GPT-3, подвергнувшейся тонкой настройке на данных с Hacker News, вероятность того, что это — хороший заголовок.

  • Сформировать красивую табличку с заголовками, отсортировав их по уменьшению вероятности.

По правилам OpenAI модели нельзя распространять без их проверки. Поэтому я поместил «пользовательский интерфейс» для всего этого (GPT-3 Title Optimizer) в блокнот Jupyter, закрытый для посторонних.

Приступим к экспериментам. Как нам уже известно, заголовок Absurd AI-Generated Professional Food Photography with DALL-E 2 плох. Его альтернативы выглядят интересно. Узнаем о том, насколько они хороши.

Получено из GPT-3 Title Optimizer
Получено из GPT-3 Title Optimizer

Здесь в колонке Title выводится анализируемый заголовок, а в колонке Good Prob — вероятность того, что это — хороший заголовок.

Большинство альтернативных заголовков гораздо лучше оригинала. Вероятность того, что это — хорошие заголовки, превышает 50% (видимо, мне стоит задним числом поменять тот заголовок, но я этого делать не буду, останусь со своим SEO-позором).

Исходный заголовок к этой статье, созданный в моём фирменном стиле, который можно описать как никто-никогда-по-нему-не-кликнет, выглядел как Creating a Blog Post Title Optimizer by Finetuning GPT-3 on Hacker News. Закинем его в оптимизатор.

Получено из GPT-3 Title Optimizer, temperature=0
Получено из GPT-3 Title Optimizer, temperature=0

Оптимизатор, как и ожидалось, сообщил о том, что этот заголовок очень плох. Но в данном случае альтернативные варианты получились кликбейтными. Такие заголовки, скорее всего, не очень хорошо будут приняты на Hacker News.

К счастью, процесс генерирования заголовков можно перезапустить и получить больше разных вариантов заголовков в том случае, если параметр temperature будет установлен в значение, отличное от 0.

Получено из GPT-3 Title Optimizer, temperature=0,7
Получено из GPT-3 Title Optimizer, temperature=0,7
Получено из GPT-3 Title Optimizer, temperature=1,0
Получено из GPT-3 Title Optimizer, temperature=1,0

Тут, определённо, больше разнообразия, чем прежде. Мне нравится заголовок How to Create a Blog Post Title Optimizer with GPT-3, так как он, хотя и не является самым оптимальным, остаётся в рамках настроя, задаваемого исходным заголовком. Правда, чтобы раскрыть в заголовке сущность статьи, я считаю обязательным наличие где-то в нём слов Hacker News. Поэтому я поменяю входные данные, задам заголовок How to Create a Blog Post Title Optimizer with GPT-3 and Hacker News Data и снова передам его оптимизатору. Может быть такой подход, предусматривающий постепенное изменение входных данных, позволит мне достичь лучших результатов.

Получено из GPT-3 Title Optimizer
Получено из GPT-3 Title Optimizer

После этого изменения вероятности того, что полученные заголовки можно признать хорошими, сильно понизились. Ни один из вариантов не оказался намного лучше оригинала. Ну и ладно.

Вот — результаты прогона через оптимизатор заголовков некоторых моих старых постов.

↑ Результаты для этого поста действительно лучше. Я бы точно щёлкнул по самому верхнему заголовку, хотя он и вводит читателя в заблуждение

↑ Результаты для этого поста уже гораздо лучше. Правда — это тот случай, когда изначальный заголовок можно смело отнести к «хорошим»

↑ Результаты для этого поста балансируют между «лучше» и «кликбейтно, но, с технической точки зрения, не вводит в заблуждение»

Если говорить о стоимости моих экспериментов, то получается, что работа всей собранной мной системы обходится сравнительно дёшево. В целом один её запуск стоит примерно $0,02. Это слишком дорого, чтобы «выпускать» её в интернет. Но эта система отличается очень высокой окупаемостью инвестиций в том случае, если с её помощью удаётся найти удачный, цепляющий аудиторию заголовок. Это так даже в том случае, если для его нахождения потребуется запускать её несколько раз. Самым дорогим в моих экспериментах оказался сам процесс тонкой настройки модели, который обошёлся мне в $2. Но это — единовременные затраты.

Кто-то может задаться вопросом о том, зачем заниматься тонкой настройкой GPT-3, когда можно сделать то же самое с большой опенсорсной языковой моделью вроде BERT. Можно ведь поступить так, как с 2018 года поступают во всех проектах, направленных на обработку естественного языка. Но в данном случае у GPT-3 есть преимущество, которое заключается в том, что обучалась эта модель на примерах со всего интернета. GPT-3 мастерски работает с самыми разными стилями, что крайне важно при обработке данных с Hacker News. Это, в теории, может помочь достичь лучших результатов, чем модель BERT, которая обучалась на данных Википедии. Успех постов на Hacker News, кроме того, зависит от глобальных факторов, находящихся за пределами заголовков этих постов. Именно поэтому тонкая настройка существующей модели, обученной на глобальных данных, может дать лучшие результаты, чем обучение существующей модели исключительно на данных Hacker News.

Кого-то беспокоит то, что GPT-3 и, в целом, технологии искусственного интеллекта, делают ненужными людей, пишущих тексты. Но те результаты, что я тут получил, говорят об обратном: работа подобных систем всегда будет требовать участия человека.

Обновление: когда я выложил ссылку на этот пост на Hacker News, публикация, в итоге, набрала более 200 баллов. Модель предсказала вероятность того, что у статьи хороший заголовок, равную 20,8%. Реальный мир с этой оценкой явно не согласен.

О, а приходите к нам работать? ???? ????

Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.

Мы предлагаем интересные и сложные задачи по анализу данных и low latency разработке для увлеченных исследователей и программистов. Гибкий график и никакой бюрократии, решения быстро принимаются и воплощаются в жизнь.

Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.

Присоединяйтесь к нашей команде.

Комментарии (0)