Type something to search...
深入解析:如何用小型语言模型简单明了地理解transformer架构!

深入解析:如何用小型语言模型简单明了地理解transformer架构!

介绍

在过去的几年里,我阅读了无数关于变换器网络的文章,并观看了许多视频。其中大多数都非常好,但我在理解变换器架构时遇到了困难,而其背后的主要直觉(上下文敏感嵌入)则更容易掌握。在一次演讲中,我尝试了一种不同且更有效的方法。因此,本文基于那次演讲,希望这会有效。

“我无法构建的东西,我就无法理解。” ― 理查德·费曼

我还记得,当我学习卷积神经网络时,直到我从头开始构建一个时,才完全理解它。因此,我构建了一些笔记本,您可以在Colab中运行,这些笔记本的亮点也在这里呈现,而没有杂乱,因为我觉得没有这种复杂性就无法深入理解。

如果您对机器学习上下文中的向量不清楚,请阅读这篇简短的文章,然后再继续。

一切都应该尽可能简单,但不能更简单。阿尔伯特·爱因斯坦

在我们讨论变换器并深入了解键、查询、值、自注意力和多头注意力的复杂性之前,让我们先仔细看看向量变换,这是所有神经网络(包括变换器)的核心,以及这里所做的特别之处。这将使所有其他部分都能融会贯通。

要理解变换器神经网络架构,您必须首先了解向量变换或特征映射。然后是向量化的概念(使用矩阵和GPU进行计算的并行化)。

如果我们通过谈论所有复杂的工程部分,例如曲轴、活塞、调速器、进气阀等来解释蒸汽机的工作原理,人们就会在细节中失去大局。但如果我告诉您,年轻时的詹姆斯·瓦特会看着水壶煮沸……

他看到锅盖跳起,试图用勺子压住它。他发现他无法压住锅盖,因为蒸汽不断将其推起。“蒸汽是非常强大的,”他对自己说。“我希望能让蒸汽做一些有用的工作”:

这正是我在二年级教科书中所解释的。我敢打赌,任何孩子只要心中有这个画面,就能很好地理解蒸汽机的原理。

来源 Dalle 生成:詹姆斯·瓦特受到蒸汽力量的启发

自注意力机制在变换器之前就已被发明和使用。因此,这并不是这里唯一的重点,而是正如著名标题所说的“注意力即一切”,“你所需要的一切部分”。这一点微妙且难以理解。这个故事是关于变换器神经网络的,它是一项软件工程壮举,类似于TCP/IP,而不是像反向传播算法那样的数学内容。这个故事中,注意力部分单独堆叠并转化,以创建一个适合多任务训练的可并行化神经网络。正如安德鲁·卡帕西所说:

变换器是一种宏伟的神经网络架构,因为它是一个通用可微分计算机。它同时具备:

  1. 表达能力(在前向传播中)
  2. 可优化(通过反向传播+梯度下降)
  3. 高效(高并行计算图)

@karpathyX

Take 1

让我们从一个关于旧机器的简单故事开始,支持向量机,然后逐步深入。

支持向量机或称为SVM是一个非常流行的机器学习模型,用于对结构化数据进行分类。它之所以如此受欢迎,是因为它是第一个有效使用强大向量变换概念的系统。

通过一个简单的例子,这一点将更加清晰。上面的图像显示了两个类别,红色和蓝色,在二维空间中绘制。假设它们代表某个类别的特征向量,比如叶子的某种特征,用于判断其是否健康。

那么什么是特征;假设计算机需要区分猫和狗。它需要一些数字。这可能是爪子的大小、牙齿的长度、头部与身体长度的比率或其他东西。这些代表对象特征的数字称为特征。这些特征的集合构成一个特征向量。

Image 2

来源 作者

从图中可以看出,这些特征向量在这个二维空间中没有分离边界——(分离边界是在二维空间中的一条线,在三维空间中的一个平面,以及在N维中的一个超平面)。

无法画出一条直线,使得红点在一边,蓝点在另一边。最简单和最著名的线性回归算法无法将这两个类别分开。

Image 3

