В этой статье всесторонне обсуждается Transformer и производные от него модели, проводится углубленный анализ механизма самообслуживания, структур кодера и декодера, перечисляет его реализацию кодирования для более глубокого понимания и, наконец, перечисляются различные модели, основанные на Transformer, такие как BERT, GPT, и т. д. Цель статьи — подробно объяснить, как работает Transformer, и продемонстрировать его широкое влияние в области искусственного интеллекта.
Появление Transformer знаменует собой важную веху в области обработки естественного языка. Ниже будет подробно объяснено его предыстория с трех аспектов: технические проблемы, развитие механизмов самообслуживания и влияние Трансформатора на всю область.
Модель ранней последовательности,Такие как РНН и LSTM,Хотя в некоторых сценариях он работает хорошо.,Однако в реальной эксплуатации возникло множество проблем:
Сверточные нейронные сети (CNN) могут фиксировать локальные зависимости, используя несколько уровней свертки, и в некотором смысле улучшать фиксацию зависимостей на больших расстояниях. Однако фиксированный размер окна свертки CNN ограничивает диапазон зависимостей, которые он может захватывать, а обработка глобальных зависимостей недостаточно гибка.
Механизм самообслуживания решает вышеперечисленные задачи:
Внедрение этого механизма делает модель Трансформера технологическим прорывом.
Появление Transformer оказало глубокое влияние на всю сферу:
Механизм самообслуживания — это метод, позволяющий фиксировать отношения между элементами внутри последовательности. Он вычисляет сходство каждого элемента последовательности с другими элементами, тем самым фиксируя глобальные зависимости.
Например, рассмотрим расчет веса элемента:
import torch
import torch.nn.functional as F
# Query, Key
query = torch.tensor([1, 0.5])
key = torch.tensor([[1, 0], [0, 1]])
# Расчет сходства
similarity = query.matmul(key)
# распределение веса
weights = F.softmax(similarity, dim=-1)
# Выход: тензор([0,7311, 0.2689])
механизм самообслуживания Используйте рассчитанный вес для взвешенной долю, тем самым получая новое представление каждого элемента.
value = torch.tensor([[1, 2], [3, 4]])
output = weights.matmul(value)
# Выход: тензор([1.7311, 2.7311])
Основное отличие механизма самовнимания от традиционного внимания заключается в следующем:
механизм Самообслуживание способно обрабатывать целые последовательности параллельно, не ограничиваясь длиной последовательности, тем самым достигая значительной Вычислительной способности. эффективность。
В Transformer механизм самообслуживания является ключевым компонентом:
Влияние механизма самовнимания выходит далеко за рамки языковой обработки:
Хотя внимание к себе достигло замечательных успехов, пространство для исследований еще есть:
Входными данными для механизма самообслуживания является последовательность, обычно состоящая из набора векторов слов или других элементов. Эти элементы будут преобразованы в три части: запрос, ключ и значение соответственно.
import torch.nn as nn
embedding_dim = 64
query_layer = nn.Linear(embedding_dim, embedding_dim)
key_layer = nn.Linear(embedding_dim, embedding_dim)
value_layer = nn.Linear(embedding_dim, embedding_dim)
Путем вычисления скалярного произведения запроса и ключа получается матрица сходства между каждым элементом.
import torch
embedding_dim = 64
# Предположим, что последовательность содержит три элемента
sequence = torch.rand(3, embedding_dim)
query = query_layer(sequence)
key = key_layer(sequence)
value = value_layer(sequence)
def similarity(query, key):
return torch.matmul(query, key.transpose(-2, -1)) / (embedding_dim ** 0.5)
Нормализуйте матрицу сходства в веса.
def compute_weights(similarity_matrix):
return torch.nn.functional.softmax(similarity_matrix, dim=-1)
Используйте матрицу весов, чтобы выполнить взвешенную длину для значения, чтобы получить выходные данные.
def weighted_sum(weights, value):
return torch.matmul(weights, value)
В практических приложениях многоголовое внимание обычно используется для последовательного захвата многогранной информации.
class MultiHeadAttention(nn.Module):
def __init__(self, embedding_dim, num_heads):
super(MultiHeadAttention, self).__init__()
self.num_heads = num_heads
self.head_dim = embedding_dim // num_heads
self.query_layer = nn.Linear(embedding_dim, embedding_dim)
self.key_layer = nn.Linear(embedding_dim, embedding_dim)
self.value_layer = nn.Linear(embedding_dim, embedding_dim)
self.fc_out = nn.Linear(embedding_dim, embedding_dim)
def forward(self, query, key, value):
N = query.shape[0]
query_len, key_len, value_len = query.shape[1], key.shape[1], value.shape[1]
# Разделить несколько заголовков
queries = self.query_layer(query).view(N, query_len, self.num_heads, self.head_dim)
keys = self.key_layer(key).view(N, key_len, self.num_heads, self.head_dim)
values = self.value_layer(value).view(N, value_len, self.num_heads, self.head_dim)
# Расчет сходства
similarity_matrix = torch.einsum("nqhd,nkhd->nhqk", [queries, keys]) / (self.head_dim ** 0.5)
# распределение веса
weights = torch.nn.functional.softmax(similarity_matrix, dim=-1)
# взвешенная сумма
attention = torch.einsum("nhql,nlhd->nqhd", [weights, values])
# Объединение выходов нескольких головок
attention = attention.permute(0, 2, 1, 3).contiguous().view(N, query_len, embedding_dim)
# Интеграция вывода через линейные слои
output = self.fc_out(attention)
return output
Кодер — один из основных компонентов Transformer. Его основная задача — понимать и обрабатывать входные данные. Кодировщик создает мощный инструмент сопоставления последовательностей, комбинируя механизмы самообслуживания, нейронные сети прямого распространения, уровни нормализации и остаточные связи. Механизм самообслуживания позволяет модели фиксировать сложные взаимосвязи внутри последовательности, а сеть прямой связи обеспечивает возможности нелинейных вычислений. Слои нормализации и остаточные связи помогают стабилизировать процесс обучения. Ниже приведены различные компоненты кодера и их подробные описания.
Первая часть кодера — это уровень самообслуживания. Как упоминалось ранее, механизм самообслуживания позволяет модели обращать внимание на все позиции во входной последовательности и кодировать каждую позицию на основе этой информации.
class SelfAttentionLayer(nn.Module):
def __init__(self, embedding_dim, num_heads):
super(SelfAttentionLayer, self).__init__()
self.multi_head_attention = MultiHeadAttention(embedding_dim, num_heads)
def forward(self, x):
return self.multi_head_attention(x, x, x)
После уровня внимания кодер включает в себя нейронную сеть прямой связи (FFNN). Эта сеть состоит из двух линейных слоев и функции активации.
class FeedForwardLayer(nn.Module):
def __init__(self, embedding_dim, ff_dim):
super(FeedForwardLayer, self).__init__()
self.fc1 = nn.Linear(embedding_dim, ff_dim)
self.fc2 = nn.Linear(ff_dim, embedding_dim)
self.relu = nn.ReLU()
def forward(self, x):
return self.fc2(self.relu(self.fc1(x)))
Чтобы стабилизировать обучение и ускорить сходимость, за каждым слоем самообслуживания и слоем прямой связи имеется слой нормализации (Layer Normalization).
layer_norm = nn.LayerNorm(embedding_dim)
Трансформатор также использует остаточные соединения, так что выходные данные каждого слоя добавляются к входным. Это помогает предотвратить исчезновение и взрыв градиентов.
output = layer_norm(self_attention(x) + x)
output = layer_norm(feed_forward(output) + output)
Конечный кодер состоит из N таких слоев.
class Encoder(nn.Module):
def __init__(self, num_layers, embedding_dim, num_heads, ff_dim):
super(Encoder, self).__init__()
self.layers = nn.ModuleList([
nn.Sequential(
SelfAttentionLayer(embedding_dim, num_heads),
nn.LayerNorm(embedding_dim),
FeedForwardLayer(embedding_dim, ff_dim),
nn.LayerNorm(embedding_dim)
)
for _ in range(num_layers)
])
def forward(self, x):
for layer in self.layers:
x = layer(x)
return x
Декодер отвечает за генерацию целевой последовательности на основе выходных данных кодера и ранее сгенерированной частичной выходной последовательности. Декодер имеет структуру, аналогичную кодировщику, но добавляет замаскированный уровень самообслуживания и уровень внимания кодер-декодер для генерации целевых последовательностей. Маска гарантирует, что декодер использует только предыдущие позиции для генерации выходных данных для каждой позиции. Уровень внимания кодер-декодер позволяет декодеру использовать выходные данные кодера. Благодаря такой структуре декодер способен генерировать целевые последовательности, соответствующие контекстной и исходной информации о последовательностях, обеспечивая мощное решение для многих сложных задач генерации последовательностей. Ниже приведены основные компоненты декодера и принципы их работы.
Первая часть декодера — это замаскированный уровень самообслуживания. Этот слой аналогичен слою самообслуживания в кодировщике, но добавляет маску, предотвращающую фокусировку местоположений на местоположениях, находящихся за ними.
def mask_future_positions(size):
mask = (torch.triu(torch.ones(size, size)) == 1).transpose(0, 1)
return mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))
mask = mask_future_positions(sequence_length)
Декодер также включает в себя уровень внимания кодер-декодер, который позволяет декодеру сосредоточиться на выходе кодера.
class EncoderDecoderAttention(nn.Module):
def __init__(self, embedding_dim, num_heads):
super(EncoderDecoderAttention, self).__init__()
self.multi_head_attention = MultiHeadAttention(embedding_dim, num_heads)
def forward(self, queries, keys, values):
return self.multi_head_attention(queries, keys, values)
Декодер также имеет нейронную сеть прямого распространения с той же структурой, что и нейронная сеть прямого распространения в кодере.
Эти компоненты такие же, как и в кодере, и используются после каждого подуровня.
Декодер состоит из уровня самообслуживания, уровня внимания кодер-декодер, нейронной сети прямого распространения, слоя нормализации и остаточной связи и обычно включает N таких слоев.
class Decoder(nn.Module):
def __init__(self, num_layers, embedding_dim, num_heads, ff_dim):
super(Decoder, self).__init__()
self.layers = nn.ModuleList([
nn.Sequential(
SelfAttentionLayer(embedding_dim, num_heads, mask=mask),
nn.LayerNorm(embedding_dim),
EncoderDecoderAttention(embedding_dim, num_heads),
nn.LayerNorm(embedding_dim),
FeedForwardLayer(embedding_dim, ff_dim),
nn.LayerNorm(embedding_dim)
)
for _ in range(num_layers)
])
def forward(self, x, encoder_output):
for layer in self.layers:
x = layer(x, encoder_output)
return x
Модели на основе трансформаторов продолжают появляться, предоставляя мощные инструменты для различных задач НЛП и других задач обработки последовательностей. От генерации текста до понимания контекста — эти модели имеют различные преимущества и характеристики, и вместе они способствуют быстрому развитию области обработки естественного языка. Общим для этих моделей является то, что все они используют основные концепции оригинального Трансформера и на их основе вносят различные инновации и улучшения. В будущем мы можем ожидать, что все больше моделей на основе трансформаторов будут продолжать появляться, что еще больше расширит сферу их применения и влияние.
BERT — это модель на основе кодировщика Transformer для создания контекстно-зависимых вложений слов. В отличие от традиционных методов встраивания слов, BERT может понимать конкретное значение слов в предложениях.
В отличие от BERT, GPT ориентирован на генерацию текста с использованием декодера Transformer. GPT предварительно обучен как языковая модель и может быть настроен для различных задач генерации.
Transformer-XL решает проблему ограничения длины контекста исходной модели Transformer, вводя механизм многократного использования памяти.
Модель T5 рассматривает все задачи НЛП как задачи преобразования текста в текст. Эта унифицированная структура позволяет очень легко переключаться между различными задачами.
XLNet — это общая авторегрессионная модель предварительного обучения, сочетающая в себе двунаправленные возможности BERT и авторегрессионные преимущества GPT.
DistilBERT — это облегченная версия модели BERT, которая сохраняет большую часть производительности, но размер модели значительно уменьшен.
ALBERT — это еще одна оптимизация BERT, которая уменьшает количество параметров, одновременно повышая скорость обучения и производительность модели.
С момента своего появления Transformer глубоко изменил облик обработки естественного языка и многих других задач обработки последовательностей. Благодаря своему уникальному механизму самообслуживания Transformer преодолевает многие ограничения предыдущих моделей и обеспечивает более высокий уровень распараллеливания и более гибкий захват зависимостей.
В этой статье мы подробно рассмотрели следующие аспекты Transformer:
Transformer не только продвигает исследования и приложения в области обработки естественного языка, но и демонстрирует свой потенциал в других областях, таких как биоинформатика, анализ изображений и т. д. Многие современные модели основаны на Transformer, используя его гибкую и эффективную структуру для решения ранее трудно решаемых проблем.
В будущем мы можем ожидать, что Transformer и его производные модели продолжат играть важную роль в более широком спектре областей, постоянно внедряя инновации и способствуя развитию области искусственного интеллекта.