Введение

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

Концепция внимания впервые получила широкое распространение из-за ее использования в модели «последовательность-последовательность» (seq2seq) для нейронного машинного перевода. В обычной модели seq2seq на основе LSTM (/GRU/RNN) производительность модели сталкивается с узким местом, вызванным ограниченным объемом информации, которая может быть передана от кодировщика к декодеру через конечное скрытое состояние кодировщика.

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

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

Общая схема внимания

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

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

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

На рис. 2 большой прямоугольный блок со скругленными углами представляет блок вычисления внимания, для которого требуется один элемент в качестве одного входа и последовательность элементов в качестве другого входа, на который обращает внимание предыдущий элемент ввода. Каждая черная точка представляет элемент ввода. Единственный входной элемент справа соответствует зеленому вектору запроса, который можно рассматривать как упомянутый выше вектор A. Каждый входной элемент во входной последовательности слева соответствует паре векторов (ключевой вектор и вектор значений). Конечно, мы можем просто использовать сам зеленый вектор, чтобы сделать прогноз, передав его в нейронную сеть с прямой связью или что-то в этом роде, но это вряд ли будет иметь хорошую производительность. Если мы знаем, что последовательность элементов слева также содержит некоторую информацию, полезную для более точных прогнозов, мы можем сделать следующее, чтобы интегрировать все эти векторы вместе, как показано на рис. 2:

  1. Мы берем запрос и взаимодействуем с ключами один за другим. Конкретное взаимодействие между запросом и каждым ключом обозначено фиолетовым квадратом, и это может быть что-то вроде внутреннего продукта или комбинации сложения или конкатенации и передачи в небольшую нейронную сеть и т. д. Обратите внимание, что если есть какие-либо обучаемые параметры в фиолетовый блок (как маленькая нейронная сеть) должен быть одинаковым для всех фиолетовых блоков, нарисованных на рисунке. Другими словами, мы используем одну и ту же операцию с теми же параметрами, обученными из обратного распространения, для обработки запроса и каждого отдельного ключа. Кроме того, мы требуем, чтобы окончательный результат после этих операций был одним значением. Назовем одно выходное значение из фиолетового прямоугольника энергией. После повторения этого процесса для запроса и всех ключевых векторов у нас будет ряд энергий, каждая из которых исходит от запроса, взаимодействующего с другим ключом через один и тот же фиолетовый прямоугольник.
  2. Используйте слой softmax для нормализации всех энергий.
  3. Сделайте взвешенную сумму по векторам значений, при этом вес будет нормализованной энергией. Это дает вектор контекста с той же размерностью, что и один вектор значений, который содержит информацию обо всех элементах, объединенных разумным образом.
  4. Теперь мы можем использовать вектор контекста и вектор запроса вместе, чтобы сделать прогноз, скажем, объединив их, а затем передав в нейронную сеть, а затем слой softmax или что-то еще в зависимости от наших потребностей.

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

Анализ настроений

Задачи типа анализа настроений — это тип задач классификации, в которых входными данными является фрагмент текста, а выходными данными — метка, соответствующая одному из возможных настроений. Прежде чем текст будет загружен в нейронную сеть, его необходимо очистить, отформатировать, разбить на токены и преобразовать в последовательность индексов на основе словаря. Хотя это не seq2seq, а seq2one, механизм внимания по-прежнему применим и помогает повысить производительность.

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

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

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

На рис. 3 процедура взаимодействия запросов и ключей выглядит следующим образом:

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

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

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

Перевод даты

Перевод даты является примером задач seq2seq на уровне символов. Цель этой задачи — взять удобочитаемую дату в качестве входных данных, например «16 сентября 2018 г.» или «06 августа 2022 г.», и вывести машиночитаемую дату, которая представляет ту же дату, что и ввод, например «2018–09–16» или «2022–08–06».

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

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

Проверьте мой репозиторий GitHub для конкретной реализации модели seq2seq на основе LSTM с механизмом внимания для перевода дат.

Разговорный чат-бот

