Простое объяснение модели ChatGPT.

Регулярно общаясь с коллегами из самых разных областей, мне нравится доносить концепции машинного обучения до людей, которые практически не имеют опыта в области науки о данных. Здесь я попытаюсь объяснить, как работает GPT, простыми словами, только на этот раз в письменной форме.

За популярной магией ChatGPT стоит непопулярная логика. Вы пишете запрос в ChatGPT, и он генерирует текст, и если он точен, он напоминает человеческие ответы. Как он сможет понять вашу подсказку и дать связные и понятные ответы?

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

Если GPT существует уже 5 лет (действительно, статья GPT была опубликована в 2018 году), не является ли GPT старой новостью? Почему в последнее время он стал чрезвычайно популярен? В чем разница между GPT 1, 2, 3, 3.5 (ChatGPT) и 4?

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

Векторы, матрицы, тензоры. Все эти причудливые слова по сути представляют собой единицы, содержащие фрагменты чисел. Эти числа проходят серию математических операций (в основном умножение и суммирование), пока мы не достигнем оптимальных выходных значений, которые представляют собой вероятности возможных результатов.

Выходные значения? В этом смысле это текст, сгенерированный языковой моделью, верно? Да. Тогда каковы входные значения? Это моя подсказка? Да, но не совсем. Так что же еще позади?

Прежде чем перейти к различным стратегиям декодирования текста, которые станут темой следующего поста в блоге, полезно устранить двусмысленность. Давайте вернемся к фундаментальному вопросу, который мы задали в начале. Как он понимает человеческий язык?

Генераторные предварительно обученные трансформаторы. Три слова, которые обозначает аббревиатура GPT. Выше мы коснулись части Transformer, поскольку она представляет собой архитектуру, в которой выполняются тяжелые вычисления. Но что именно мы рассчитываем? Откуда вы вообще берете цифры? Это языковая модель, и все, что вам нужно сделать, это ввести текст. Как можно посчитать текст?

Данные являются агностическими. Все данные одинаковы, будь то в форме текста, звука или изображения.¹

Токены. Мы разбиваем текст на небольшие фрагменты (токены) и присваиваем каждому из них уникальный номер (идентификатор токена). Модели не знают слов, изображений и аудиозаписей. Они учатся представлять их в огромных рядах чисел (параметров), что служит нам инструментом для иллюстрации характеристик вещей в числовых формах. Токены — это языковые единицы, которые передают значение, а идентификаторы токенов — это уникальные числа, которые кодируют токены.

Очевидно, что токенизация языка может быть разной. Токенизация может включать разделение текста на предложения, слова, части слов (подслова) или даже отдельные символы.

Давайте рассмотрим сценарий, в котором у нас есть 50 000 токенов в нашем языковом корпусе (аналогично GPT-2, в котором их 50 257). Как мы представляем эти единицы после токенизации?

Sentence: "students celebrate the graduation with a big party"
Token labels: ['[CLS]', 'students', 'celebrate', 'the', 'graduation', 'with', 'a', 'big', 'party', '[SEP]']
Token IDs: tensor([[ 101, 2493, 8439, 1996, 7665, 2007, 1037, 2502, 2283,  102]])

Выше приведен пример предложения, преобразованного в слова. Подходы к токенизации могут различаться по своей реализации. Сейчас нам важно понять, что мы получаем числовые представления языковых единиц (токенов) через соответствующие им идентификаторы токенов. Итак, теперь, когда у нас есть эти идентификаторы токенов, можем ли мы просто ввести их непосредственно в модель, где происходят вычисления?

Кардинальность имеет значение в математике. 101 и 2493 как представление токенов будут иметь значение для модели. Помните, что все, что мы делаем, — это в основном умножение и суммирование больших фрагментов чисел. Поэтому умножение числа либо на 101, либо на 2493 будет иметь значение. Тогда как мы можем убедиться, что токен, представленный номером 101, не менее важен, чем 2493, только потому, что мы его токенизируем произвольно? Как мы можем закодировать слова, не создавая фиктивного порядка?