来源 作者;线性回归无法分开这些类别

这就是SVM的作用所在。

核心思想是,如果我们能够将这些向量转换或投影到更高的维度空间,就有可能找到一个能够有效分隔这些类别的超平面。

以下是从二维特征空间转换到六维特征空间的简单方法。这是一个简单的函数,使用输入并将其转换为更高的维度。

def polynomial_phi(x):
    x1, x2 = x
    return [
        1.0,                  
        math.sqrt(2) * x1,    
        math.sqrt(2) * x2,    
        x1**2,                
        x2**2,                
        math.sqrt(2) * x1 * x2  
    ]

这里有一些注意事项。这些是特定的核,例如多项式(如下)或高斯核,基于特征类型,帮助更好地聚类这些类别,类似于用于转换(平滑、锐化等)图像的专业滤镜,在照片编辑应用程序中使用。

这些是多年来开发并经过实证测试的手工制作核。有关SVM的更多细节如下,如果您感兴趣。

Image 4

核映射是SVM的一种复杂数学技术,它在不实际计算的情况下找到两个高维特征映射特征向量之间的点积(而不实际计算phi(x)和phi(z)并进行矩阵乘法)。同时找到“支持向量”,这些向量构成决策边界,这是算法的核心。来源 作者 colab

简单的直觉是,将特征向量投射到更高维特征空间有助于线性可分性。相似的特征(特征向量)可以被视为“聚集在一起”。

这种将特征向量转换为更高维特征空间的过程称为特征映射

这种特征映射本质上是所有深度神经网络(包括变换器)的基础。然而,与SVM中使用的手工编码映射(如多项式特征映射或高斯核)不同,变换器中的特征映射是通过深度学习学习的。

注意力机制是一种特定的特征映射,其中有序集合或令牌序列中的每个令牌及其所占据的位置以及该集合中的其他令牌影响特征映射。

这意味着

_“我游到河岸”“我去银行”_虽然在使用的单词上看起来非常相似,但却有完全不同的注意力签名。

所以假设X是输入集 = “我游到河岸,银行是” → 训练好的变换器 → AttentionKernel(X) → 预测词汇中的下一个单词 → 可能会给出类似_“陡峭”或“潮湿”的结果_

而Y是另一个输入集 =“我去银行,银行是” → 训练好的变换器 → AttentionKernel(Y) → 预测词汇中的下一个单词 → 可能会给出类似_“开放”或“拥挤”的结果_。

训练好的变换器保持学习到的AttentionKernel,就像我们在SVM中有手工编码的多项式核一样。这就是变换器所包含的一切(请注意,大语言模型具有涌现行为,但我们现在不讨论这个)。

变换器架构的其余部分(例如,多头注意力、前馈层、残差连接和层归一化)旨在使端到端训练稳定和高效。这有助于避免爆炸或消失的梯度等陷阱,并确保网络能够从数据中学习越来越丰富的特征映射,而无需手动特征工程。

回顾

  1. 特征映射或向量变换,其中一个特征被建模为N维向量并投影到N+M维(通常)有助于将“相似”的向量或更准确地说是张量聚集在一起。
  2. 与SVM中使用手工编码核不同,这些特征映射是通过深度学习学习的。
  3. 特征映射学习基于自注意力,其中函数依赖于序列中的所有令牌,基于它们在序列中的位置及其如何影响目标(稍后将详细讨论)。

向量化

这是一个软件工程术语,最好通过一些代码来说明。假设我们有一个包含二维空间中源点和目标点的列表,我们需要找到它们之间的距离。通常所做的事情如下所示。

sources = [(1, 2), (3, 4), (5, 6)]
destinations = [(7, 8), (9, 10), (11, 12)]

import math

def calculate_distances_loop(sources, destinations):
    distances = []
    for i in range(len(sources)):
        x1, y1 = sources[i]
        x2, y2 = destinations[i]
        distance = math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
        distances.append(distance)
    return distances

distances_loop = calculate_distances_loop(sources, destinations)
print("Distances (Loop):", distances_loop)

