«Внимание — это все, что вам нужно» — это основополагающая статья, опубликованная в 2017 году, в которой впервые была представлена модель Трансформера.
Эта статья полностью изменила направление исследований в области обработки естественного языка (НЛП) и заложила основу для многих последующих моделей и приложений НЛП. Знакомый нам ChatGPT также основан на представленном сегодня Transformer.
Основные концепции проектирования модели Трансформера можно резюмировать следующим образом:
Далее поймите три основных вектора QKV внимания к себе:
Вычисляет слово «сидел» в предложении «Кот сидел на коврике». Для простоты мы предполагаем, что после некоторого метода внедрения вектор внедрения каждого слова равен:
Уведомление:для Демо Цель,Здесь мы предполагаем, что вектор Query(Q), Key(K) и Value(V) эквивалентен самому встраиванию слова.,И в настоящей модели Трансформера,Q, K и V получаются путем умножения вложений слов на разные весовые матрицы.
Предполагая, что оценка нормализована функцией Softmax (для упрощения расчета процесс расчета Softmax здесь не показан), полученный вес (предполагаемое значение) равен:
На основе весов, полученных выше, мы теперь вычисляем взвешенную сумму векторов значений (в данном случае вектор значений и вектор ключей совпадают):
Чтобы выполнить расчет:
Вектор взвешенной суммы [0,66, 0,33] представляет собой новое представление слова «сат» после учета «внимания» других слов. Этот вектор фиксирует в предложении информацию, наиболее соответствующую слову «сидел». В этом упрощенном примере слово «сат» само по себе имеет наибольший вес, что имеет смысл, поскольку в механизме самообслуживания слово, обрабатываемое в данный момент, имеет тенденцию вносить наибольший вклад в свое собственное представление.
Обратите внимание, что этот пример очень упрощен. Фактически в модели Трансформера размерность встраивания слова будет больше (например, 512 измерений), а векторы Q, K, V получаются путем умножения встраивания слова на. разные весовые матрицы. Кроме того, для дальнейшего расширения возможностей модели будет применен механизм внимания с несколькими головками.
В модели Transformer вектор взвешенной суммы, рассчитанный с помощью механизма самообслуживания, например [0,66, 0,33] в нашем примере, будет использоваться в качестве входных данных следующего слоя или следующего шага обработки. В частности, этот вектор пройдет следующие этапы:
Следовательно, на следующей итерации (т. е. на следующем уровне обработки) вектор взвешенной суммы [0,66, 0,33] пройдет серию преобразований, таких как остаточное соединение, нормализация уровня и сеть прямой связи, а затем может стать следующим уровень ввода самовнимания в механизм. Это одна из основных конструкций архитектуры Transformer. Таким образом, модель способна последовательно собирать и интегрировать информацию, а также понимать и обрабатывать текст на глубоком уровне.
Существует множество способов реализации механизма принудительного Уведомления в PyTorch.,Вот базовый пример реализации самообслуживания.с Уведомлениесила этоTransformerсетьсерединаделатьиспользовать的一种Уведомлениесиловая форма,Это позволяет Модели взвешивать совокупную информацию между различными позициями в последовательности.
Ниже приведена реализация простого класса самообслуживания:
import torch
import torch.nn as nn
import torch.nn.functional as F
class SelfAttention(nn.Module):
def __init__(self, embed_size, heads):
super(SelfAttention, self).__init__()
self.embed_size = embed_size
self.heads = heads
self.head_dim = embed_size // heads
assert (
self.head_dim * heads == embed_size
), "Embedding size needs to be divisible by heads"
self.values = nn.Linear(self.head_dim, self.head_dim, bias=False)
self.keys = nn.Linear(self.head_dim, self.head_dim, bias=False)
self.queries = nn.Linear(self.head_dim, self.head_dim, bias=False)
self.fc_out = nn.Linear(heads * self.head_dim, embed_size)
def forward(self, values, keys, query, mask):
N = query.shape[0]
value_len, key_len, query_len = values.shape[1], keys.shape[1], query.shape[1]
# Split the embedding into self.heads different pieces
values = values.reshape(N, value_len, self.heads, self.head_dim)
keys = keys.reshape(N, key_len, self.heads, self.head_dim)
queries = query.reshape(N, query_len, self.heads, self.head_dim)
values = self.values(values)
keys = self.keys(keys)
queries = self.queries(queries)
# Einsum does matrix multiplication for query*keys for each training example
# with each head
attention = torch.einsum("nqhd,nkhd->nhqk", [queries, keys])
if mask is not None:
attention = attention.masked_fill(mask == 0, float("-1e20"))
attention = F.softmax(attention / (self.embed_size ** (1/2)), dim=3)
out = torch.einsum("nhqk,nvhd->nqhd", [attention, values]).reshape(
N, query_len, self.heads * self.head_dim
)
out = self.fc_out(out)
return out
Этот код реализует простой механизм самообслуживания с несколькими головками, который включает в себя следующие шаги:
einsum
Выполнить умножение матрицы,для расчета показателя силы Уведомления между запросом и ключом.einsum
Воля Уведомление力权重应использовать于值,Получите взвешенное значение.Чтобы использовать описанный выше механизм самообслуживания, вам необходимо интегрировать его в модель нейронной сети. Вот пример использования модуля самообслуживания в простой задаче обработки последовательности:
import torch
import torch.nn as nn
# Предположим, у нас есть слой внедрения определенного размера и слой силы самоуведомления.
embed_size = 256
heads = 8
sequence_length = 100 # Введите длину последовательности
batch_size = 32
vocab_size = 10000 # Предполагаемый размер словарного запаса
class TransformerBlock(nn.Module):
def __init__(self, embed_size, heads):
super(TransformerBlock, self).__init__()
self.attention = SelfAttention(embed_size, heads)
self.norm1 = nn.LayerNorm(embed_size)
self.norm2 = nn.LayerNorm(embed_size)
self.feed_forward = nn.Sequential(
nn.Linear(embed_size, 2 * embed_size),
nn.ReLU(),
nn.Linear(2 * embed_size, embed_size)
)
def forward(self, value, key, query, mask):
attention = self.attention(value, key, query, mask)
x = self.norm1(attention + query)
forward = self.feed_forward(x)
out = self.norm2(forward + x)
return out
class Transformer(nn.Module):
def __init__(self, embed_size, heads, vocab_size, sequence_length):
super(Transformer, self).__init__()
self.word_embedding = nn.Embedding(vocab_size, embed_size)
self.position_embedding = nn.Embedding(sequence_length, embed_size)
self.layers = nn.ModuleList([TransformerBlock(embed_size, heads) for _ in range(6)])
self.fc_out = nn.Linear(embed_size, vocab_size)
def forward(self, x, mask):
N, seq_length = x.shape
positions = torch.arange(0, seq_length).expand(N, seq_length).to(x.device)
out = self.word_embedding(x) + self.position_embedding(positions)
for layer in self.layers:
out = layer(out, out, out, mask)
out = self.fc_out(out)
return out
# Создайте экземпляр модели
model = Transformer(embed_size, heads, vocab_size, sequence_length)
# Создайте случайную входную последовательность
input_seq = torch.randint(0, vocab_size, (batch_size, sequence_length))
# Создайте маску (в этом примере для None)
mask = None
# прямое распространение
output = model(input_seq, mask)
Класс TransformerBlock реализует следующий рисунок:
здесь,Transformer
类实现了一индивидуальный Включать6индивидуальныйTransformerBlock
уровень простотыTransformerМодель,TransformerBlock
Включать了с Уведомлениесиловой слой(SelfAttentionсередина的多头с Уведомление Ли Чжун Длинна здесь равна головам для 8)и前馈神经сеть。Модель的输入是一индивидуальный整数序列,Эти целые числа представляют собой индексы в словаре.,ЗатемМодельвыход последовательности одинаковой длины,где каждый элемент представляет собой соответствующий вектор размера словаря,представляет собой распределение вероятностей。
mask
Этот параметр является необязательным и может использоваться для маскировки определенных частей последовательности, что полезно, например, при работе с входными данными переменной длины или при предотвращении просмотра модели будущей информации при декодировании.
в практическом применении,Необходимо настроить структуру Модели и гиперпараметры в соответствии с конкретной задачей.,напримерразмер встраивания слова、Уведомление количества силовых головок、длина последовательностиждать,и, возможно, потребуется добавить дополнительные слои и функции.,Такие как слой встраивания слов, уровень встраивания позиции и финальный выходной слой. также,Вам также необходимо подготовить данные для обучения.,Определить функцию потерь и оптимизатор,и выполнить цикл обучения.
финальныйвыходформа(32, 100, 10000), значение поясняется ниже:
Предположим, мы используем TransformerModel для задачи генерации текста. Задача Модели основана на приведенном выше,Создайте продолжение истории. Обрабатываем 32 сюжетных сегмента одновременно (т.е. размер партии для32),Длина целевой генерации для 100 слов на сегмент,Модель может выбрать слово для каждой позиции из словаря в 10 000 слов.
выходформа(32, 100, 10000)
значение
Как использовать вывод
Теперь модели необходимо сгенерировать распределение вероятностей для следующей позиции слова.
Гипотетическое распределение вероятностей
Когда Модель рассматривает следующее слово, предполагая, что оно соответствует следующим параметрам, генерирует распределение вероятностей:
В этом Гипотетическом распределение В вероятностях «принц» получил самую высокую вероятность (0,6), что указывает на то, что согласно предсказанию Модели и текущему контексту «принц» является преемником «... there lived Наиболее вероятное слово после а».
на основе распределения вероятностей,Следующим словом для слова модель выберет «принц».,Потому что для оно имеет наибольшее значение вероятности (0,6). Это означает, что Модель распознает,в данном контексте,«Князь» — самое подходящее слово для продолжения этой истории.
Поэтому фрагмент рассказа обновлен для: «Однажды в далеком королевстве жил-был принц…».
Допустим, первый фрагмент истории в пакете в данный момент имеет текст «Однажды upon a time, in a faraway kingdom, there lived a ...”,Модель должна выбрать следующее лучшее слово. Распределение вероятностей текущего местоположения Моделидля может быть сильно смещено в сторону слова «принц».,Поэтому в качестве следующего слова для выбрано «принц». Этот процесс повторяется для каждого места и для каждого сегмента истории в пакете.,Пока не будет создан полный фрагмент истории.
финальныйвыходформа(32, 100, 10000)
точно отражает Модель在文本生становиться Задачасередина的能力,т.е. параллельная обработка нескольких фрагментов текста,для Распределение вероятностей сгенерированных слов в каждой позиции каждого сегмента,И соответственно подбирайте слова, чтобы построить связный текст. Суть этого метода заключается в том, что модель Transformer может эффективно улавливать зависимости на больших расстояниях с помощью механизма самопринуждения.,и выполнять точную генерацию текста на основе заданного контекста.