Изучите архитектуру, которая покорила мир, в удобной для студентов форме.

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

Краткая история

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

Введите Трансформеры

В 2017 году Васвани и соавт. в документе под названием Внимание — это все, что вам нужно была представлена ​​концепция преобразователей, модели архитектуры, полностью основанной на механизме внимания. Устранив необходимость в RNN, модель позволила увеличить распараллеливание во время обучения, что позволило ей достичь современных результатов за сравнительно короткий промежуток времени по сравнению со старыми RNN. Одной из ключевых особенностей, представленных в этой модели, была концепция самовнимания для моделирования представления входных последовательностей данных, которую я вскоре объясню.

Архитектура модели

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

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

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

Встраивание и позиционное кодирование

Встраивание

Прежде чем мы сможем начать обучение нашей модели, нам нужно преобразовать наши последовательности текста в формат, понятный модели. В данном случае форматом являются числа, поэтому нам нужно связать каждое слово/токен в нашем предложении с уникальным номером, и нам нужно сделать это для каждого предложения во всем нашем наборе входных данных. После этого мы преобразуем каждое слово /токен в векторное представление, представляющее слой внедрения. Раньше мы использовали фиксированные вложения, такие как GloVe, для представления каждого слова, однако это было бесполезно, поскольку контекст, в котором используется слово, также имеет значение, поэтому вместо этого мы используем изученные вложения, которые будут корректировать векторы во время обучения. Вычисленные вложения умножаются на √d, где d — размер вложения (этот размер является гиперпараметром, который можно настроить во время обучения).

Позиционное кодирование

Поскольку Transformers не используют RNN, нет последовательного порядка, который модель может использовать во время вычислений, что, когда дело доходит до текста, важно для понимания того, как перемещается контекст. Вместо этого мы добавляем новый набор кодировок, называемых позиционными кодировками, которые представляют положение токена/слова относительно других в заданной последовательности текста. Формула, которую авторы использовали для расчета, выглядит следующим образом:

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

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

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

Внимание

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

Если это звучит запутанно, просто помните, что:

запрос — это то, что вы пытаетесь найти.

Ключ — это информация, которую содержит словарь.

значение и есть эта информация.

Источник — (Учебник по TensorFlow Transformer)

Трансформеры представили механизм внимания под названием Масштабируемое скалярное произведение внимания. Уравнение для него дано:

Где Q, K, Vпредставляют собой векторы запроса, ключа и значения. В большинстве приложений Transformers K и V являются одним и тем же вектором, а Q является входом, для которого вам требуется какой-то ответ. Мы вычисляем скалярное произведение Q и K и делим его на √d, где d — размер слоя внимания. Затем мы берем softmax этого вывода, который в основном преобразует вывод в оценки вероятности, которые затем умножаются на вектор значений. Этот механизм внимания позволяет нам сосредоточиться на соответствующих частях вектора значений, чтобы их можно было использовать в последующих вычислениях.

Многоголовое внимание

Вместо того, чтобы выполнять одно внимание, которое было бы дорого для больших измерений ключа, значения и запроса, мы вместо этого выполняем линейную проекцию на Q, K и V, чтобы преобразовать их в меньшие измерения, а затем выполняем вышеуказанное внимание. Мы делаем это несколько раз в отдельных экземплярах или «головках», чтобы позволить модели совместно обрабатывать информацию из разных представлений, поскольку каждая головка, вероятно, будет обслуживать разные пространства для одной и той же пары Q, K и V. Затем выходные данные каждой головки внимания объединяются и линейно проецируются для получения агрегированного вывода.

Сети прямого распространения

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

Где полносвязный слой представлен как F(x) = xW + b, где W — вес, а b — смещение. ReLU представлен как ReLU(x) = max(0, x).

Остаточные связи и нормализация

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

Уровень кодировщика