这段代码没有问题,但对于大输入,串行运行意味着我们在慢慢处理事情。软件工程师通常会将其拆分为跨多个线程或CPU等的映射-减少形式,以在多个CPU核心或分布式机器之间并行处理。

但还有另一种方法。这在使用GPU时更为相关,因为GPU拥有数千个核心,而CPU的核心数量较少(但GPU的核心不如CPU多功能,但非常适合数学运算,如乘法、加法等)。我们将这些转换为矩阵,并使用执行矩阵乘法的库来实现并行化。

sources = [(1, 2), (3, 4), (5, 6)]
destinations = [(7, 8), (9, 10), (11, 12)]

import torch

sources = torch.tensor(sources, dtype=torch.float32)
destinations = torch.tensor(destinations, dtype=torch.float32)

def calculate_distances_torch(sources, destinations):
    diff = destinations - sources  
    squared_diff = diff ** 2
    distances = torch.sqrt(torch.sum(squared_diff, dim=1))  
    return distances

distances_torch = calculate_distances_torch(sources, destinations)
print("Distances (Torch, Matmul-based):", distances_torch)

所有神经网络本质上都是矩阵运算和向量化的。但与早期用于序列到序列映射的RNN和LSTMs或CNNs相比,变换器是通过向量化来执行注意力,从而使其在输入端实现大规模并行处理,因此可扩展,最终导致像ChatGPT这样的LLM。我们将在后面更详细地看到这一方面。

Take 2

让我们为一个非常小的语言模型构建一个更简单的注意力模型,以便更好地理解这一点。这将更具技术性,并且需要一些关于神经网络的背景知识来理解。

单头注意力

Colab 笔记本: https://colab.research.google.com/drive/1NaD3PD6VtCQ2szvMJ2-Pa7ykhQ90HoaT#scrollTo=NzdcxKmqT7qi

上面的笔记本自我描述。使用 Google 账户和访问免费 T4 GPU,您可以训练这个基本语言模型以执行基本的语言建模任务。

以下是使用十万行训练示例大致得到的结果。我们的模型非常基础,为了节省成本,我们仅在部分数据上进行训练。代码可以通过批量加载完整数据集而不是仅取前十万行等方式进行许多改进。但为了更好的可读性,保持简单。

prompt = "Bloom lived in a big garden"

Generated Text = "Bloom lived in a big garden with lots of funny. One day, Lily saw a big tree branch of funny's friends decided to play with. They were very much. They were very happy that they had lots of funny's friends were very happy that they had lots of funny's friends were very happy that they had lots of funny't always wanted to play with. They were very happy that they had lots of funny't always wanted to play with. They were very much"

关于 训练数据集 — Tiny Stories。这本身似乎是一个有趣的数据集。它来自论文 TinyStories: How Small Can Language Models Be and Still Speak Coherent English? (Ronen, Yuanzhi 2023)。它专门为像我们这样非常小的模型设计。

“在这篇论文中,我们介绍了 TinyStories,这是一个合成的短故事数据集,旨在仅包含大多数 3 到 4 岁儿童通常能够理解的单词,由 GPT-3.5 和 GPT-4 生成……我们的主要贡献是,我们展示了 TinyStories 可以用于训练和评估更小的语言模型…… 或具有更简单架构(仅一个变换器块),但仍能生成与较大和更复杂模型生成的故事相当或更优质的多样流畅一致的故事 …”

第一步:词汇和分词

给定一个输入文本序列,“猫走在”. 第一步是:

  1. 将文本转换为神经网络可以处理的数字。
  2. 这称为分词。

语言建模中的分词

基于变换器的神经网络的最终层负责预测下一个单词(或标记)

为此,模型输出一个覆盖整个词汇表的概率分布,其中每个值表示特定标记作为下一个单词的可能性。

例如,如果我们的词汇表由100个单词组成,并且给定序列中的最后两个标记是"ball""fence",模型的最后一层可能会为输入_“The Cat walked on the”_生成如下输出:

[0.001, 0.002, …, 0.001, **0.89**]

在这里,0.89对应于最可能的下一个标记("fence"),而其他值则表示替代标记的较低概率。

