通过小型语言模型尽可能简单地解释 Transformer
介绍
在过去的几年里,我阅读了无数关于 Transformer 网络的文章,观看了许多视频。其中大部分都非常好,但我很难理解 Transformer 架构,而其背后的主要直觉(上下文敏感嵌入)则更容易掌握。在做演讲时,我尝试了一种不同且更有效的方法。因此,本文基于那次演讲,希望这会很有效。
“What I cannot build. I do not understand.” ― Richard Feynman
我还记得,当我学习卷积神经网络时,直到我从头开始构建一个,我才完全理解它。因此,我创建了一些笔记本,您可以在 Colab 中运行它们,其中的重点也在这里毫无杂乱地呈现,因为我觉得如果没有这种复杂性,就不可能深入理解。
如果您对 ML 环境中的向量 (Vector) 不清楚,请先阅读这篇简短的文章
一切都应该尽可能简单,但不能过于简单。阿尔伯特·爱因斯坦
在我们讨论 Transformers 并深入探讨键、查询、值、自注意力和多头注意力的复杂性(每个人都首先会涉及这些复杂性)之前,让我们仔细看看向量转换,它是包括 Transformers 在内的所有神经网络的核心,以及这里做了什么特别的事情。这将使所有其他部分都各就各位。
要理解 Transformer 神经网络架构,你必须首先了解向量变换或特征映射。然后了解向量化的概念(使用矩阵和 GPU 进行并行计算)。
如果我们通过谈论曲轴、活塞、调速器、进气阀等所有复杂的工程部件来解释蒸汽机的工作原理,人们就会忽略零件的整体情况。但如果我告诉你,小时候,詹姆斯·瓦特常常看着水壶烧开……
他看到盖子跳了起来,就试图用勺子把它按住。他发现自己无法把盖子按住,因为蒸汽一直把它往上推。“蒸汽很强大,”他自言自语道。“我想让蒸汽做一些有用的工作”:
这和我二年级课本上的解释完全一样。我敢打赌,只要有这张图片在脑海里,任何孩子都能很好地理解蒸汽机的原理。
自注意力机制是在 Transformer 出现之前发明和使用的。所以这不是这里唯一的重点,而是正如著名的标题所说“注意力就是你所需要的一切”,“你所需要的一切”。这是微妙的,很难首先得到。这个故事是关于 Transformer 神经网络的,它是一种像 TCP/IP 这样的软件工程壮举,而不是像反向传播算法这样的数学。这是一个仅将注意力部分堆叠和转换以创建可并行化的神经网络的故事,该神经网络可用于训练许多任务。正如 Andrew Karpathy 所说:
Transformer 是一个很棒的神经网络架构,因为它是一个通用的可微分计算机。它同时具有以下特点:1)富有表现力(在前向传递中)2)可优化(通过反向传播+梯度下降)3)高效(高并行计算图)X
第一部分
让我们从一个关于老机器,支持向量机的简单故事开始,然后我们再逐步深入。
支持向量机(SVM)是一种非常流行的机器学习模型,用于对结构化数据进行分类。它之所以如此受欢迎,是因为它是第一个有效利用强大的向量变换概念的系统。
从一个简单的例子来看,这一点会更清楚。上图显示了在二维空间中绘制的两个类,分别为红色和蓝色。假设它们代表某个类的特征向量,比如说叶子的一个特征,用于分类它是否健康。
那么什么是特征呢?假设计算机需要区分猫和狗。因此它需要一些数字。这些数字可能是爪子的大小、牙齿的长度、头部与身体长度的比例或其他东西。这些代表主体特征的数字称为特征。一组这些数字组合在一起构成一个特征向量。
从图中可以看出,这些特征向量在这个二维空间中没有分离边界——(分离边界在二维空间中是一条线,在三维空间中是一个平面,在 N 维中是一个超平面 )。
我们不能画一条直线,一边是红点,一边是蓝点。最简单、最著名的线性回归算法无法区分这两个类别。
这时 SVM 就可以发挥作用了。
核心思想是,如果我们可以将这些向量转换或投影到更高维的空间,就有可能找到可以有效分离这些类别的超平面。
这是一个从 2D 特征空间转换为 6D 特征空间的简单方法。这是一个使用输入并将其转换为更高维度的简单函数。
#Transforming from 2D to 6D directly
# -------------------------
# 1) Define the polynomial feature map φ(x)
# for a 2D point x = (x1, x2)
# -------------------------
def polynomial_phi(x):x1, x2 = xreturn [1.0, # constant termmath.sqrt(2) * x1, # √2 * x1math.sqrt(2) * x2, # √2 * x2x1**2, # x1^2x2**2, # x2^2math.sqrt(2) * x1 * x2 # √2 * x1 x2]
这里有一些注意事项。这些是使用的特定核,如多项式(如下)或高斯,它们有助于根据特征类型更好地对类别进行聚类,类似于照片编辑应用程序中用于转换(平滑、锐化等)图像的专用过滤器。
这些是多年来开发并经过实证测试的手工内核。如果您有兴趣,下面有关于 SVM 的更多详细信息。
核映射是 SVM 的一种复杂数学技术,它可以找到两个高维特征映射特征向量之间的点积,而无需实际计算(无需实际计算 phi(x) 和 phi(z) 并进行矩阵乘法)。还可以找到排列决策边界的“支持向量”,这是算法的核心。
简单的直觉是,将特征向量投射到更高维的特征空间有助于实现线性可分性。相似的特征(特征向量)可以被认为是“聚集在一起的”。
将特征向量转换为更高维特征空间的过程称为特征映射。
这种特征映射本质上是所有深度神经网络(包括 Transformer)的基础。然而,Transformer中的特征映射不是通过手工编码的映射(如 SVM 中使用的多项式特征映射或高斯核),而是通过深度学习来学习的。
注意力机制是一种特定的特征映射,其中有序集合或标记序列中的每个标记及其所占据的位置以及该集合内的其他标记都会影响特征映射。
这意味着
“我游到了银行”和“我去了银行”虽然在用词上看起来非常相似,但注意力特征却完全不同。
因此假设 X 是输入集 = “我游到岸边,岸边是 ” → 训练好的 Transformer → AttentionKernel(X) → 预测词汇表中的下一个单词 → 可能会给出类似“陡峭”或“湿”的答案
而 Y 是另一个输入集 = “我去了银行,银行是” → 训练 Transformer → AttentionKernel(Y) → 预测词汇表中的下一个单词 → 可能会给出类似“开放”或“拥挤”之类的结果。
经过训练的 Transformer 拥有学习到的 AttentionKernel,就像我们在 SVM 中手动编码的多项式核一样。这就是 Transformer 所拥有的全部(请注意,大型语言模型具有突发行为,但我们现在不讨论这一点)
Transformer 架构的其余部分(例如多头注意力、前馈层、残差连接和层归一化)旨在使端到端训练稳定且高效。这有助于避免梯度爆炸或梯度消失等陷阱,并确保网络无需手动特征工程即可从数据中学习越来越丰富的特征映射。
回顾
- 特征映射或向量变换,其中将特征建模为 N 维向量并投影到 N+M 维(通常)有助于将“相似”向量或更准确地张量聚类在一起。
- 这些特征映射不是像 SVM 那样使用手工编码的核,而是通过深度学习来学习
- 特征映射学习基于自我注意力,其中函数依赖于序列中的所有标记,这些标记基于序列中的位置产生影响,以及它如何影响目标(稍后会详细介绍)
向量化
# some sample source and destination
sources = [(1, 2), (3, 4), (5, 6)]
destinations = [(7, 8), (9, 10), (11, 12)]# A simple function which loops over and does te calculation
import mathdef 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 distancesdistances_loop = calculate_distances_loop(sources, destinations)
print("Distances (Loop):", distances_loop)
代码本身没有问题,但对于大量输入,以串行方式运行意味着我们处理速度很慢。软件工程师通常会将其以 map-reduce 形式拆分到多个线程或 CPU 等上,以便在多个 CPU 核心或分布式机器上并行化。
但还有另一种方法。这在我们使用的是 GPU 的情况下更为重要,因为 GPU 比 CPU 有数千个核心(但核心不像 CPU 那么通用,但非常适合乘法、加法等数学运算)。我们将它们转换为矩阵,并使用执行矩阵乘法的库来并行化。
# 将这些转换为数组/矩阵
sources = [( 1 , 2 ), ( 3 , 4 ), ( 5 , 6 )]
destinations = [( 7 , 8 ), ( 9 , 10 ), ( 11 , 12 )] sources = torch.tensor(sources, dtype=torch.float32)
destinations = torch.tensor(destinations, dtype=torch.float32) import torch def calculate_distances_torch ( sources, destinations ): diff = destinations - sources # 计算差异矩阵squared_diff = diff ** 2 # 逐元素平方distances = torch.sqrt(torch. sum (squared_diff, dim= 1 )) # 沿行求和并求平方返回距离distances_torch = calculate_distances_torch(sources, destinations)
print ( "Distances (Torch,基于 Matmul 的):” , distances_torch)
所有神经网络本质上都是矩阵运算和矢量化的。但与 RNN 和 LSTM 甚至早期用于序列到序列映射的 CNN 相比,Transformers 是通过矢量化来实现 Attention 的,这使得它(在输入端)大规模并行,因此可扩展,最终导致像 ChatGPT 这样的 LLM。我们稍后会更详细地介绍这方面。
第二部分
让我们为一个非常小的语言模型构建一个更简单的注意力模型,以便更好地理解这一点。这将更具技术性,需要一些神经网络背景才能理解。
单头注意力机制
Colab Notebook: https://colab.research.google.com/drive/1NaD3PD6VtCQ2szvMJ2-Pa7ykhQ90HoaT#scrollTo=NzdcxKmqT7qi
上面给出的笔记本是自描述的。有了 Google 帐户并访问免费 T4 GPU,您就可以训练这个基本语言模型来执行基本的语言建模任务。
以下是使用训练示例中的十万行代码大致可获得的结果。我们的模型非常简陋,为了节省成本,我们只对一小部分数据进行训练。代码可以通过多种方式进行改进,例如通过整个数据集批量加载,而不是只取前十万行代码等。但为了提高可读性,请保持代码简单。
# Test the generation function
prompt = "Bloom lived in a big garden"
#Output
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:语言模型可以有多小,仍然可以说连贯的英语? (Ronen,Yuanzhi 2023)。它是专门为像我们这样的非常小的模型设计的。
在本文中,我们介绍了 TinyStories,这是一个由 GPT-3.5 和 GPT-4 生成的合成短篇故事数据集,旨在仅包含大多数 3 至4 岁儿童通常会理解的单词……我们的主要贡献是,我们展示了 TinyStories可用于训练和评估更小的小型语言模型……或者具有更简单的架构(只有一个转换器块),但仍然可以生成一组多样化的流畅且一致的故事,这些故事可与更大、更复杂的模型生成的故事相媲美或更胜一筹……
步骤 1:词汇和标记
给定一个文本输入序列,“The Cat walking on the”。第一步是
- 将文本转换为神经网络可以处理的数字。
- 这称为标记化(Tokenization)
语言建模中的标记化(Tokenization)
基于 Transformer 的语言建模神经网络的最后一层负责预测下一个单词(或 token)。
为了实现这一点,模型输出整个词汇表的概率分布,其中每个值代表特定标记成为下一个单词的可能性。
例如,如果我们的词汇表包含100 个单词,并且给定序列中的最后两个标记是"ball"和,则模型的最后一层可能会为输入“The Cat walking on the”"fence"产生如下所示的输出
[0.001,0.002,…,0.001, 0.89 ]
这里,0.89对应于最可能的下一个标记(“fence”),而其他值表示替代标记的较低概率。
这就是为什么固定词汇表和预定义标记化至关重要——模型只能预测其词汇表中存在的单词或子词。
创建词汇表
大多数 LLM 使用一种称为字节对编码(BPE)的算法,其中将单词拆分为组成高频项以创建此词汇表。有一个流行的库可用于训练和获取此词汇表和标记化,称为 SentencePiece,这就是我们使用https://github.com/google/sentencepiece/tree/master来创建词汇表的方法。
log.info("Training Non contextual tokeniser")
spm.SentencePieceTrainer.Train(input="train.txt", # our training datamodel_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 # This forces splitting "123" -> "1", "2", "3"
)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 - 训练非上下文标记器
09 -Feb -25 08 : 00 : 56 - 句子:The Cat sat on the Fence
09 -Feb -25 08 : 00 : 56 -标记:[ 'The','C','at',' sat ' , ' on ' , ' the ' ,' F ',' en ',' ce ' ]
09 -Feb -25 08 : 00 : 56 -标记ID : [ 60,1947,50,1134,56,16,1945,23,123 ]
第 2 步:嵌入(Embedding)
将标记的简单(学习到的)特征映射到更高维向量。
下一步类似于 SVM 将特征投影到更高维度。当应用于文本时,此过程称为嵌入。
在 Transformers 中,这是通过将 N 维权重向量与 token id 相乘来实现的。是的,就是这么简单。权重值是从训练中学习到的,使其成为学习到的特征映射。
由于论文《Attention is All You Need》使用术语d_model表示 N,因此我们也使用它。
# 定义一个线性层
token_embedding = nn.Embedding( num_embeddings=vocab_size, embedding_dim=d_model)
# 在前向传递中使用该层
embedded_tokens = token_embedding(trimmed_input)
上面的代码使用了 PyTroch nn.Embedding 层。这本质上是一个线性层,但如果我们使用线性层,则每个标记都必须在 d_model dim 矩阵中进行独热编码并输入到线性层中。这个 nn.Embedding 在内部执行此查找,我们可以跳过独热编码直接输入转换后的标记。如果你不理解这一点,没关系,这是一个工程部分,对整体理解并不重要
该层与类似的Word2Vec的区别(没有太大区别)
这一层类似于我们从 word2vec 获得的静态嵌入;也就是说,它是非上下文的。
以前的 NLP 模型(如 word2vec)只使用经过训练的权重向量。然而,这有一个严重的限制,每个单词只能有一个嵌入向量,与上下文无关。
例如,“我吃了一个苹果”和“我买了一台苹果 Macbook”,使用 word2vec 等静态权重向量时,“苹果”一词的嵌入值将相同。因此,根据上下文,它不能聚类在橙子(其他水果)附近或(戴尔、其他计算机/公司)附近。实际上,它会在某个上下文中被错误地聚类。这就是您需要记住的全部内容。
步骤 3:自我注意力
这是将上下文嵌入思想实现为矩阵乘法和加法架构的地方。进行一系列线性变换以获得上下文嵌入 - 注意力机制。
这里要注意的一件重要事情是,Transformers 并没有引入 Attention 概念;它以一种可并行、高效的方式实现了 Attention,这种方式针对 GPU 和基于梯度下降的学习进行了优化。
这就是 Key、Query 和 Value 矩阵发挥作用的地方,事情变得复杂了。最好的理解技巧是不要将其与任何类比进行比较,例如键和值的映射查找等。将它们视为转换的混合,仅此而已。
要理解这个公式,我们需要回顾一下过去,看看一些以前的研究成果。以下这些论文可以直接或间接地追溯到《Attention is all you need 》这篇论文。
2014: Sequence to Sequence Learning with Neural Networks (Sutskever et al)
到 2014 年,深度神经网络 (DNN) 在图像识别和作为强大的通用函数逼近器方面的强大功能得到了广泛认可。然而,主要限制在于它过去仅适用于固定长度的输入并映射到固定长度的输出。
正是这篇论文《Sequence to Sequence Learning with Neural Networks》( Sutskever 等人)尝试使用 DNN 进行语言翻译等序列到序列的学习任务。
他们的做法是使用编码器从可变长度的输入句子中创建一个固定大小的向量(特征向量) 。然后,他们将其解码回目标序列,方法是使用这个固定大小的向量 (v)作为一个输入,将已经生成的序列作为另一个输入,并使用学习的概率生成器(类似于 LSTM 的线性层等效项)将其索引到固定长度的词汇表中。
下面的公式不需要完全理解,但将其与下一篇改进它的论文进行对比是有帮助的
LSTM 的目标是估计条件概率 p(y1, . . . , yT′ |x1, . . . , xT ),其中 (x1, . . . , xT ) 是输入序列,y1, . . . , yT′ 是其对应的输出序列,其长度 T ′ 可能与 T 不同。LSTM 通过首先获得由 LSTM 的最后一个隐藏状态给出的输入序列 (x1, . . . , xT ) 的固定维度表示 v来计算该条件概率,…
这实质上表明,使用学习到的转换将所有有序的标记集投影到更高维的特征向量,以一种方式对集合中的所有标记进行编码,并有助于学习可以生成目标序列的函数。
使用这种简单的学习映射投影到更高的维度有助于将相似的单词序列或句子聚类(因为当我们谈论向量时,接下来谈论的通常是点积和余弦相似度);如下面来自上述论文的图片所示。
我们的模型的一个吸引人的特征是它能够将单词序列转换为固定维度的向量。图 2 可视化了一些学习到的表示。该图清楚地表明,这些表示对单词的顺序很敏感,但对用被动语态替换主动语态相当不敏感。(PCA 投影到 2D)
这是一篇引入了注意力概念的论文,尽管它并没有引起太多关注。然而,值得深入研究一下这篇论文,看看注意力概念的演变。
本文提出的是,用一种新方法来学习句子或序列的哪些部分对输出很重要,而不是之前最先进的将固定长度向量映射到可变长度的句子或序列的方法。
我们可以从这里看到注意力的概念正在慢慢发展
在本文中,我们推测使用固定长度向量是提高这种基本编码器-解码器架构性能的瓶颈,并建议通过允许模型自动(软)搜索源句子中与预测目标词相关的部分来扩展这一点,而不必明确地将这些部分形成为硬段。
…允许模型自动(软)搜索源句子中与预测目标词相关的部分。
由于这里很好地捕捉到了粒状注意力的概念,我想从论文中引用更多短语。
每次所提出的模型在翻译中生成一个单词时,它都会(软)搜索源句子中集中最相关信息的一组位置。
然后,模型根据与这些源位置相关的上下文向量和所有先前生成的目标词来预测目标词。…
… 它不会尝试将整个输入句子编码为单个固定长度的向量。相反,它将输入句子编码为一系列向量,并在解码翻译时自适应地选择这些向量的子集。…
需要注意的是,与现有的编码器-解码器方法(见公式 (2))不同,这里的概率取决于每个目标词 yi的不同上下文向量 ci
如果你还记得 2014 年论文中的公式,其中固定长度向量 v用于 下面给出的整个句子表示
与这里使用的 c(i)相比,它是句子中每个单词或标记的上下文向量(就像每个单词的注意力分数)
所有标记都使用算法转换为单独的特征向量(c_i),并从训练数据中学习非线性搜索函数(g),该函数可以为目标输出选择最合适的特征向量。
然后是 2015 年的一篇论文《Effective Approaches to attention-based neural machine translation》。Minh-Thang Luong 等人使用 RNN 再次给出了点积注意力机制
回到自我注意力
自注意力的理念与上述论文类似,即使用每个输入标记来计算其他每个输入标记的注意力分数,并使用缩放点积注意力,即 Luong 的 d_model 点积注意力机制。这是为了限制梯度下降过程中梯度变得过大,仅此而已。
但真正的突破是将注意力作为矩阵乘法。以下是Ashish Vaswani(主要作者之一)对此进行描述的视频摘录。
Transformer 是第一个通过简单线性层实现这一目标的神经网络,它不像之前的所有工作那样使用 RNN 或 CNN,这使得它能够通过矩阵乘法来实现注意力,这意味着并行(使用 GPU),这是一个巨大的瓶颈改进,并导致将训练扩展到我们现在所知道和使用的 LLM。
另一个突破则更加微妙。它主要只使用这种机制,并去掉之前工作中的 LSTM、CNN 等所有内容。
我们问的问题是——为什么不使用注意力机制来进行表征?” Ashish Vaswani
“Attention is all you need ?”注意力加权表示可以表示整个序列,因此可以用于下游的进一步处理,例如生成下一个标记(具有因果注意力掩码的生成模型),而无需先前专门的网络(例如 RNN-LSTM 或 CNN)进行序列到序列的处理。
这是一个革命性的飞跃,从当时最先进的更复杂的网络(如 LSTM)或基于 CNN 的ByteNets,到仅使用堆叠的注意力块进行序列到序列的处理。
学习自注意力映射
由于注意力映射不是手工编码的内核,而且必须进行学习,因此在每个点添加一组权重,并最初随机初始化,然后像下面这样将这些权重与标记嵌入部分相乘,使其适合通过梯度下降进行学习。
在代码中(在自我注意类中)看到这一点更容易,因为解释这一点很令人困惑,你需要盯着它看很长时间才能明白。
# intialist three random Weight matrices Q,K,Vself.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)# and use this in the forward layerdef forward(self, x):"""Forward lyer of SingleHeadedAttention"""B, seq_len, d_model = x.shape # B is batch size , seq_len is the length of the sequence , and d_model is the embedding size (512) # torch.Size([1, 999, 512])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)
为什么要使用这种特殊的注意力机制?如果你直接跳到本节,请参阅上面的部分,其中介绍了介绍该机制以及使用该机制的不同论文的历史记录(仅使用模型的缩放部分/除以平方根来减少梯度过大)。
请注意,与蒸汽机的离心调速器和进气阀等类似,还有一些工程部件,如位置编码和残差连接。这对于一般理解来说并不重要,但在实际实施中却至关重要。人们常说,Transformer 只是 ResNet 上的矢量化注意力块。
ResNet 基于残差连接/跳过连接的概念,非常简单。它只是将输入直接添加到输出,为梯度流动增加一个管道,并在另一管道被阻塞(梯度变得太低)时提供帮助。
在我们的例子中,这是前向传递的最后一行
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)# Add residual connection out = x + score # without this the model output is not good
步骤 4:通过线性层创建更多特征并投影到词汇维度
将注意力得分的输出进一步投影到几个线性层,以获得额外的特征,并有必要将其投影回词汇维度以进行损失计算。
# intialising the linear layers
prediction_layer1 = nn.Linear(d_model, vocab_size*2)
prediction_layer2 = nn.Linear(vocab_size*2, vocab_size)
layer_norm = nn.LayerNorm(vocab_size) # kast dimension is the vocab size# and using them in the feed forwad pathembedded_tokens = token_embedding(trimmed_input)# shape remains (batch_size, seq_len, d_model)pos_embedded_tokens = pos_encoding(embedded_tokens)# get attention and scorescore,_ = attention_mod(pos_embedded_tokens)# Predict the next wordhidden1 = prediction_layer1(score) # Project to vocabulary sizelogits = prediction_layer2(hidden1) # through few linear layers# add layer normlogits = layer_norm(logits)# the last dimension of the output tensor represents the vocabulary size or the number of classes.# Therefore, applying softmax along the last dimension (dim=-1)predicted_probs = torch.softmax(logits, dim=-1) # Get probabilities# Get the predicted word (token ID)predicted_token_id = torch.argmax(predicted_probs, dim=-1)# Calculate the loss # crossentropy already does softmax inside# If your input has 49 tokens, you predict 49 next tokens.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, walk, on, the, Fence],神经网络的输入是[The, Cat, walk, on, the,],这些输入的目标是[ Cat, walk, on, the, Fence]
给定The ,它应该生成Cat;给定The Cat,它应该生成walking,以此类推,以此类推,进行损失计算。这样就不需要像另一个训练集那样单独添加标签了。训练标签可以从输入中生成,从而可以轻松地在大型文本数据集上进行训练。
因果掩码
我们遗漏了解释的一个较小的部分是因果掩蔽部分。请注意,与论文《Attention is All You Need》中 Transformer 的编码器-解码器层不同,我们正在对只有解码器层的类似 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))# Apply the mask to the attention scores# why is this needed; basically it allows the model from attending to only tokens in the past, that is in the left side of# the current token, when you mulitply by V# the left side becomes the lower triangular matrix; and right side the future tokens are the upper triangular matrix# We build an upper-triangular mask (set to -inf) that zeros out attention (the next softmmax layer will set it to zero)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] 值彼此不同(因为权重是随机初始化的,并且通过梯度下降进行训练也会使其保持不同),充当不同的学习过滤器集。这就是拥有多个注意力块的概念。
为了便于理解,在笔记本中,我没有通过矩阵乘法并行执行此操作并为头部数量添加额外的维度,而是按顺序执行此操作。
# Adding multi head attention using SingleHeaded ones
# Add a linear layer for predictionnum_heads=2 # work on T4 GPUnum_heads=12 # work on A100 GPUmultihead_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) # as we are concatenating the heads outputlayer_norm1 = nn.LayerNorm(vocab_size)prediction_layer2 = nn.Linear(vocab_size, vocab_size)layer_norm2 = nn.LayerNorm(vocab_size) # last dimension is the vocab size
Multihead Attention Sequentially : Colab notebook Multihead Attention1
请注意,这款笔记本需要更多 GPU 内存,因为免费版 T4 GPU 内存(15 GB)不够。因此,您至少需要 Colab Pro(10 美元可获得 100 个 GPU 积分)才能运行它。
# in the forward passembedded_tokens = token_embedding(trimmed_input)# shape remains (batch_size, seq_len, d_model)pos_embedded_tokens = pos_encoding(embedded_tokens)# Initialise the scores# Initialize an empty list to store scoreshead_outputs = []# get attention and score from multihead attention- we are doing a very simple way# in reality this could be parallelised by adding an extra dim to a matrxi and in one shotfor attention_mod in multihead_attention:score,_ = attention_mod(pos_embedded_tokens)head_outputs.append(score)#Convert list of scores into a sing
Multiheades 注意力模块的输出
# Test the generation function
prompt = "Bloom lived in a big garden"
# output
07-Feb-25 12:59:12 - Generated Text=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)# in the forward pass
# Compute Q, K, V for all heads together, then reshape with the head_dim so that Matrix multiply can do everything in parallelQ = self.W_Q(x).reshape(B, seq_len, self.num_heads, self.head_dim).permute(0, 2, 1, 3) # (B, num_heads, seq_len, head_dim)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)# Rest are same as before
# Compute Scaled Dot-Product Attention
attention_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.head_dim)
请查看我的 repo 以获取这些的进一步更新和改进 github
相关文章:
通过小型语言模型尽可能简单地解释 Transformer
介绍 在过去的几年里,我阅读了无数关于 Transformer 网络的文章,观看了许多视频。其中大部分都非常好,但我很难理解 Transformer 架构,而其背后的主要直觉(上下文敏感嵌入)则更容易掌握。在做演讲时&#…...
GcExcel
GcExcel 简述:GcExcel Java 是一款基于 Java 平台,支持批量创建、编辑、打印、导入/导出Excel文件的服务端表格组件,能够高性能处理和高度兼容 Excel。功能特性(图1)文档查询(图2)...
封装红黑树实现map和set
" 喜欢了你十年,却用整个四月,编织了一个不爱你的谎言。 " 目录 1 源码及其框架分析 2 模拟实现map和set 2.1 实现出复用红黑树的框架 2.2 支持iterator迭代器的实现 2.2.1 代码实现和--这两个运算符 2.3 map支持[ ] Hello,大家…...
Redis进阶使用
在日常工作中,使用Redis有什么需要注意的? 设置合适的过期时间。尽量避免大key问题,避免用字符串存储过大的数据;避免集合的数据量太大,要定期清除。 常用的数据结构有哪些?用在什么地方? 按…...
【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第四节】
ISO 14229-1:2023 UDS诊断服务测试用例全解析(Read DTC Information0x19服务) 作者:车端域控测试工程师 更新日期:2025年2月13日 关键词:UDS诊断协议、0x19服务、DTC信息读取、ISO 14229-1:2023、ECU测试 一、服务功能…...
使用Node.js进行串口通信
目录 一、 安装 serialport 库二.、实现方法1.打开串口并配置参数2. 向串口传递信息3. 接收串口信息4. 处理错误5. 关闭串口6. 使用解析器7. 获取串口列表 三、 完整示例代码 一、 安装 serialport 库 首先,需要安装 serialport 库。可以通过 npm 安装:…...
vue3+elementplus新建项目
更新node.js和npm node.js官网更新指南 可以根据自己的操作系统进行选择 我的电脑操作系统是mac os所以我的步骤如下 # Download and install nvm: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash# in lieu of restarting the shell \. &…...
【网络安全 | 漏洞挖掘】跨子域账户合并导致的账户劫持与删除
未经许可,不得转载。 文章目录 概述正文漏洞成因概述 在对目标系统进行安全测试时,发现其运行着两个独立的域名——一个用于司机用户,一个用于开发者/企业用户。表面上看,这两个域名各自独立管理账户,但测试表明它们在处理电子邮件变更时存在严重的逻辑漏洞。该漏洞允许攻…...
VLSM基础知识
VLSM(Variable Length Subnet Mask,变长子网掩码)是一种更灵活的子网划分技术,允许在同一网络中使用不同长度的子网掩码,以满足不同子网对主机数量的需求,最大化IP地址利用率。 一、基础概念 传统子网划分…...
小小小病毒(3)(~_~|)
一分耕耘一分收获 声明: 仅供损害电脑,不得用于非法。损坏电脑,作者一律不负责。此作为作者原创,转载请经过同意。 欢迎来到小小小病毒(3) 感谢大家的支持 还是那句话:上代码! …...
WebRTC与EasyRTC:开启智能硬件音视频通讯的全新旅程
在当今数字化时代,音视频通讯技术正以前所未有的速度革新着我们的生活与工作方式。WebRTC与EasyRTC作为这一领域的佼佼者,正携手为智能硬件的音视频通讯注入强大动力,开启全新的篇章。 一、WebRTC与智能硬件融合的崭新趋势 WebRTC技术&…...
Lua 数据库访问
Lua 数据库访问 引言 Lua 是一种轻量级的编程语言,因其简洁性和高效性,常被用于游戏开发、嵌入系统和应用程序开发。在许多情况下,数据库访问是应用程序的核心功能之一。本文将深入探讨在 Lua 中如何进行数据库访问,包括连接数据库、执行查询、处理结果以及异常处理等。 …...
rtsp rtmp 跟 http 区别
SDP 一SDP介绍 1. SDP的核心功能 会话描述:定义会话的名称、创建者、时间范围、连接地址等全局信息。媒体协商:明确媒体流的类型(如音频、视频)、传输协议(如RTP/UDP)、编码格式(如H.264、Op…...
蓝桥杯篇---IAP15F2K61S2串口
文章目录 前言简介串口通信的基本参数1.波特率2.数据位3.停止位4.校验位 串口相关寄存器1.SCON2.SBUF3.PCON4.TMOD5.TH1/TL1 串口使用步骤1.配置波特率2.配置串口模式3.使能串口中断4.发送数据5.接收数据6.处理中断 示例代码:串口发送与接收示例代码:串口…...
Linux 远程文件复制传输-----scp/rsync/sftp
scp(Secure Copy Protocol)是基于 SSH 的安全文件传输工具,可用于在本地和远程计算机之间复制文件或目录。 1. scp(基于 SSH 复制文件) a. 复制文件到远程 从本地复制到远程 scp localfile.txt userremote_host:/remo…...
企业文件安全:零信任架构下的文件访问控制
在企业数字化转型的进程中,传统的文件访问控制模型已难以满足日益复杂的网络安全需求。零信任架构作为一种新兴的安全理念,为企业的文件安全访问提供了全新的解决方案。 一、传统文件访问控制的局限性 传统的文件访问控制主要基于网络边界,…...
用deepseek学大模型05-线性回归
deepseek.com:多元线性回归的目标函数,损失函数,梯度下降 标量和矩阵形式的数学推导,pytorch真实能跑的代码案例以及模型,数据,预测结果的可视化展示, 模型应用场景和优缺点,及如何改进解决及改进方法数据推…...
2009年下半年软件设计师上午真题的知识点整理(附真题及答案解析)
以下是2009年下半年软件设计师上午真题的知识点分类整理,涉及定义的详细解释,供背诵记忆。 1. 计算机组成原理 CPU与存储器的访问。 Cache的作用: 提高CPU访问主存数据的速度,减少访问延迟。存储器的层次结构: 包括寄存器、Cache、主存和辅存…...
Element Plus table 去除行hover效果
需求: 给table的指定行设置高亮背景色且去除掉这些行的hover效果 思路: 给指定行设置css类名选择需要设置高亮的行的单元格,设置鼠标禁用属性让高亮行继承父元素的背景色 考虑到表格的第一列是勾选框,因此仅选择 tr 下除了第一…...
2010年下半年软件设计师考试上午真题的知识点整理(附真题及答案解析)
以下是2010年下半年软件设计师考试上午真题的知识点分类整理,涉及定义的详细解释,供背诵记忆。 1. 计算机组成原理 CPU与存储器的访问。 Cache的作用: 提高CPU访问主存数据的速度,减少访问延迟。存储器的层次结构: 包括寄存器、Cache、主存和…...
Mac Golang 开发环境配置
Mac Golang 开发环境配置 Golang 介绍 Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。 由罗伯特格瑞史莫,罗勃派克(Rob Pike)及肯汤普逊于2007年9月开始设计…...
计算机视觉中图像的基础认知
第一章:计算机视觉中图像的基础认知 第二章:计算机视觉:卷积神经网络(CNN)基本概念(一) 第三章:计算机视觉:卷积神经网络(CNN)基本概念(二) 第四章:搭建一个经典的LeNet5神经网络 一、图像/视频的基本属性…...
理解 WebGPU 中的 navigator.gpu 和 adapter:从浏览器到显卡的旅程
WebGPU 是一种现代图形 API,旨在为 Web 应用程序提供高性能的图形和计算功能。作为 WebGL 的继任者,WebGPU 提供了更底层的硬件访问和更高效的性能。在 WebGPU 开发中,navigator.gpu 是访问 WebGPU API 的入口点,而 adapter 则是浏…...
【ESP32 IDF】ESP32 linux 环境搭建
ESP32 linux 环境搭建 1. 开发环境2. linux指令 1. 开发环境 liunx镜像 liunx镜像地址 : https://mirrors.xjtu.edu.cn/ubuntu-releases/20.04.6/ubuntu-20.04.6-live-server-amd64.iso 有提示你装openssl,务必装上 2. linux指令 工具 sudo apt-get …...
react传递函数与回调函数原理
为什么 React 允许直接传递函数? 回调函数核心逻辑 例子:父组件控制 Modal 的显示与隐藏 // 父组件 (ParentComponent.tsx) import React, { useState } from react; import { Modal, Button } from antd; import ModalContent from ./ModalContent;co…...
目标检测IoU阈值全解析:YOLO/DETR模型中的精度-召回率博弈与工程实践指南
一、技术原理与数学本质 IoU计算公式: IoU \frac{Area\ of\ Overlap}{Area\ of\ Union} \frac{A ∩ B}{A ∪ B}阈值选择悖论: 高阈值(0.6-0.75):减少误检(FP↓)但增加漏检(FN↑…...
使用grafana v11 建立k线(蜡烛图)仪表板
先看实现的结果 沪铜主力合约 2025-02-12 的1分钟k线图 功能介绍: 左上角支持切换主力合约,日期,实现动态加载数据. 项目背景: 我想通过前端展示期货指定品种某1天的1分钟k线,类似tqsdk 的web_gui 生成图形化界面— TianQin Python SDK 3.7.8 文档 项目架构: 后端: fastap…...
Ubuntu下载安装Docker-Desktop
下载 Ubuntu | Docker Docs 预备工作 Ubuntu增加docker apt库-CSDN博客 安装 sudo apt-get updatesudo apt install gnome-terminal# sudo apt install -y docker-composesudo apt-get install ./docker-desktop-amd64.deb 测试 sudo docker run hello-worldHello from D…...
【大模型】DeepSeek 高级提示词技巧使用详解
目录 一、前言 二、DeepSeek 通用提示词技巧 2.1 DeepSeek 通用提示词技巧总结 三、DeepSeek 进阶使用技巧 3.1 DeepSeek一个特定角色的人设 3.1.1 为DeepSeek设置角色操作案例一 3.1.2 为DeepSeek设置角色操作案例二 3.2 DeepSeek开放人设升级 3.2.1 特殊的人设&#…...
23. AI-大语言模型
文章目录 前言一、LLM1. 简介2. 工作原理和结构3. 应用场景4. 最新研究进展5. 比较 二、Transformer架构1. 简介2. 基本原理和结构3. 应用场景4. 最新进展 三、开源1. 开源概念2. 开源模式3. 模型权重 四、再谈DeepSeek 前言 AI 一、LLM LLM(Large Language Mod…...
STM32的启动流程
启动模式 我们知道的复位方式有三种:上电复位,硬件复位和软件复位。当产生复位,并且离开复位状态后, CM33 内核做的第一件事就是读取下列两个 32 位整数的值: (1) 从地址 0x0000 0000 处取出堆…...
C++ Primer 函数匹配
欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…...
Httprint 指纹识别技术:网络安全的关键洞察
引言 Http指纹识别现在已经成为应用程序安全中一个新兴的话题,Http服务器和Http应用程序安全也已经成为网络安全中的重要一部分。从网络管理的立场来看,保持对各种web服务器的监视和追踪使得Http指纹识别变的唾手可得,Http指纹识别可以使得信…...
STM32的HAL库开发---ADC
一、ADC简介 1、ADC,全称:Analog-to-Digital Converter,指模拟/数字转换器 把一些传感器的物理量转换成电压,使用ADC采集电压,然后转换成数字量,经过单片机处理,进行控制和显示。 2、常见的AD…...
PostgreSQL有undo表空间吗?
PostgreSQL有undo表空间吗 PostgreSQL 没有单独的 Undo 表空间,其事务回滚和多版本并发控制(MVCC)机制与 Oracle 等数据库有显著差异。 一 PostgreSQL 的 MVCC 实现 PostgreSQL 通过 多版本并发控制(MVCC) 管理事务…...
Huatuo热更新--安装HybridCLR
1.自行安装unity编辑器 支持2019.4.x、2020.3.x、2021.3.x、2022.3.x 中任一版本。推荐安装2019.4.40、2020.3.26、2021.3.x、2022.3.x版本。 根据你打包的目标平台,安装过程中选择必要模块。如果打包Android或iOS,直接选择相应模块即可。如果你想打包…...
Windows环境安装部署minimind步骤
Windows环境安装部署minimind步骤 必要的软件环境 git git,可下载安装版,本机中下载绿色版,解压到本地目录下(如:c:\soft\git.win64),可将此路径添加到PATH环境变量中,供其他程序…...
前端面试手写--虚拟列表
目录 一.问题背景 二.代码讲解 三.代码改装 四.代码发布 今天我们来学习如何手写一个虚拟列表,本文将把虚拟列表进行拆分并讲解,然后发布到npm网站上. 一.问题背景 为什么需要虚拟列表呢?这是因为在面对大量数据的时候,我们的浏览器会将所有数据都渲染到表格上面,但是渲…...
【算法进阶详解 第一节】树状数组
【算法进阶详解 第一节】树状数组 前言树状数组基础树状数组原理树状数组能够解决的问题 树状数组提高树状数组区间加,区间和操作二维树状数组 树状数组应用树状数组区间数颜色树状数组二维偏序 前言 树状数组在算法竞赛中十分常见,其能解决二维数点&am…...
青少年编程与数学 02-009 Django 5 Web 编程 16课题、权限管理
青少年编程与数学 02-009 Django 5 Web 编程 16课题、权限管理 一、授权授权的主要特点和作用授权的类型应用场景 二、权限系统使用Django内置的权限系统使用组管理权限使用第三方库在视图中应用权限 三、权限管理示例步骤 1: 创建Django项目和应用步骤 2: 定义模型和权限步骤 …...
第四十四篇--Tesla P40+Janus-Pro-7B部署与测试
环境 系统:CentOS-7 CPU: 14C28T 显卡:Tesla P40 24G 驱动: 515 CUDA: 11.7 cuDNN: 8.9.2.26创建环境 conda create --name trans python3.10torch 2.6.0 transformers 4.48.3克隆项目 git clone https:/…...
低成本、高效率且成熟的电商实时数据采集方案:梦想成真?
在电子商务领域,数据是驱动业务决策的核心资源。实时数据采集对于电商企业而言,意味着能够即时洞察市场动态、消费者行为以及运营效果,从而快速调整策略,提升竞争力。然而,如何在保证数据质量的同时,实现低…...
微信小程序之mobx-miniprogram状态管理
目前已经学习了6种小程序页面、组件间的数据通信方案,分别是: 1. 数据绑定: properties 2.获取组件实例: this.selectComponent() 3.事件绑定: this.triggerEvent() 4. 获取应用实例:getApp() 5. 页面间通信: EventChannel 6.事件总线:pubsub-js 在中小型项目…...
uniapp可视化-活动报名表单系统-代码生成器
活动报名表单系统小程序旨在为各类活动组织者提供一个便捷、高效的线上报名管理平台,同时为参与者提供简单易用的报名途径。 主要功能 活动发布:活动组织者可以发布活动的详细信息,包括活动名称、时间、地点、活动内容等。用户可以在小程序中…...
1.从零开始学会Vue--{{基础指令}}
全新专栏带你快速掌握Vue2Vue3 1.插值表达式{{}} 插值表达式是一种Vue的模板语法 我们可以用插值表达式渲染出Vue提供的数据 1.作用:利用表达式进行插值,渲染到页面中 表达式:是可以被求值的代码,JS引擎会将其计算出一个结果 …...
深入解析操作系统控制台:阿里云Alibaba Cloud Linux(Alinux)的运维利器
作为一位个人开发者兼产品经理,我的工作日常紧密围绕着云资源的运维和管理。在这个过程中,操作系统扮演了至关重要的角色,而操作系统控制台则成为了我们进行系统管理的得力助手。本文将详细介绍阿里云的Alibaba Cloud Linux操作系统控制台的功…...
CSS Grid 网格布局,以及 Flexbox 弹性盒布局模型,它们的适用场景是什么?
CSS Grid网格布局和Flexbox弹性盒布局模型都是现代CSS布局的重要工具,它们各自具有独特的优势和适用场景。 作为前端开发工程师,理解这些布局模型的差异和适用场景对于编写高效、可维护的代码至关重要。 CSS Grid网格布局 适用场景: 复杂…...
2025.2.16机器学习笔记:TimeGan文献阅读
2025.2.9周报 一、文献阅读题目信息摘要Abstract创新点网络架构一、嵌入函数二、恢复函数三、序列生成器四、序列判别器损失函数 实验结论后续展望 一、文献阅读 题目信息 题目: Time-series Generative Adversarial Networks会议: Neural Information…...
高通推出骁龙游戏超级分辨率™:充分释放移动游戏性能,带来更持久的续航
Snapdragon Elite Gaming 一直致力于为每位用户打造卓越游戏体验。骁龙支持众多端游级特性,包括144FPS游戏体验、True 10-bit HDR支持的最高视觉质量的超流畅图形,让玩家可以畅享超10亿色的游戏体验。骁龙将许多移动端首创特性引入备受玩家喜爱的游戏中&…...
golangAPI调用deepseek
目录 1.deepseek官方API调用文档1.访问格式2.curl组装 2.go代码1. config 配置2.模型相关3.错误处理4.deepseekAPI接口实现5. 调用使用 3.响应实例 1.deepseek官方API调用文档 1.访问格式 现在我们来解析这个curl 2.curl组装 // 这是请求头要加的参数-H "Content-Type:…...