Это часть 1/2 книги Dissecting BERT, написанной Мигелем Ромеро и Франсиско Ингамом. Каждая статья написана совместно обоими авторами. Если вы уже знакомы с архитектурой кодировщика из Внимание - это все, что вам нужно, и вас интересуют отличия, которые делают BERT потрясающим, перейдите к Специфика BERT.

Большое спасибо Яннет Интериан за ее обзор и отзывы.

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

Обозначение

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

emb_dim: размер встраиваемых токенов.

input_length: длина входной последовательности (одинаковая для всех последовательностей в определенном пакете из-за заполнения).

hidden_dim: размер скрытого слоя сети прямой связи.

vocab_size: количество слов в словаре (полученное из корпуса).

Вступление

Кодировщик, используемый в BERT, представляет собой архитектуру обработки естественного языка (NLP), основанную на внимании, которая была представлена ​​в статье Все, что вам нужно, внимание год назад. В документе представлена ​​архитектура, называемая преобразователем, которая состоит из двух частей: кодировщика и декодера. Поскольку BERT использует только кодировщик, мы собираемся объяснить это только в этом сообщении в блоге (если вы хотите узнать о декодере и о том, как он интегрирован с Encoder, мы написали об этом отдельную запись в блоге).

Трансферное обучение быстро стало стандартом для современных результатов в НЛП с момента выпуска ULMFiT в начале этого года. После этого значительные успехи были достигнуты за счет объединения Transformer с трансферным обучением. Двумя яркими примерами этой комбинации являются OpenAI GPT и Google БЕРТ AI.

Цель этой серии:

  1. Обеспечьте интуитивное понимание базовой архитектуры Transformer и BERT.
  2. Объясните основные принципы того, что делает BERT таким успешным в задачах НЛП.

Чтобы объяснить эту архитектуру, мы воспользуемся подходом от общего к конкретному. Мы начнем с рассмотрения информационного потока в архитектуре, а затем погрузимся во входные и выходные данные кодировщика, представленные в документе . Затем мы рассмотрим каждый из блоков кодировщика и поймем, как используется Multi-Head Attention. Не волнуйтесь, если вы еще не знаете, что это такое; мы убедимся, что вы это поняли к концу этой статьи.

Поток информации

Поток данных через архитектуру выглядит следующим образом:

  1. Модель представляет каждый токен как вектор размера emb_dim. С одним вектором внедрения для каждого из входных токенов у нас есть матрица размеров (input_length) x (emb_dim) для конкретной входной последовательности.
  2. Затем он добавляет позиционную информацию (позиционное кодирование). Этот шаг возвращает матрицу размеров (input_length) x (emb_dim), как и на предыдущем шаге.
  3. Данные проходят через N блоков кодера. После этого получаем матрицу размеров (input_length) x (emb_dim).

Примечание. Размеры входа и выхода блока кодировщика одинаковы. Следовательно, имеет смысл использовать выход одного блока кодера в качестве входа следующего блока кодера.

Примечание. В экспериментах BERT количество блоков N (или L, как они его называют) было выбрано равным 12 и 24.

Примечание. блоки не имеют одинаковых весов друг с другом.

От слов к векторам

Токенизация, оцифровка и встраивание слов

Токенизация, оцифровка и встраивание не отличаются от того, как это делается с RNN. Учитывая предложение в корпусе:

" Привет, как дела?"

Первый шаг - токенизировать его:

" Привет, как дела?" → [«Привет», «,», «как», «есть», «ты», «?»]

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

[«Привет», «,«, «как», «есть» »,« ты »,«? »] → [34, 90, 15, 684, 55, 193]

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

Поэтому для каждого токена ищем соответствующий вектор:

Складывая каждый из векторов вместе, мы получаем матрицу Z размеров (input_length) x (emb_dim):

Важно отметить, что заполнение использовалось для того, чтобы входные последовательности в пакете имели одинаковую длину. То есть мы увеличиваем длину некоторых последовательностей, добавляя токены «‹pad›. Последовательность после заполнения может быть такой:

[«‹Pad›», «‹pad›», «‹pad›», «Привет», «,«, как »,« есть »,« вы »,«? »] →

[5, 5, 5, 34, 90, 15, 684, 55, 193]

если для input_length было установлено значение 9.

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

Примечание. В BERT авторы использовали заученные позиционные вложения. Если вас интересует только BERT, вы можете пропустить этот раздел, в котором мы объясняем функции, используемые для расчета позиционных кодировок в Attention is All You Need.

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

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

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

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

Подход, выбранный в статье для добавления этой информации, заключается в добавлении к Z матрицы P с позиционным кодированием.

Z + P

Авторы решили использовать комбинацию синусоидальных функций. Математически, используя i для позиции токена в последовательности и j для позиции функции внедрения:

Более конкретно, для данного предложения P матрица позиционного вложения будет следующей:

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

  • input_length можно увеличивать до бесконечности, так как функции могут быть вычислены для любой произвольной позиции.
  • Требовалось изучить меньше параметров, а модель обучить быстрее.

Полученная матрица:

X = Z + P

является входом первого блока кодировщика и имеет размеры (input_length) x (emb_dim).

Блок кодировщика

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

Интуитивно этот итеративный процесс через блоки поможет нейронной сети зафиксировать более сложные отношения между словами во входной последовательности. Вы можете думать об этом как об итеративном построении значения входной последовательности в целом.

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

Преобразователь использует Multi-Head Attention, что означает, что он вычисляет внимание h разное время с разными матрицами весов, а затем объединяет результаты вместе.

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