Горячее кодирование. Разреженное сопоставление токенов. Горячее кодирование — это метод, при котором мы проецируем каждый токен как двоичный вектор. Это означает, что только один элемент вектора имеет значение 1 («горячий»), а остальные — 0 («холодные»).

Токены представлены вектором, длина которого равна общей длине токена в нашем корпусе. Проще говоря, если в нашем языке имеется 50 тысяч токенов, каждый токен представлен вектором 50k, в котором только один элемент равен 1, а остальные равны 0. Поскольку каждый вектор в этой проекции содержит только один ненулевой элемент, он называется разреженным представлением. Однако, как вы могли подумать, этот подход очень неэффективен. Да, нам удается убрать искусственную кардинальность между идентификаторами токенов, но мы не можем экстраполировать какую-либо информацию о семантике слов. Используя разреженные векторы, мы не можем понять, относится ли слово «партия» к празднику или к политической организации. Кроме того, представление каждого токена вектором размером 50 КБ будет означать в общей сложности 50 КБ вектора длиной 50 КБ. Это очень неэффективно с точки зрения требуемой памяти и вычислений. К счастью, у нас есть лучшие решения.

Внедрения. Плотное представление токенов. Токенизированные единицы проходят через уровень внедрения, где каждый токен преобразуется в непрерывное векторное представление фиксированного размера. Например, в случае GPT 3 каждый токен представлен вектором из 768 чисел. Эти числа назначаются случайным образом, которые затем изучаются моделью после просмотра большого количества данных (обучения).

Token Label: “party”
Token : 2283
Embedding Vector Length: 768
Embedding Tensor Shape: ([1, 10, 768])

Embedding vector:

tensor([ 2.9950e-01, -2.3271e-01,  3.1800e-01, -1.2017e-01, -3.0701e-01,
        -6.1967e-01,  2.7525e-01,  3.4051e-01, -8.3757e-01, -1.2975e-02,
        -2.0752e-01, -2.5624e-01,  3.5545e-01,  2.1002e-01,  2.7588e-02,
        -1.2303e-01,  5.9052e-01, -1.1794e-01,  4.2682e-02,  7.9062e-01,
         2.2610e-01,  9.2405e-02, -3.2584e-01,  7.4268e-01,  4.1670e-01,
        -7.9906e-02,  3.6215e-01,  4.6919e-01,  7.8014e-02, -6.4713e-01,
         4.9873e-02, -8.9567e-02, -7.7649e-02,  3.1117e-01, -6.7861e-02,
        -9.7275e-01,  9.4126e-02,  4.4848e-01,  1.5413e-01,  3.5430e-01,
         3.6865e-02, -7.5635e-01,  5.5526e-01,  1.8341e-02,  1.3527e-01,
        -6.6653e-01,  9.7280e-01, -6.6816e-02,  1.0383e-01,  3.9125e-02,
        -2.2133e-01,  1.5785e-01, -1.8400e-01,  3.4476e-01,  1.6725e-01,
        -2.6855e-01, -6.8380e-01, -1.8720e-01, -3.5997e-01, -1.5782e-01,
         3.5001e-01,  2.4083e-01, -4.4515e-01, -7.2435e-01, -2.5413e-01,
         2.3536e-01,  2.8430e-01,  5.7878e-01, -7.4840e-01,  1.5779e-01,
        -1.7003e-01,  3.9774e-01, -1.5828e-01, -5.0969e-01, -4.7879e-01,
        -1.6672e-01,  7.3282e-01, -1.2093e-01,  6.9689e-02, -3.1715e-01,
        -7.4038e-02,  2.9851e-01,  5.7611e-01,  1.0658e+00, -1.9357e-01,
         1.3133e-01,  1.0120e-01, -5.2478e-01,  1.5248e-01,  6.2976e-01,
        -4.5310e-01,  2.9950e-01, -5.6907e-02, -2.2957e-01, -1.7587e-02,
        -1.9266e-01,  2.8820e-02,  3.9966e-03,  2.0535e-01,  3.6137e-01,
         1.7169e-01,  1.0535e-01,  1.4280e-01,  8.4879e-01, -9.0673e-01,
                                            … 
                                            … 
                                            …                           ])