Теперь, когда мы рассмотрели каждый блок, пришло время посмотреть, как они объединяются. Входные вложения, которые мы предоставляем, вычисляются с помощью набора N блоков кодировщика. Каждый блок кодировщика состоит из уровня внимания с несколькими головками, где мы выполняем самостоятельное внимание на входе, т. е. где Q, K и V являются одним и тем же вектором. Выход этого затем подается на уровень прямой связи, выход которого затем используется следующим блоком кодера в качестве его ввода. Выход N-го блока кодировщика затем используется как пара K, V для уровня перекрестного внимания в блоках декодера. Входные вложения и N блоков кодировщика составляют уровень кодера.

Самостоятельное внимание

Когда мы передаем тот же входной вектор, что и запрос, ключ и значение, блоку Multi-Head Attention, это называется самостоятельным вниманием. Self-Attention позволяет каждому элементу в последовательности получать доступ ко всем другим элементам в последовательности параллельно и, таким образом, позволяет элементам ассоциировать себя с другими элементами и создавать более сильные представления контекста. Раньше это делалось с помощью RNN и CNN, но они были ограничены их последовательным характером и диапазоном.

Уровень декодера

Слой декодера немного интереснее. Большая часть структуры практически одинакова: N блоков декодера принимают выходные вложения в качестве входных данных, а затем их выходные данные используются следующим блоком до тех пор, пока окончательные выходные данные не будут отправлены в блоки декодера. >слой классификации. Вы можете заметить, что здесь есть два блока многоголового внимания, первый из которых добавляет изюминку к обычному блоку внутреннего внимания, называемому маскированное собственное внимание. Результат этого затем используется в качестве вектора запроса в следующем блоке множественного внимания, называемом блоком перекрестного внимания, где пара ключ-значение задается конечным выходом уровня кодировщика. Именно здесь модель фактически учится отображать выходные данные, чтобы они соответствовали тому, что представляют входные данные. Окончательный вывод после прохождения через все блоки декодера затем линейно проецируется на вектор, к которому мы применяем softmax, чтобы получить выходные вероятности, которые затем можно использовать для прогнозирования наиболее вероятного токена, который должен быть сгенерирован.

Последние линейные слои и слои softmax можно заменить любой «головой» классификации в зависимости от задачи, для которой вы хотите обучить свою модель.

Замаскированное внимание к себе

Изюминка внутреннего внимания, используемого декодером, заключается в том, что K и V маскируются, так что для данной последовательности элемент в векторе Q может обращать внимание только на свои предыдущие элементы. Это полезно, чтобы научить модель во время обучения тому, что она не может полагаться на информацию дальше в последовательности, к которой она могла бы получить доступ, когда модель обучается, но не когда она используется во время вывода. Как следствие, во время обучения мы смещаем выходную последовательность вправоодин раз (добавляя токен ‹СТАРТ›), так что токен может обращаться только к своим предыдущим токенам (право сдвига не позволяет данному токену посещать самому себе, что делает весь декодер причинным по своей природе)

Тренировка Трансформера

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

Во время вывода

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

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

Приложения

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

  • Языковое моделирование
  • Машинный перевод
  • Анализ настроений
  • Классификация
  • Предсказание следующего предложения
  • Перефразируя
  • Вопрос Ответ

Примеры

Существует множество примеров успешного использования моделей на основе трансформеров в реальном мире. Двумя наиболее известными примерами являются BERT (представления двунаправленного кодировщика от преобразователей) и GPT (преобразователь генеративного предварительного обучения). Оба следуют одной и той же архитектуре, но с некоторыми изменениями.

Последние мысли

Спасибо, что дочитали до конца статьи. Это мой первый раз, когда я пишу один, и я открыт для отзывов или любых предложений по улучшению. Надеюсь, я, по крайней мере, сделал Трансформеры немного более простыми для вашего понимания, с которыми вы, вероятно, можете продолжить и попытаться прочитать настоящую статью и получить еще больше ясности. Здесь, на Medium, также есть отличные статьи на ту же тему, на которые я буду ссылаться ниже. Я постараюсь дополнить этот пост практическим руководством о том, как вы можете использовать предварительно обученные преобразователи (такие как BERT) в своих собственных моделях и задачах. Оставайтесь с нами, чтобы узнать больше!

Рекомендации