这就是固定词汇表和预定义分词至关重要的原因——模型只能预测其词汇表中存在的单词或子词。

创建词汇表

大多数大语言模型使用一种叫做字节对编码(Byte Pair Encoding)的算法,将单词拆分为组成的高频项以创建这个词汇表。有一个流行的库用于训练和获取这个词汇表和分词,叫做SentencePiece,这正是我们用来创建词汇表的 https://github.com/google/sentencepiece/tree/master

log.info("Training Non contextual tokeniser")
spm.SentencePieceTrainer.Train(
    input="train.txt",   
    model_prefix='llama_like',
    vocab_size=vocab_size,
    model_type='bpe',
    character_coverage=1.0,
    max_sentence_length=2048,
    treat_whitespace_as_suffix=True,
    split_digits=True               
)

sp = spm.SentencePieceProcessor()
sp.load("llama_like.model")

tokens = sp.encode(test_sentence, out_type=str)
token_ids = sp.encode(test_sentence, out_type=int)

log.info(f"Sentence: {test_sentence}")
log.info(f"Tokens:  {tokens}")
log.info(f"Token IDs: {token_ids}")

输出

test_sentence = "The Cat sat on the Fence"

09-Feb-25 08:00:43 - Training Non contextual tokeniser
09-Feb-25 08:00:56 - Sentence: The Cat sat on the Fence
09-Feb-25 08:00:56 - Tokens:  ['The▁', 'C', 'at▁', 'sat▁', 'on▁', 'the▁', 'F', 'en', 'ce▁']
09-Feb-25 08:00:56 - Token IDs: [60, 1947, 50, 1134, 56, 16, 1945, 23, 123]

第2步:嵌入

将标记映射到更高维向量的简单(学习的)特征映射。

下一步类似于支持向量机将特征投影到更高维度。当应用于文本时,这个过程被称为嵌入

在变换器中,它是通过将一个N维权重向量与标记ID相乘来完成的。是的,就是这么简单。权重值是从训练中学习得来的,使其成为一种学习的特征映射。

由于论文《注意力即一切》使用术语d_model表示N,我们也使用这个术语。

token_embedding = nn.Embedding(
    num_embeddings=vocab_size, embedding_dim=d_model)

embedded_tokens = token_embedding(trimmed_input)

上述代码使用了PyTorch nn.Embedding层。这本质上是一个线性层,但如果我们使用线性层,每个标记必须在d_model维矩阵中进行独热编码并输入到线性层中。这个nn.Embedding内部完成了这个查找,我们可以直接输入转换后的标记,跳过独热编码。如果你不理解这一点也没关系,这部分是工程实现,不影响整体理解。

该层与类似Word2Vec的区别(没有重大区别)

该层类似于我们从word2vec获得的静态嵌入;也就是说,这是非上下文的。

之前的NLP模型如word2vec使用了训练的权重向量,如此而已。然而,这有一个严重的限制,每个单词只能有一个嵌入向量,而不考虑上下文。

例如,“I ate an Apple”和“I bought an Apple Macbook”使用静态权重向量如word2vec时,单词“Apple”的嵌入值将是相同的。因此,它无法根据上下文聚类到接近Orange(其他水果)或接近(Dell,其他计算机/公司)。实际上,它将在某个上下文中错误地聚类。这是您需要记住的全部内容。

Image 5

固定或单词嵌入值的问题
来源: https://youtu.be/UPtG_38Oq8o?t=199