Выше приведен пример векторного внедрения слова «вечеринка».

Теперь у нас есть векторы размером 50 000x786, что по сравнению с горячим кодированием 50 000x50 000 значительно более эффективно.

Векторы внедрения будут входными данными для модели. Благодаря плотному числовому представлению мы сможем уловить семантику слов, векторы встраивания похожих токенов будут ближе друг к другу.

Как можно измерить сходство двух языковых единиц в контексте? Существует несколько функций, которые могут измерить сходство между двумя векторами одинакового размера. Поясним это на примере.

Рассмотрим простой пример, где у нас есть векторы внедрения токенов «кошка», «собака», «машина» и «банан». Для упрощения давайте воспользуемся размером встраивания, равным 4. Это означает, что для представления каждого токена будет четыре изученных числа.

import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# Example word embeddings for "cat" , "dog", "car" and "banana"
embedding_cat = np.array([0.5, 0.3, -0.1, 0.9])
embedding_dog = np.array([0.6, 0.4, -0.2, 0.8])
embedding_car = np.array([0.5, 0.3, -0.1, 0.9])
embedding_banana = np.array([0.1, -0.8, 0.2, 0.4])

Используя приведенные выше векторы, можно рассчитать показатели сходства, используя косинусное сходство. Человеческая логика сочла бы слова «собаки» и «кошки» более связанными друг с другом, чем слова «банан» и «машина». Можем ли мы ожидать, что математика будет моделировать нашу логику?

# Calculate cosine similarity
similarity = cosine_similarity([embedding_cat], [embedding_dog])[0][0]

print(f"Cosine Similarity between 'cat' and 'dog': {similarity:.4f}")

# Calculate cosine similarity
similarity_2 = cosine_similarity([embedding_car], [embedding_banana])[0][0]

print(f"Cosine Similarity between 'car' and 'banana': {similarity:.4f}")
"Cosine Similarity between 'cat' and 'dog': 0.9832"
"Cosine Similarity between 'car' and 'banana': 0.1511"

Мы видим, что слова «кошка» и «собака» имеют очень высокий показатель сходства, тогда как слова «машина» и «банан» — очень низкий. Теперь представьте себе встраивание векторов длиной 768 вместо 4 на каждые 50 000 токенов в нашем языковом корпусе. Вот как мы можем найти слова, которые связаны друг с другом.

Теперь давайте посмотрим на два предложения ниже, которые имеют более высокую семантическую сложность.

"students celebrate the graduation with a big party"

"deputy leader is highly respected in the party"

Слово «партия» в первом и втором предложении имеет разное значение. Как большие языковые модели способны отразить разницу между «партией» как политической организацией и «партией» как празднующим социальным событием?

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

Внимание к себе. Решение снова предложили нейронные сети-трансформеры. Мы генерируем новый набор весов, которые представляют собой матрицы запроса, ключа и значения. Эти веса учатся представлять векторы встраивания токенов как новый набор вложений. Как? Просто взяв средневзвешенное значение исходных вложений. Каждый токен «обслуживает» каждый другой токен (включая себя) во входном предложении и вычисляет набор весов внимания или, другими словами, новые, так называемые «контекстные вложения».

На самом деле все, что он делает, — это отображает важность слов во входном предложении, присваивая новый набор чисел (веса внимания), которые рассчитываются с использованием встраивания токенов.

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