Как показано на рисунке 7, после вычисления всех головок они будут объединены. В результате получится матрица размеров (input_length) x (h * d_v). После этого будет применен линейный слой с весовой матрицей W⁰ размеров (h * d_v) x (emb_dim), что приведет к окончательному результату с размерами (input_length) x (emb_dim) . Математически:

Где Q, K и V - заполнители для разных входных матриц. В частности, для этого случая Q, K и V будут заменены выходной матрицей предыдущего шага X.

Масштабируемое внимание к скалярному продукту

Обзор

Каждая голова будет характеризоваться тремя различными проекциями (матричными умножениями), заданными матрицами:

Для вычисления головы мы возьмем входную матрицу X и отдельно спроецируем ее с указанными выше матрицами весов:

Примечание: в документе d_k и d_v установлены так, что d_k = d_v = emb_dim / h

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

Графически:

Примечание: в блоке кодировщика при вычислении внимания маска не используется. В нашей публикации Decoder мы объясняем, как декодер использует маскировку.

Углубляясь

Это ключ к архитектуре (название статьи не случайно), поэтому нам нужно внимательно его понять. Начнем с рассмотрения матричного произведения между Q_i и K_i транспонированным:

Помните, что Q_i и K_i были разными проекциями токенов в пространство измерений d_k. Следовательно, мы можем рассматривать скалярное произведение этих прогнозов как меру сходства между проекциями токенов. Для каждого вектора, проецируемого через Q_i, скалярное произведение с проекциями через K_i измеряет сходство между этими векторами. Если мы вызовем v_i и u_j проекции i-го токена и j-го токена через Q_i и K_i соответственно, их скалярное произведение можно увидеть как:

Таким образом, это показатель того, насколько похожи направления u_i и v_j и насколько велика их длина (чем ближе направление и чем больше длина, тем больше скалярное произведение).

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

После этого умножения матрица поэлементно делится на квадратный корень из d_k для масштабирования.

Следующим шагом является построчное применение Softmax (одно вычисление softmax для каждой строки):

В нашем примере это может быть:

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

Пример 1

Для понимания предложим фиктивный пример. Предположим, что получившаяся первая строка:

это [0,0,0,0,1,0]. Следовательно, поскольку 1 находится в 5-й позиции вектора, результат будет следующим:

Где v_ {token} - это проекция через V_i представления токена. Обратите внимание, что в этом случае слово «привет» заканчивается представлением, основанным на 4-м токене «вы» ввода для этой заголовка.

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

Пример 2

Давайте теперь немного усложним пример. Предположим теперь наш предыдущий пример в более общем сценарии, где есть не просто 1 в строке, а десятичные положительные числа, сумма которых равна 1:

Если мы сделаем, как в предыдущем примере, и умножим это на V_i:

В результате получается матрица, в которой каждая строка представляет собой композицию проекции представлений токена через V_i:

Обратите внимание на то, что мы можем рассматривать результирующее представление «Hello» как взвешенную комбинацию (центроид) проецируемых векторов через V_i входных токенов.

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

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

Тогда первая строка результата слоя Multi-Head Attention, то есть представление «Hello» в этой точке, будет

Это вектор длины emb_dim, учитывая, что матрица W_0 имеет размеры (d_v * h) x (emb_dim). Применяя ту же логику к остальным представлениям строк / токенов, мы получаем матрицу размеров (input_length) x (emb_dim).

Таким образом, на данном этапе представление токена представляет собой конкатенацию h взвешенных комбинаций представлений токенов (центроидов) через h различных изученных проекций.

Позиционная сеть прямой связи

Этот шаг состоит из следующих слоев:

Математически для каждой строки вывода предыдущего слоя:

где W_1 и W_2 - матрицы (emb_dim) x (d_F) и (d_F) x (emb_dim) соответственно .

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

Выходные данные этого шага имеют размер (input_length) x (emb_dim).

Выпадение, добавление и норма

Перед этим слоем всегда есть слой, для которого входы и выходы имеют одинаковые размеры (Multi-Head Attention или Feed-Forward). Мы назовем этот слой Sublayer и его вход x.

После каждого подслоя выпадение применяется с 10% вероятностью. Назовите этот результат Dropout (Sublayer (x)). Этот результат добавляется к входу подслоя x,, и мы получаем x + Dropout (Sublayer (x)).

Обратите внимание, что в контексте слоя Multi-Head Attention это означает добавление исходного представления токена x к представлению на основе связи с другими токенами. Это как сказать токену:

«Изучите отношения с остальными токенами, но не забывайте то, что мы уже узнали о вас!»

Наконец, вычисляется токеновая / построчная нормализация со средним значением и стандартным отклонением для каждой строки. Это улучшает стабильность сети.

Результатом этих слоев является:

Вот и все! Это архитектура, лежащая в основе всей магии современного НЛП.

Если у вас есть отзыв, дайте нам знать в разделе комментариев!

использованная литература

Внимание - все, что вам нужно; Vaswani et al., 2017.

BERT: предварительная подготовка глубоких двунаправленных преобразователей для понимания языка; Девлин и др., 2018.

Аннотированный трансформатор; Александр Раш, Винсент Нгуен и Гийом Кляйн.

Настройка универсальной языковой модели для классификации текста; Ховард и др., 2018.

Улучшение понимания языка с помощью генеративного предварительного обучения; Рэдфорд и др., 2018.

Источник обложки: Cripttografia e numeri primi