http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&user=Nilaev&feedformat=atomВикиконспекты - Вклад участника [ru]2024-03-29T01:02:44ZВклад участникаMediaWiki 1.30.0http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82387Трансформер2022-06-15T14:03:04Z<p>Nilaev: </p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|400px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
Внутри кодирующего и декодирующего компонента нет рекуррентности. Кодирующий компонент состоит из кодировщиков, которые повторяются несколько раз, аналогично устроен декодирующий компонент. Трансформер {{---}} это поставленные друг за другом модели внимания, которые позволяют исходную последовательность векторов перевести в новую последовательность векторов, которые кодируют информацию о контексте каждого элемента. Трансформер-кодировщик переводит исходные векторы в скрытые, которые правильно сохраняют в себе информацию о контексте каждого элемента. Далее трансформер-декодировщик декодирует результат кодировщика в новую последовательность, которая состоит из эмбедингов элементов выходного языка. После по эмбедингам генерируются сами итоговые элементы с помощью вероятностной языковой модели.<br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3--7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncodingNew.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>https://kazemnejad.com/blog/transformer_architecture_positional_encoding/</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем информацию о порядке элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено. Пример такого кодирования:<br />
<br />
<math><br />
p_{(i, s)} =<br />
\begin{cases}<br />
\sin \left(i \cdot 10000^{\frac{-2k}{d_{model}}}\right) & \quad \text{если } s=2k\\<br />
\cos \left(i \cdot 10000^{\frac{-2k}{d_{model}}}\right) & \quad \text{если } s=2k+1<br />
\end{cases}<br />
</math><br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1--4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82379Трансформер2022-06-14T21:12:38Z<p>Nilaev: /* Позиционное кодирование */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру [[Механизм внимания#Базовая архитектура Seq2seq|Seq2seq]]: кодирующий компонент {{---}} это последовательные блоки кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это последовательные блоки декодировщиков (англ. ''decoders''). Кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3--7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncodingNew.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>https://kazemnejad.com/blog/transformer_architecture_positional_encoding/</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем информацию о порядке элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено. Пример такого кодирования:<br />
<br />
<math><br />
p_{(i, s)} =<br />
\begin{cases}<br />
\sin \left(i \cdot 10000^{\frac{-2k}{d_{model}}}\right) & \quad \text{если } s=2k\\<br />
\cos \left(i \cdot 10000^{\frac{-2k}{d_{model}}}\right) & \quad \text{если } s=2k+1<br />
\end{cases}<br />
</math><br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1--4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82378Трансформер2022-06-14T21:06:52Z<p>Nilaev: /* Позиционное кодирование */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру [[Механизм внимания#Базовая архитектура Seq2seq|Seq2seq]]: кодирующий компонент {{---}} это последовательные блоки кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это последовательные блоки декодировщиков (англ. ''decoders''). Кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3--7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncodingNew.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>https://kazemnejad.com/blog/transformer_architecture_positional_encoding/</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем информацию о порядке элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<br />
<math><br />
p_{(i, s)} =<br />
\begin{cases}<br />
\sin \left(i \cdot 10000^{\frac{-s}{d_{model}}}\right) & \quad \text{если } s \text{ четное}\\<br />
\cos \left(i \cdot 10000^{\frac{-s + 1}{d_{model}}}\right) & \quad \text{если } s \text{ нечетное}<br />
\end{cases}<br />
</math><br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1--4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82377Трансформер2022-06-14T20:55:40Z<p>Nilaev: </p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру [[Механизм внимания#Базовая архитектура Seq2seq|Seq2seq]]: кодирующий компонент {{---}} это последовательные блоки кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это последовательные блоки декодировщиков (англ. ''decoders''). Кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3--7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncodingNew.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>https://kazemnejad.com/blog/transformer_architecture_positional_encoding/</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем информацию о порядке элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<br />
<math><br />
p_{(i, s)} =<br />
\begin{cases}<br />
\sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right) & \quad \text{если } s \text{ четное}\\<br />
\cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right) & \quad \text{если } s \text{ нечетное}<br />
\end{cases}<br />
</math><br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1--4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82376Трансформер2022-06-14T20:11:10Z<p>Nilaev: /* Позиционное кодирование */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру [[Механизм внимания#Базовая архитектура Seq2seq|Seq2seq]]: кодирующий компонент {{---}} это последовательные блоки кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это последовательные блоки декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3--7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncodingNew.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>https://kazemnejad.com/blog/transformer_architecture_positional_encoding/</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем информацию о порядке элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<br />
<math><br />
p_{(i, s)} =<br />
\begin{cases}<br />
\sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right) & \quad \text{если } s \text{ четное}\\<br />
\cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right) & \quad \text{если } s \text{ нечетное}<br />
\end{cases}<br />
</math><br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1--4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:PositionalEncodingNew.png&diff=82375Файл:PositionalEncodingNew.png2022-06-14T19:58:42Z<p>Nilaev: </p>
<hr />
<div></div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82374Трансформер2022-06-14T19:50:23Z<p>Nilaev: </p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру [[Механизм внимания#Базовая архитектура Seq2seq|Seq2seq]]: кодирующий компонент {{---}} это последовательные блоки кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это последовательные блоки декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3--7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/images/e/e6/Voron-ML-TopicModeling-slides.pdf</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем информацию о порядке элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math><br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1--4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82373Трансформер2022-06-14T19:41:01Z<p>Nilaev: /* Архитектура трансформера */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру Seq2seq<ref>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC_%D0%B2%D0%BD%D0%B8%D0%BC%D0%B0%D0%BD%D0%B8%D1%8F&mobileaction=toggle_view_desktop#.D0.91.D0.B0.D0.B7.D0.BE.D0.B2.D0.B0.D1.8F_.D0.B0.D1.80.D1.85.D0.B8.D1.82.D0.B5.D0.BA.D1.82.D1.83.D1.80.D0.B0_Seq2seq</ref>: кодирующий компонент {{---}} это последовательные блоки кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это последовательные блоки декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/images/e/e6/Voron-ML-TopicModeling-slides.pdf</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем информацию о порядке элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math><br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82372Трансформер2022-06-14T19:34:25Z<p>Nilaev: /* Позиционное кодирование */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру Seq2seq<ref>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC_%D0%B2%D0%BD%D0%B8%D0%BC%D0%B0%D0%BD%D0%B8%D1%8F&mobileaction=toggle_view_desktop#.D0.91.D0.B0.D0.B7.D0.BE.D0.B2.D0.B0.D1.8F_.D0.B0.D1.80.D1.85.D0.B8.D1.82.D0.B5.D0.BA.D1.82.D1.83.D1.80.D0.B0_Seq2seq</ref>: кодирующий компонент {{---}} это стек кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/images/e/e6/Voron-ML-TopicModeling-slides.pdf</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем информацию о порядке элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math><br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82371Трансформер2022-06-14T19:31:12Z<p>Nilaev: /* Архитектура трансформера */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру Seq2seq<ref>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC_%D0%B2%D0%BD%D0%B8%D0%BC%D0%B0%D0%BD%D0%B8%D1%8F&mobileaction=toggle_view_desktop#.D0.91.D0.B0.D0.B7.D0.BE.D0.B2.D0.B0.D1.8F_.D0.B0.D1.80.D1.85.D0.B8.D1.82.D0.B5.D0.BA.D1.82.D1.83.D1.80.D0.B0_Seq2seq</ref>: кодирующий компонент {{---}} это стек кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/images/e/e6/Voron-ML-TopicModeling-slides.pdf</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем порядок элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math> <br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82370Трансформер2022-06-14T19:28:45Z<p>Nilaev: /* Архитектура трансформера */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор элементов без учета порядка в последовательности поступает в кодирующий компонент (параллельная обработка), а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру Seq2seq<ref>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC_%D0%B2%D0%BD%D0%B8%D0%BC%D0%B0%D0%BD%D0%B8%D1%8F&mobileaction=toggle_view_desktop#.D0.91.D0.B0.D0.B7.D0.BE.D0.B2.D0.B0.D1.8F_.D0.B0.D1.80.D1.85.D0.B8.D1.82.D0.B5.D0.BA.D1.82.D1.83.D1.80.D0.B0_Seq2seq</ref>: кодирующий компонент {{---}} это стек кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики последовательно передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/images/e/e6/Voron-ML-TopicModeling-slides.pdf</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем порядок элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math> <br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82369Трансформер2022-06-14T19:27:01Z<p>Nilaev: /* Архитектура трансформера */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибавляется вектор позиционного кодирования, после чего набор слов без учета порядка в последовательности поступает в кодирующий компонент, а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру Seq2seq<ref>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC_%D0%B2%D0%BD%D0%B8%D0%BC%D0%B0%D0%BD%D0%B8%D1%8F&mobileaction=toggle_view_desktop#.D0.91.D0.B0.D0.B7.D0.BE.D0.B2.D0.B0.D1.8F_.D0.B0.D1.80.D1.85.D0.B8.D1.82.D0.B5.D0.BA.D1.82.D1.83.D1.80.D0.B0_Seq2seq</ref>: кодирующий компонент {{---}} это стек кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики последовательно передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/images/e/e6/Voron-ML-TopicModeling-slides.pdf</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем порядок элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math> <br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82368Трансформер2022-06-14T19:26:20Z<p>Nilaev: добавлены уточнения</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), прибаляется вектор позиционного кодирования, после чего набор слов без учета порядка в последовательности поступает в кодирующий компонент, а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность.<br />
<br />
В основе лежит архитектура похожая на базовую архитектуру Seq2seq<ref>http://neerc.ifmo.ru/wiki/index.php?title=%D0%9C%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC_%D0%B2%D0%BD%D0%B8%D0%BC%D0%B0%D0%BD%D0%B8%D1%8F&mobileaction=toggle_view_desktop#.D0.91.D0.B0.D0.B7.D0.BE.D0.B2.D0.B0.D1.8F_.D0.B0.D1.80.D1.85.D0.B8.D1.82.D0.B5.D0.BA.D1.82.D1.83.D1.80.D0.B0_Seq2seq</ref>: кодирующий компонент {{---}} это стек кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики последовательно передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы работы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормализацию слоя (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормализацию слоя: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/images/e/e6/Voron-ML-TopicModeling-slides.pdf</ref>]]<br />
Так как в архитектуре трансформер обработка последовательности заменяется на обработку множества мы теряем порядок элементов последовательности. Чтобы отобразить информацию о позиции элемента в исходной последовательности мы используем позиционное кодирование.<br />
<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math> <br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, чтобы посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии с кодировщиком):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту для каждой позиции решаем задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82366Трансформер2022-06-14T12:18:05Z<p>Nilaev: /* Архитектура трансформера-декодировщика */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), векторизованная последовательность поступает в кодирующий компонент, а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность. <br />
<br />
Кодирующий компонент {{---}} это стек кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики последовательно передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормировку уровня (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормировку уровня: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/index.php</ref>]]<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math> <br />
<br />
По сути мы свели задачу обработки последовательности (''seq'') к множеству (''set'').<br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, что посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность влияния элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии, как и в кодировщике):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. В самом конце мы хотим получить вероятностную порождающую модель для элементов. Результат (индекс слова с наибольшей вероятностью): <math>\mathrm{SoftArgMax}(W_y y_t + b_y) </math>, где <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту решаем для каждого класса задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82365Трансформер2022-06-14T11:29:08Z<p>Nilaev: /* Архитектура трансформера-декодировщика */</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), векторизованная последовательность поступает в кодирующий компонент, а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность. <br />
<br />
Кодирующий компонент {{---}} это стек кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики последовательно передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормировку уровня (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормировку уровня: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/index.php</ref>]]<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math> <br />
<br />
По сути мы свели задачу обработки последовательности (''seq'') к множеству (''set'').<br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, что посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность влияния элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии, как и в кодировщике):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. Линейный предсказывающий слой:<br />
<math> p(\tilde w|t) = \mathrm{SoftMax}_{\tilde w}(W_y y_t + b_y) </math>, <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту решаем для каждого класса задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции. <br />
<br />
В самом конце мы имеем вероятностную порождающую модель для элементов и остается только породить эти элементы. Для простоты мы будем считать, что для каждой позиции просто выбирается самый вероятный элемент. Генерация самих элементов: <math> {\tilde w}_t = \mathrm{arg max}_{\tilde w} p(\tilde w|t) </math>, пока не сгенерируется слово обозначающее конец последовательности.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82364Трансформер2022-06-14T11:27:44Z<p>Nilaev: добавлены уточнения</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), векторизованная последовательность поступает в кодирующий компонент, а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность. <br />
<br />
Кодирующий компонент {{---}} это стек кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики последовательно передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормировку уровня (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормировку уровня: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/index.php</ref>]]<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math> <br />
<br />
По сути мы свели задачу обработки последовательности (''seq'') к множеству (''set'').<br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, что посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность влияния элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\sqrt{d}</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math>, где <math>\circ</math> {{---}} композиция.<br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии, как и в кодировщике):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. Линейный предсказывающий слой:<br />
<math> p(\tilde w|t) = \mathrm{Soft-argmax}_{\tilde w}(W_y y_t + b_y) </math>, <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту решаем для каждого класса задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции. <br />
<br />
В самом конце мы имеем вероятностную порождающую модель для элементов и остается только породить эти элементы. Для простоты мы будем считать, что для каждой позиции просто выбирается самый вероятный элемент. Генерация самих элементов: <math> {\tilde w}_t = \mathrm{arg max}_{\tilde w} p(\tilde w|t) </math>, пока не сгенерируется слово обозначающее конец последовательности.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82356Трансформер2022-06-11T21:46:46Z<p>Nilaev: добавлены уточнения</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), векторизованная последовательность поступает в кодирующий компонент, а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность. <br />
<br />
Кодирующий компонент {{---}} это стек кодировщиков (англ. ''encoders''), а декодирующий компонент {{---}} это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики последовательно передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(Q^j h_i, K^j H, V^j H)</math>, где обучаемые матрицы: <math>Q</math> для запроса, <math>K</math> для ключа, <math>V</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормировку уровня (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормировку уровня: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/index.php</ref>]]<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math> <br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными.<br />
<br />
Будем для каждого элемента <math>x_i</math> получать обучаемым преобразованием три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = Q x_i</math><br />
* Ключ (''key'') <math>k_i = K x_i</math><br />
* Значение (''value'') <math>v_i = V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, что посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность влияния элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(Q x_i, K X, V X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. <br />
По факту ''self-attention'' {{---}} это ''soft-arg-max'' с температурой <math>\mathrm{sqrt}(d)</math>. Мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(Q^j q, K^j X, V^j X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j H_t, V^j H_t) </math><br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(Q^j h_t, K^j Z, V^j Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии, как и в кодировщике):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. Линейный предсказывающий слой:<br />
<math> p(\tilde w|t) = \mathrm{SoftMax}_{\tilde w}(W_y y_t + b_y) </math>, <math> W_y </math>, <math> b_y </math> {{---}} обучаемые параметры линейного преобразования. Для каждой позиции <math>t</math> выходной последовательности мы строим вероятностную модель языка, то есть все элементы из выходного словаря получают значение вероятности. Эти значения как раз получаются из векторов <math>y_t</math> из предыдущего пункта, которые мы берем с последнего блока трансформера-декодировщика.<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту решаем для каждого класса задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции. <br />
<br />
В самом конце мы имеем вероятностную порождающую модель для элементов и остается только породить эти элементы. Для простоты мы будем считать, что для каждой позиции просто выбирается самый вероятный элемент. Генерация самих элементов: <math> {\tilde w}_t = \mathrm{arg max}_{\tilde w} p(\tilde w|t) </math>, пока не сгенерируется слово обозначающее конец последовательности. По сути мы свели задачу обработки последовательности (''seq'') к множеству (''set'').<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82355Трансформер2022-06-10T21:17:32Z<p>Nilaev: обновление стилей</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера<ref>https://jalammar.github.io/illustrated-transformer/</ref>]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), векторизованная последовательность поступает в кодирующий компонент, а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность. <br />
<br />
Кодирующий компонент – это стек кодировщиков (англ. ''encoders''), а декодирующий компонент – это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики последовательно передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
Рассмотрим последовательно шаг за шагом этапы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = \mathrm{Attn}(W^j_q h_i, W^j_k H, W^j_v H)</math>, где <math>W</math> {{---}} обучаемые матрицы, <math>W_q</math> для запроса, <math>W_k</math> для ключа, <math>W_v</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') {{---}} по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормировку уровня (англ. ''layer normalization''): <math>h''_i = \mathrm{LN}(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым {{---}} полносвязную двухслойную нейронную сеть: <br />
<math> h'''_i = W_2 \mathrm{ReLU} (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормировку уровня: <math>z_i = \mathrm{LN}(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|400px|thumb|right|Визуализация работы позиционного кодирования<ref>http://www.machinelearning.ru/wiki/index.php</ref>]]<br />
Позиционное кодирование (англ. ''positional encoding'') {{---}} позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos \left(i \cdot 10000^{\frac{-2s}{d_{model}}}\right)</math> <br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными. <br />
<br />
Будем для каждого элемента <math>x_i</math> обучать три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = W_Q x_i</math><br />
* Ключ (''key'') <math>k_i = W_K x_i</math><br />
* Значение (''value'') <math>v_i = W_V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, что посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность влияния элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp \left(\frac{\langle q_i, k_j \rangle}{\sqrt{d}} \right)<br />
}{<br />
\sum_{p=1}^n \exp \left(\frac{\langle q_i, k_p \rangle}{\sqrt{d}} \right)<br />
}</math>, <br />
где <math>d</math> {{---}} размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> {{---}} число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = \mathrm{Attn}(W_q x_i, W_k X, W_v X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы. По итогу мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = \mathrm{Attn}(W^j_q q, W^j_k X, W^j_v X)</math>, где <math>j = 1...J</math>, <math>J</math> {{---}} число разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> {{---}} входные векторы, а <math>W</math> {{---}} обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика<ref>https://arxiv.org/abs/1706.03762</ref>]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(W^j_q h_t, W^j_k H_t, W^j_v H_t) </math><br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = \mathrm{LN} \circ M H_j \circ \mathrm{Attn}(W^j_q h_t, W^j_k Z, W^j_v Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии, как и в кодировщике):<br />
<math> y_t = \mathrm{LN} \circ FNN(h''_t) </math><br />
<br />
5. Линейный предсказывающий слой:<br />
<math> p(\tilde w|t) = \mathrm{SoftMax}_{\tilde w}(W_y y_t + b_y) </math>, <math> W_y </math> {{---}} обучаемая матрица весовых коэффицентов, <math> b_y </math> {{---}} обучаемый вектор смещения<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту решаем для каждого класса задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции. В самом конце происходит генерация самих элементов: <math> {\tilde w}_t = \mathrm{arg max}_{\tilde w} p(\tilde w|t) </math>, пока не сгенерируется слово обозначающее конец последовательности.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%80%D0%B0%D0%BD%D1%81%D1%84%D0%BE%D1%80%D0%BC%D0%B5%D1%80&diff=82354Трансформер2022-06-09T18:08:40Z<p>Nilaev: Написал статью про трансформеры</p>
<hr />
<div>'''Трансформер''' (англ. ''transformer'') {{---}} архитектура глубоких нейронных сетей, основанная на [[:Механизм_внимания|механизме внимания]] без использования [[:Рекуррентные_нейронные_сети|рекуррентных нейронных сетей]] (сокр. ''RNN''). Самое большое преимущество трансформеров по сравнению с RNN заключается в их высокой эффективности в условиях параллелизации. Впервые модель трансформера была предложена в статье Attention is All You Need<ref>https://arxiv.org/abs/1706.03762</ref> от разработчиков Google в 2017 году.<br />
<br />
==Архитектура трансформера==<br />
[[Файл:TransformerSimpleArchitecture.png|350px|thumb|right|Архитектура трансформера]]<br />
Устройство трансформера состоит из кодирующего и декодирующего компонентов. На вход принимается некая последовательность, создается ее [[:Векторное_представление_слов|векторное представление]] (англ. ''embedding''), векторизованная последовательность поступает в кодирующий компонент, а затем декодирующий компонент получает на вход часть этой последовательности и выход кодирующего. В результате получается новая выходная последовательность. <br />
<br />
Кодирующий компонент – это стек кодировщиков (англ. ''encoders''), а декодирующий компонент – это стек декодировщиков (англ. ''decoders''). Каждый кодировщики последовательно передает результат своей работы следующему кодировщику на вход. Декодировщики последовательно передают друг другу на вход результат работы вместе с результатом кодирующего компонента. <br />
<br />
Ниже рассмотрим архитектуру кодировщика и декодировщика подробнее.<br />
<br />
==Архитектура трансформера-кодировщика==<br />
[[Файл:TransformerEncoderArchitecture.png|150px|thumb|left|Архитектура трансформера-кодировщика]]<br />
Рассмотрим последовательно шаг за шагом этапы кодировщика:<br />
<br />
1. На вход поступает последовательность элементов <math>w_i</math>, по ней создается последовательность эмбедингов, где каждый <math>x_i</math> это векторное представление элемента <math>w_i</math>.<br />
<br />
2. Добавляются позиционные векторы <math>p_i</math>: <math>h_i = x_i + p_i</math>, <math>H = (h_1,...,h_n)</math>.<br />
Это необходимо для того, чтобы отобразить информацию о позиции элемента в исходной последовательности. Основное свойство позиционного кодирования {{---}} чем дальше два вектора будут стоять друг от друга в последовательности, тем больше между ними будет расстояние. Более подробное устройство позиционного кодирования будет рассмотрено ниже. <br />
<br />
3. Полученный вектор <math>h_i</math> подается на вход в блок многомерного самовнимания (англ. ''multi-headed self-attention''). <br />
<math>h^j_i = Attn(W^j_q h_i, W^j_k H, W^j_v H)</math>, где <math>W</math> - обучаемые матрицы, <math>W_q</math> для запроса, <math>W_k</math> для ключа, <math>W_v</math> для значения. Подробное объяснения работы механизма self-attention будет разобрано ниже. <br />
<br />
4. Затем необходима конкатенация, чтобы вернуться в исходную размерность: <math> h'_i = M H_j (h^j_i) = [h^1_i...h^J_i] </math><br />
<br />
5. Добавим сквозные связи (англ. ''skip connection'') - по факту просто добавление из входного вектора к выходному (<math>h'_i + h_i</math>). После делаем нормировку уровня (англ. ''layer normalization''): <math>h''_i = LN(h'_i + h_i; \mu_1, \sigma_1)</math>. У нее два обучаемых параметра, для каждой размерности вектора вычисляется среднее и дисперсия. <br />
<br />
6. Теперь добавим преобразование, которое будет обучаемым - полносвязную 2х-слойную нейронную сеть: <br />
<math> h'''_i = W_2 ReLU (W_1 h''_i + b_1) + b_2 </math> <br />
<br />
7. Повторим пункт 5 еще раз: добавим сквозную связь и нормировку уровня: <math>z_i = LN(h'''_i + h''_i; \mu_2, \sigma_2)</math><br />
<br />
После, в кодирующем компоненте пункты кодировщика 3-7 повторяются еще несколько раз, преобразовывая друг за другом из контекста контекст. Тем самым мы обогащаем модель и увеличиваем в ней количество параметров.<br />
<br />
<br />
<br />
<br />
===Позиционное кодирование===<br />
[[Файл:PositionalEncoding.png|450px|thumb|right|Визуализация работы позиционного кодирования]]<br />
Позиционное кодирование (англ. ''positional encoding'') - позволяет модели получить информацию о порядке элементов в последовательности путем прибавления специальных меток к вектору входных элементов. Позиции элементов <math>i</math> кодируются векторами <math>p_i</math>, <math>i = 1, 2, ..., n</math>, так, что чем больше <math>|i - j|</math>, тем больше <math>||p_i - p_j||</math>, и <math>n</math> не ограничено:<br />
<math>p_{(i, s)} = \sin(i \cdot 10000^{\frac{-2s}{d_{model}}})</math>,<br />
<math>p_{(i, s + \frac{d}{2})} = \cos(i \cdot 10000^{\frac{-2s}{d_{model}}})</math> <br />
<br />
===Self-attention===<br />
'''Self-Attention''' {{---}} разновидность [[:Механизм_внимания|механизма внимания]], задачей которой является выявление закономерности между входными данными. <br />
<br />
Будем для каждого элемента <math>x_i</math> обучать три вектора:<br />
<br />
* Запрос (''query'') <math>q_i = W_Q x_i</math><br />
* Ключ (''key'') <math>k_i = W_K x_i</math><br />
* Значение (''value'') <math>v_i = W_V x_i</math><br />
<br />
Векторы <math>q_i</math> и <math>k_i</math> будем использовать, что посчитать важность элемента <math>x_j</math> для элемента <math>x_i</math>. Чтобы понять, насколько для пересчета вектора элемента <math>x_i</math> важен элемент <math>x_j</math> мы берем <math>k_j</math> (вектор ключа элемента <math>x_j</math>) и умножаем на <math>q_i</math> (вектор запроса элемента <math>x_i</math>). Так мы скалярно перемножаем вектор запроса на все векторы ключей, тем самым понимаем, насколько каждый входной элемент нам нужен, чтобы пересчитать вектор элемента <math>x_i</math>.<br />
<br />
Далее считаем важность влияния элемента <math>x_j</math> для кодирования элемента <math>x_i</math>:<br />
<math>w_{ji}=\frac{<br />
\exp(\frac{\langle q_i, k_j \rangle}{\sqrt{d}})<br />
}{<br />
\sum_{p=1}^n \exp(\frac{\langle q_i, k_p \rangle}{\sqrt{d}})<br />
}</math>, <br />
где <math>d</math> - размерность векторов <math>q_i</math> и <math>k_j</math>, а <math>n</math> - число элементов во входной последовательности. <br />
<br />
Таким образом, новое представление элемента <math>x_i</math> считаем как взвешенную сумму векторов значения: <math>z_i = Attn(W_q x_i, W_k X, W_v X) = \sum_{p=1}^n w_{p i} v_p</math>, где <math>X = (x_1, x_2, ..., x_n)</math> - входные векторы. По итогу мы перемешиваем все входные векторы, чтобы получить новые векторы всех элементов, где каждый элемент зависит от всех входных элементов. <br />
<br />
===Multi-headed self-attention===<br />
'''Multi-headed self-attention''' {{---}} улучшенная модификация self-attention.<br />
<br />
Слой внимания снабжается множеством «подпространств представлений» (англ. ''representation subspaces''). Теперь у нас есть не один, а множество наборов матриц запроса/ключа/значения. Каждый из этих наборов создается случайным образом. Далее после обучения каждый набор используется для отображения входящих векторов в разных подпространствах представлений. Также появляется способность модели фокусироваться на разных аспектах входной информации. <br />
<br />
То есть параллельно независимо несколько раз делаем attention. Потом результат каждого attention по элементам конкатенируем, затем сжимаем получившуюся матрицу и получаем для каждого элемента свой вектор той же размерности.<br />
<br />
<math>с^j = Attn(W^j_q q, W^j_k X, W^j_v X)</math>, где <math>j = 1...J</math>, <math>J</math> - количество разных моделей внимания, <math>X = (x_1, x_2, ..., x_n)</math> - входные векторы, а <math>W</math> - обучаемые матрицы.<br />
<br />
<br />
<br />
==Архитектура трансформера-декодировщика==<br />
[[Файл:TransformerDecoderArchitecture.png|150px|thumb|left|Архитектура трансформера-декодировщика]]<br />
На вход декодировщику подается выход кодировщика. Главное отличие архитектуры декодировщика заключается в том, что дополнительно имеется attention к вектору, который получен из последнего блока кодирующего компонента. Компонент декодировщика тоже многослойный и каждому блоку компонента на вход подается вектор именно с последнего блока кодирующего компонента. Разберем по порядку этапы работы декодировщика:<br />
<br />
1. Для того, чтобы распараллелить декодировщик и уйти от [[:Рекуррентные_нейронные_сети|рекуррентности]], но тем не менее генерировать элементы друг за другом, используется прием маскирования данных из будущего. Идея в том, что мы запрещаем себе подглядывать в те элементы, которые еще не сгенерированы с учетом порядка. Когда генерируем элемент под номером <math>t</math>, имеем право смотреть только первые <math>t-1</math> элементов: <math>h_t = y_{t-1} + p_t</math>; <math>H_t=(h_1, ...,h_t)</math><br />
<br />
2. Далее идет этап многомерного самовнимания: линейная нормализация и multi-headed self-attention. Особенность в том, что в attention ключи и значения применяются не ко всем векторам, а только к тем, значения которых уже синтезировали (<math>H_t</math>): <br />
<math> h'_t = LN \circ M H_j \circ Attn(W^j_q h_t, W^j_k H_t, W^j_v H_t) </math><br />
<br />
3. На следующем этапе мы делаем многомерное внимание на кодировку <math>Z</math>, результат работы компонента кодировщика:<br />
<math> h''_t = LN \circ M H_j \circ Attn(W^j_q h_t, W^j_k Z, W^j_v Z) </math><br />
<br />
4. Линейная полносвязная сеть (по аналогии, как и в кодировщике):<br />
<math> y_t = LN \circ FNN(h''_t) </math><br />
<br />
5. Линейный предсказывающий слой:<br />
<math> p(\tilde w|t) = SoftMax_{\tilde w}(W_y y_t + b_y) </math>, <math> W_y </math> - обучаемая матрица весовых коэффицентов, <math> b_y </math> - обучаемый вектор смещения<br />
<br />
Последний этап выполняется только после того, когда повторились пункты 1-4 для всех декодировщиков. На выходе получаем вероятности классов, по факту решаем для каждого класса задачу многоклассовой классификации, для того, чтобы понять какие элементы лучше поставить на каждые позиции. В самом конце происходит генерация самих элементов: <math> {\tilde w}_t = arg max_{\tilde w} p(\tilde w|t) </math>, пока не сгенерируется слово обозначающее конец последовательности.<br />
<br />
==Источники информации==</div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:TransformerDecoderArchitecture.png&diff=82353Файл:TransformerDecoderArchitecture.png2022-06-09T17:54:20Z<p>Nilaev: </p>
<hr />
<div></div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:PositionalEncoding.png&diff=82352Файл:PositionalEncoding.png2022-06-09T15:00:19Z<p>Nilaev: </p>
<hr />
<div></div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:TransformerEncoderArchitecture.png&diff=82351Файл:TransformerEncoderArchitecture.png2022-06-09T12:07:02Z<p>Nilaev: </p>
<hr />
<div></div>Nilaevhttp://neerc.ifmo.ru/wiki/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:TransformerSimpleArchitecture.png&diff=82350Файл:TransformerSimpleArchitecture.png2022-06-09T11:20:53Z<p>Nilaev: </p>
<hr />
<div></div>Nilaev