Разговорный чат-бот — пример задач seq2seq на уровне слов. Другие примеры включают языковой перевод, обобщение текста, ответы на вопросы и т. д. Эти задачи также могут выполняться с помощью моделей seq2seq на основе LSTM, но здесь мы используем архитектуру Transformer.

Модель Трансформера основана исключительно на само-внимании. Самовнимание относится к тому факту, что токены в предложении получают свои представления, обращая внимание на само предложение. Кроме того, в оригинальной статье Transformer также была предложена концепция многоголового внимания, где разные головы учатся по-разному обращать внимание на контекст, что приводит к более полным представлениям. Схема многоголового блока внимания показана на рис. 5.

Блок внимания с несколькими головками следует общей схеме вычисления внимания с некоторыми расширениями, которые позволяют ему лучше понимать язык. Сходство между блоком внимания с несколькими головками на рис. 5 и блоком внимания на рис. 2 заключается в том, что они оба требуют значений, ключей и запроса в качестве входных данных, и что они оба включают взвешенную сумму по векторам значений, где веса зависят от взаимодействия. между запросом и ключами. Расширения блока внимания с несколькими головками:

  1. Существует последовательность запросов вместо одного запроса.
  2. Есть три нейронные сети, которые отвечают за сопоставление каждого вектора входного значения, ключа и последовательности запроса с новым вектором той же размерности.
  3. Сопоставленные последовательности векторов равномерно разбиваются на несколько последовательностей меньших векторов (называемых разными головками).
  4. Последовательности значений, ключей и запросов в каждой голове проходят расчет внимания. В каждой голове каждый запрос обращает внимание на ключи и значения, приводящие к одному вектору контекста, поэтому общее количество векторов контекста, созданных здесь, равно количеству векторов запроса. Взаимодействие между запросом и вектором ключа представляет собой скалярное произведение, нормализованное квадратным корнем размерности вектора ключа (или значения, или запроса) в одной голове.
  5. Объедините результирующие последовательности векторов контекста в разных головках вместе и пройдите через одну последнюю нейронную сеть для вывода результатов. Таким образом, выходные данные представляют собой последовательность векторов контекста с той же размерностью, что и сопоставленный вектор запроса/ключа/значения. Выходная последовательность векторов контекста представляет собой представление последовательности входных векторов запроса на основе контекста, заданного ключами и значениями.

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

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

Блок внимания с несколькими головками — самый важный блок в архитектуре Transformer. Кодер-трансформер строится путем объединения нескольких блоков энкодера, и структура одного блока энкодера показана на рис. 6.

Точно так же декодер Transformer состоит из сложенных блоков декодера, где каждый блок декодера выглядит так:

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

Наконец, можно построить преобразователь, соединив кодер и декодер и добавив позиционное кодирование и головку классификации:

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

Складывая несколько блоков кодировщика/декодера в стопку для формирования кодировщика/декодера, Transformer способен изучать сложные корреляции в языке и извлекать исчерпывающее представление для каждого токена, которое затем подается на окончательный полносвязный уровень и softmax для прогнозирования. .

Если вам интересно, как создать и обучить игрушечного чат-бота с нуля с помощью Transformer, не стесняйтесь заглянуть в мой репозиторий GitHub.

После того, как в 2017 году была предложена техника самоконтроля с несколькими головами, она широко использовалась в различных задачах НЛП. Два больших семейства современных моделей НЛП, а именно BERT и GPT, основаны на кодировщике и декодере Transformer соответственно. Их появление также сделало возможным эффективное трансфертное обучение в НЛП. Более того, идея внимания также распространилась на другие области, такие как компьютерное зрение, где она сочетается со сверточной нейронной сетью (CNN) для достижения передовой производительности во многих задачах.

Сводка

Кратко повторим то, о чем мы говорили:

  1. Мы ввели общие рамки внимания.
  2. Мы приводим пример использования внимания тремя типичными архитектурами: bi-LSTM для задач классификации и модель seq2seq на основе LSTM и Transformer для задач seq2seq.
  3. Включены три проекта для трех типов задач: обнаружение токсичных комментариев, перевод даты и диалоговый чат-бот.

Надеюсь, вы нашли что-то полезное в этом блоге и счастливого обучения!

Благодарность

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