(Word2vec论文 “Efficient Estimation of Word Representations in Vector Space” by Tomas Mikolov et al.

第3步:自注意力

这是上下文敏感嵌入思想作为矩阵乘法和加法架构的实现。通过一系列线性变换来获得上下文敏感嵌入——注意力机制。

在这里需要注意的一件重要事情是,变换器并没有引入注意力概念;它以一种可并行化和高效的方式实现了注意力,优化了GPU和基于梯度下降的学习。

这就是键、查询和值矩阵的作用所在,事情变得复杂。理解的最佳提示是,不要将其与任何类似于键和值的映射查找进行比较。将它们视为变换的混合,仅此而已。

Image 6

Image 7

注意力即一切 https://arxiv.org/pdf/1706.03762

要理解这个公式,需要回顾一下之前的一些工作。以下这些论文可以直接或间接追溯到《注意力即一切》这篇论文。

2014:使用神经网络进行序列到序列学习 (Sutskever等)

到2014年,深度神经网络(DNN)在图像识别和作为强大的通用函数逼近器的能力得到了广泛认可。然而,主要的限制是它只能处理固定长度的输入并映射到固定长度的输出。

正是这篇论文使用神经网络进行序列到序列学习 (Sutskever等)试图使用DNN进行序列到序列学习任务,如语言翻译。

他们所做的是从可变长度的输入句子中创建一个固定大小的向量(特征向量),使用编码器。然后,他们通过使用这个固定大小的向量(v)作为一个输入,已经生成的序列作为另一个输入,以及一个学习的概率生成器(类似于LSTMs的线性层等效)将其解码回目标序列。

下面的公式不需要完全理解,但与下一篇改进它的论文进行对比是有帮助的。

Image 8

LSTM的目标是估计条件概率 p(y1, … , yT′ |x1, … , xT ),其中 (x1, … , xT ) 是输入序列,而 y1, … , yT′ 是其对应的输出序列,长度 T ′ 可能与 T 不同。LSTM通过首先获得输入序列 (x1, … , xT ) 的固定维度表示 v,由LSTM的最后一个隐藏状态给出,…

这本质上表明,通过学习的变换将所有有序的标记集投影到更高维的特征向量中,以某种方式编码了集合中的所有标记,并帮助学习可以生成目标序列的函数。

通过这种简单的学习映射投影到更高维度,有助于聚类(因为当我们谈论向量时,接下来的讨论通常是点积和余弦相似性)相似的单词序列或句子在一起;正如上面论文中的这张图片所示。

Image 9

我们模型的一个吸引特性是其将单词序列转换为固定维度向量的能力。图2可视化了一些学习到的表示。该图清楚地显示,表示对单词的顺序敏感,同时对主动语态与被动语态的替换相对不敏感。(PCA投影到2D)

**2015: 通过联合学习对齐和翻译的神经机器翻译 (Dzmitry Bahdanau等)

这是引入注意力概念的论文,尽管这篇论文并没有引起太多关注。然而,深入研究这篇论文,看看注意力概念的演变是值得的。

Image 10

Image 11

https://arxiv.org/pdf/1706.03762

这篇论文提出,不再使用之前的最先进方法固定长度向量映射可变长度句子或序列,而是提出了一种新方法学习句子或序列的哪些_部分_对输出_重要。

在这里可以看到,注意力的概念正在逐渐发展。

“在这篇论文中,我们推测,使用固定长度向量是提高该基本编码器-解码器架构性能的瓶颈,并建议通过允许模型自动(软)搜索与预测目标词相关的源句子部分来扩展这一点,而无需将这些部分明确地形成硬段落。”

…允许模型自动(软)搜索与预测目标词相关的源句子部分。

由于细粒度注意力的概念在这里得到了很好的体现,我想引用论文中的几个短语。

每当所提议的模型在翻译中生成一个单词时,它**(软)搜索源句子中最相关信息集中位置的集合。**

然后,模型基于与这些源位置相关的上下文向量和所有之前生成的目标词预测目标词。…

..它不试图将整个输入句子编码为一个固定长度的向量。相反,它将输入句子编码为一系列向量,并在解码翻译时适应性地选择这些向量的一个子集。 ..

Image 12

需要注意的是,与现有的编码器-解码器方法不同(见公式(2)),这里的概率是针对每个目标词 yi的不同上下文向量 ci。

如果您回忆起2014年论文中使用的固定长度向量 v,如下所示

Image 13

2014: 使用神经网络进行序列到序列学习 (Sutskever等)

与这里使用的 c(i) 对比,它是句子中每个单词或标记的上下文向量(如每个单词的注意力分数)

所有标记都使用算法转换为单独的特征向量 (c_i),并从训练数据中学习一个非线性搜索函数 (g),可以选择最适合目标输出的特征向量。

然后是这篇2015年的论文 基于注意力的神经机器翻译的有效方法. Minh-Thang Luong等再次使用RNN给出了点积注意力机制。

回到自注意力

自注意力的思想与上述论文类似,即使用每个输入标记计算每个其他输入标记的注意力分数,并使用缩放的点积注意力,即仅将Luong的点积注意力机制除以 d_model。这只是为了限制在梯度下降过程中梯度变

学习自注意力映射

由于注意力映射不是手动编码的核,并且需要学习,因此在每个点添加一组权重,初始随机初始化,并将其与令牌嵌入部分相乘,如下所示,使其能够通过梯度下降进行学习。

Image 14

变换器网络中单个注意力头的近似工作原理 - 来源 作者

在代码中(在自注意力类中)更容易看到这一点,因为解释起来会令人困惑,您需要盯着它看一段时间才能理解。

self.W_Q = nn.Linear(d_model, d_model, bias=False)
self.W_K = nn.Linear(d_model, d_model, bias=False)
self.W_V = nn.Linear(d_model, d_model, bias=False)

def forward(self, x):
    """
    Forward layer of SingleHeadedAttention
    """
    B, seq_len, d_model = x.shape

    Q = self.W_Q(x)
    K = self.W_K(x)
    V = self.W_V(x)

    attention = torch.matmul(Q, K.transpose(-2, -1)) / \
                torch.sqrt(torch.tensor(d_model, dtype=torch.float32))
    attention = torch.softmax(attention, dim=-1)
    score = torch.matmul(attention, V)

为什么使用这种特定的注意力机制?如果您直接跳到这一部分,请查看上面的部分,其中提供了介绍这一机制的不同论文的历史,以及从中使用的内容(仅使用缩放部分/通过模型的平方根进行除法,以减少梯度变得过大)。

请注意,像蒸汽机的离心调速器和进气阀等,有一些工程部件,如位置编码和残差连接。对于一般理解来说,这并不重要,但在实际实现中至关重要。人们常说,变换器只是基于ResNet的向量化注意力块。

ResNet基于残差连接/跳过连接的概念,这个概念非常简单。它只是将输入直接添加到输出中,为梯度流动提供了一个额外的通道,并且在另一个通道被阻塞时(梯度变得太低)提供帮助。

Image 15

来源 Ashish Vaswani 斯坦福演示

在我们的案例中,这是前向传播中的最后一行

Q = self.W_Q(x)
K = self.W_K(x)
V = self.W_V(x)

attention = torch.matmul(Q, K.transpose(-2, -1)) / \
            torch.sqrt(torch.tensor(d_model, dtype=torch.float32))
causal_mask = torch.triu(
    torch.ones((seq_len, seq_len), device=x.device), diagonal=1
).bool()
attention = attention.masked_fill(causal_mask, float('-inf'))
attention = torch.softmax(attention, dim=-1)
score = torch.matmul(attention, V)

out = x + score

第4步:通过线性层和投影到词汇维度创建更多特征

注意力分数的输出进一步投影到几个线性层,以获取额外特征,并且需要将其投影回词汇维度以进行损失计算。

prediction_layer1 = nn.Linear(d_model, vocab_size * 2)
prediction_layer2 = nn.Linear(vocab_size * 2, vocab_size)
layer_norm = nn.LayerNorm(vocab_size)

embedded_tokens = token_embedding(trimmed_input)

pos_embedded_tokens = pos_encoding(embedded_tokens)

score, _ = attention_mod(pos_embedded_tokens)

hidden1 = prediction_layer1(score)  
logits = prediction_layer2(hidden1)

logits = layer_norm(logits)

predicted_probs = torch.softmax(logits, dim=-1)

predicted_token_id = torch.argmax(predicted_probs, dim=-1)

loss = loss_function(
    logits.reshape(-1, vocab_size),
    target_labels.reshape(-1)
)
loss.backward()

前向路径中的一个重要部分。

labels = input_ids.clone()
trimmed_input = input_ids[i][:-1]
target_labels = labels[i][1:]

我们从输入中移除最后一个词,并将输入向右移动1以获取标签。

也就是说,对于输入集 [The, Cat, walked, on, the, Fence],神经网络的输入是 [The, Cat, walked, on, the,],而这些输入的目标是 [ Cat, walked, on, the, Fence]

给定 The 应该产生 Cat, 给定 The Cat, 应该产生 walked,依此类推以进行损失计算。这样就不需要像另一个训练集那样的单独标签。训练标签可以从输入中生成,使得在大型文本数据集上进行训练变得简单。

因果掩蔽

我们遗漏解释的一个较小部分是因果掩蔽部分。请注意,与论文中变换器的编码器-解码器层不同,Attention is All You Need, 我们正在建模的GPT类架构只有解码器层。这并没有太大关系。这两个模块是相似的,但在论文中,只有解码器具有因果掩蔽,而编码器没有;这可能是因为在翻译等NLP任务中,查看编码器端的整个输入序列是有意义的。如果您对此感到困惑,可以将其视为分层变换。

由于我们将其用作语言模型,它应该只能看到它之前生成的标记,即左侧的标记。由于输入ID是矩阵形式,右侧的标记成为矩阵的上三角部分(对角线之上);这部分被因果掩蔽置为零。您可以通过去掉掩蔽进行训练,看看网络的训练和输出是无效的。

Q = self.W_Q(x)
K = self.W_K(x)
V = self.W_V(x)

attention = torch.matmul(Q, K.transpose(-2, -1)) / \
            torch.sqrt(torch.tensor(d_model, dtype=torch.float32))

causal_mask = torch.triu(
    torch.ones((seq_len, seq_len), device=x.device), diagonal=1
).bool()
attention = attention.masked_fill(causal_mask, float('-inf'))
attention = torch.softmax(attention, dim=-1)
score = torch.matmul(attention, V)

多头注意力

从笔记本中可以看出,输出效果并不好。诚然,我们的训练集也非常有限。但通过使用更多的变换,我们可以改善这一点。这就是多头注意力的核心直觉。

记住这一点;K、Q和V权重一旦训练完成,就像word2vec权重一样是固定的。唯一变化的是输入序列的顺序。因此,为了通过这些学习到的过滤器创造更多的序列间交互机会,拥有一组不同的过滤器会比只有一个更好。也就是说,[K, Q, V]的值彼此不同(因为权重是随机初始化的,梯度下降训练也保持了其不同),作为不同的学习过滤器集。这就是拥有多个注意力块的概念。

为了便于理解,在笔记本中,我不是通过矩阵乘法并为头数添加额外维度来并行处理,而是顺序处理。

num_heads = 2 
num_heads = 12 
multihead_attention = nn.ModuleList()
for _ in range(num_heads):
    attention_mod = SingleHeadSelfAttention(d_model)
    multihead_attention.append(attention_mod)
prediction_layer1 = nn.Linear(d_model * num_heads, vocab_size) 
layer_norm1 = nn.LayerNorm(vocab_size)
prediction_layer2 = nn.Linear(vocab_size, vocab_size)
layer_norm2 = nn.LayerNorm(vocab_size)

多头注意力顺序处理:Colab笔记本 Multihead Attention1

请注意,这个笔记本需要更多的GPU内存,因为免费层的T4 GPU内存(15 GB)不够。因此,您需要至少Colab Pro(10美元可获得100个GPU积分)来运行此程序。

embedded_tokens = token_embedding(trimmed_input)
pos_embedded_tokens = pos_encoding(embedded_tokens)

head_outputs = []
for attention_mod in multihead_attention:
    score, _ = attention_mod(pos_embedded_tokens)
    head_outputs.append(score)

多头注意力块的输出

prompt = “Bloom lived in a big garden”

07-Feb-25 12:59:12 - 生成文本=Bloom lived in a big garden with a big smile on her face.
She was so happy and thanked her mom for helping her.
She was so happy and hugged her mom and said, “Thank you, mom. You are very kind.” But, Brownie and Brownie careful with the big smile on her face. She was so happy and thanked her mom for helping her mom and dad. She hugged her mom and said, “Thank you, Bye. You are very kind.” Browpy

对于我们非常初步的系统来说,这并不算太差。以下是您如何对多头部分进行向量化,以便可以并行处理

多头注意力并行处理: MultiHeadAttentionv2.ipynb

super().__init__()
self.W_Q = nn.Linear(d_model, d_model, bias=False)
self.W_K = nn.Linear(d_model, d_model, bias=False)
self.W_V = nn.Linear(d_model, d_model, bias=False)

Q = self.W_Q(x).reshape(B, seq_len, self.num_heads, self.head_dim).permute(0, 2, 1, 3)  
K = self.W_K(x).reshape(B, seq_len, self.num_heads, self.head_dim).permute(0, 2, 1, 3)
V = self.W_V(x).reshape(B, seq_len, self.num_heads, self.head_dim).permute(0, 2, 1, 3)

attention_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.head_dim)