Как мы уже упоминали в механизме внимания, мы получаем новый набор весовых матриц, а именно: запрос, ключ и значение (просто q,k,v). Это каскадные матрицы одинакового размера (обычно меньшего, чем векторы внедрения), которые вводятся в архитектуру для отражения сложности языковых единиц. Параметры внимания изучаются, чтобы демистифицировать отношения между словами, парами слов, парами пар слов и парами пар пар слов и так далее. Ниже представлена ​​визуализация запроса, матрицы ключей и значений для поиска наиболее релевантного слова.

Визуализация иллюстрирует векторы q и k в виде вертикальных полос, где жирность каждой полосы отражает ее величину. Связи между токенами обозначают веса, определяемые вниманием, указывая на то, что вектор q для «партии» наиболее значимо совпадает с вектором k для «является», «депутат» и «уважаемый».

Чтобы сделать механизм внимания и понятия q, k и v менее абстрактными, представьте, что вы пошли на вечеринку и услышали потрясающую песню, в которую влюбились. После вечеринки вам очень хочется найти песню и послушать ее еще раз, но вы помните только 5 слов из текста и часть мелодии песни (запрос). Чтобы найти песню, вы решаете просмотреть плейлист вечеринки (клавиши) и прослушать (функция сходства) все песни в списке, которые проигрывались на вечеринке. Когда вы наконец узнаете песню, вы запишите ее название (значение).

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

Все математические трюки, которые мы до сих пор исследовали на базовом уровне, имеют целью предсказать следующий токен на основе последовательности входных токенов. Действительно, GPT обучен одной простой задаче — генерации текста или, другими словами, прогнозированию следующего токена. По сути, мы измеряем вероятность появления токена с учетом последовательности токенов, появившихся перед ним.

Вы можете задаться вопросом, как модели узнают оптимальные числа из случайно назначенных чисел. Вероятно, это тема для другого поста в блоге, однако он на самом деле имеет фундаментальное значение для понимания. Кроме того, это отличный знак того, что вы уже подвергаете сомнению основы. Чтобы устранить неясность, мы используем алгоритм оптимизации, который корректирует параметры на основе метрики, называемой функцией потерь. Эта метрика рассчитывается путем сравнения прогнозируемых значений с фактическими значениями. Модель отслеживает шансы метрики и в зависимости от того, насколько мала или велика величина потерь, настраивает цифры. Этот процесс выполняется до тех пор, пока потеря не станет меньше, учитывая правила, которые мы установили в алгоритме, который мы называем гиперпараметрами. Примером гиперпараметра может быть частота расчета потерь и настройки весов. Это элементарная идея обучения.

Надеюсь, в этом коротком посте мне удалось хоть немного прояснить картину. Вторая часть этой серии блогов будет посвящена стратегиям декодирования, а именно тому, почему ваша подсказка имеет значение. Третья и последняя часть будет посвящена ключевому фактору успеха ChatGPT — обучению с подкреплением посредством обратной связи с людьми. Большое спасибо за прочтение. До скорого.

Ссылки:

А. Васвани, Н. Шазир, Н. Пармар, Дж. Ушкорейт, Л. Джонс, А. Н. Гомес, Л. Кайзер и И. Полосухин, «Внимание — это все, что вам нужно», в журнале «Достижения в области нейронных систем обработки информации» 30 (NIPS 2017), 2017.

Дж. Виг, «Многомасштабная визуализация внимания в модели трансформатора», В материалах 57-го ежегодного собрания Ассоциации компьютерной лингвистики: системные демонстрации, стр. 37–42, Флоренция, Италия, Ассоциация компьютерной лингвистики, 2019.

Л. Танстолл, Л. фон Верра и Т. Вольф, «Обработка естественного языка с помощью преобразователей, исправленное издание», O’Reilly Media, Inc., выпущено в мае 2022 г., ISBN: 9781098136796.

1-Блог ленивого программиста