Related Posts

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

结合chatgpt-o3-mini与perplexity Deep Research的3步提示:提升论文写作质量的终极指南

AI 研究报告和论文写作 合并两个系统指令以获得两个模型的最佳效果 Perplexity AI 的 Deep Research 工具提供专家级的研究报告,而 OpenAI 的 ChatGPT-o3-mini-high 擅长推理。我发现你可以将它们结合起来生成令人难以置信的论文,这些论文比任何一个模型单独撰写的都要好。你只需要将这个一次性提示复制到 **

阅读更多
让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

让 Excel 过时的 10 种 Ai 工具:实现数据分析自动化,节省手工作业时间

Non members click here作为一名软件开发人员,多年来的一个发现总是让我感到惊讶,那就是人们还在 Excel

阅读更多
使用 ChatGPT 搜索网络功能的 10 种创意方法

使用 ChatGPT 搜索网络功能的 10 种创意方法

例如,提示和输出 你知道可以使用 ChatGPT 的“搜索网络”功能来完成许多任务,而不仅仅是基本的网络搜索吗? 对于那些不知道的人,ChatGPT 新的“搜索网络”功能提供实时信息。 截至撰写此帖时,该功能仅对使用 ChatGPT 4o 和 4o-mini 的付费会员开放。 ![](https://images.weserv.nl/?url=https://cdn-im

阅读更多
掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

掌握Ai代理:解密Google革命性白皮书的10个关键问题解答

10 个常见问题解答 本文是我推出的一个名为“10 个常见问题解答”的新系列的一部分。在本系列中,我旨在通过回答关于该主题的十个最常见问题来分解复杂的概念。我的目标是使用简单的语言和相关的类比,使这些想法易于理解。 图片来自 [Solen Feyissa](https://unsplash.com/@solenfeyissa?utm_source=medium&utm_medi

阅读更多
在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和技术领域保持领先地位的 10 项必学技能 📚

在人工智能和科技这样一个动态的行业中,保持领先意味着不断提升你的技能。无论你是希望深入了解人工智能模型性能、掌握数据分析,还是希望通过人工智能转变传统领域如法律,这些课程都是你成功的捷径。以下是一个精心策划的高价值课程列表,可以助力你的职业发展,并让你始终处于创新的前沿。 1. 生成性人工智能简介课程: [生成性人工智能简介](https://genai.works

阅读更多
揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

揭开真相!深度探悉DeepSeek AI的十大误区,您被误导了吗?

在AI军备竞赛中分辨事实与虚构 DeepSeek AI真的是它所宣传的游戏规则改变者,还是仅仅聪明的营销和战略炒作?👀 虽然一些人将其视为AI效率的革命性飞跃,但另一些人则认为它的成功建立在借用(甚至窃取的)创新和可疑的做法之上。传言称,DeepSeek的首席执行官在疫情期间像囤积卫生纸一样囤积Nvidia芯片——这只是冰山一角。 从其声称的550万美元培训预算到使用Open

阅读更多
Type something to search...