floraNo1 / llama3_fuxian_22shuke_guandongzu

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

大家好,我们是山东大学威海校区22级数科班关东组

LLaMA(Language Learning from Multiview Annotations) 是一个用于自然语言处理的开源平台,它是 LLaMA 系统的最新版本,旨在通过多视图学习和弱监督学习来实现对自然语言的理解和生成。LLaMA 系统提供了一种框架,能够从多源标注数据中学习语言模型,用于解决各种自然语言处理任务。

以下是llama3从头开始利用pytorch来实现并复现LLaMA-3模型的每层代码的简介、核心思路梳理。

aistudio链接为https://aistudio.baidu.com/projectdetail/8170849?sUid=5563173&shared=1&ts=1721317425138

(有更详细的讲解与代码)现在文件中有model.safetensors和optimizer.pt由于文件较大无法上传

参考数据集来源链接https://huggingface.co/datasets/noanabeshima/TinyStoriesV2

一. 输入嵌入层

  1. BPE算法

1.1 简介

字节对编码(Byte Pair Encoding,BPE) 是一种用于自然语言处理(NLP)的子词分词算法,在Llama3中运用。它的目的是将词汇表的大小控制在预定范围内,同时有效地处理未知词汇(Out-of-Vocabulary, OOV)问题。其核心**在于迭代地合并出现频率最高的字符对。

1.2 流程

初始化词汇表和频次统计:首先准备语料库并统计每个单词的出现频次,将这些单词以“词频_词语”的形式存储。这里的下划线表示词的结尾。

设定终止条件:设置词表的最大长度或者循环的次数作为算法的终止条件。

统计字符频次:统计每个字符(包括结束符‘_’)的出现频次,这张表即为初始词汇表(vocabulary)。在后续迭代中,这张表将用于分词。

合并字符对:在每次迭代中,选择频次最高的相邻字符对进行合并。例如,首次迭代可能会合并‘r’和‘’形成‘r’,然后更新词汇表中的频。

更新词汇表:合并后的字符对替换原有的两个字符,并从词汇表中删除这两个字符的条目,同时增加新条目。如果词表中的总长度超过预设的最大长度,需要适当减少。

重复迭代:重复上述过程直到达到预设的词表大小或迭代次数,这样最终得到的词表即可用于文本分词。

例如,语料库中的单词“newest”可以被拆分为“new”、“est”和其他子词单元,其中“new”出现了8次,“est”出现了6次。通过这种方式,BPE算法能够有效减少词表的大小,同时保留语义信息。

  1. 嵌入向量化

离散token ID进行嵌入向量化的过程是通过嵌入矩阵(Embedding Matrix)实现的。具体步骤如下:

标记化:将输入文本分割成单词、子词或字符等标记。

词汇表映射:为每个标记分配一个唯一的整数索引,这些索引通常来自模型的词汇表。

嵌入矩阵:构建一个嵌入矩阵,其行数等于词汇表的大小,列数等于模型设定的向量维度。

查找嵌入向量:根据每个标记的索引,在嵌入矩阵中查找对应的向量表示,从而得到该标记的嵌入向量。

学习与调整:在模型训练过程中,嵌入向量会通过反向传播算法进行学习和调整,以更好地捕捉语义信息并适应特定任。

上下文感知:对于高级模型如BERT,嵌入向量还会考虑单词的上下文信息,生成上下文相关的词向量。

预训练与微调:嵌入向量通常首先在大规模语料库上预训练,然后在特定任务上进行微调。

优化与正则化:使用优化算法和正则化技术来防止过拟合,提高模型泛化能力。

3.RMSNorm

RMSNorm用于神经网络中对每个神经元的输入进行标准化。它通过将输入除以它们的均方根(Root Mean Square,RMS)来实现标准化。 通常在标准化之后,还可以对输入进行缩放和偏移操作,以增加模型的表达能力。 RMSNorm有助于减少内部协变量偏移问题,提高神经网络的训练稳定性和收敛速度。

二. 位置编码层

为词元嵌入位置信息,使模型理解词元顺序。主要运用多头注意力机制及残差连接Transformer层。

  1. transformer模型

1.1 矩阵乘法

整个transformer的模型的核心操作为矩阵乘法,矩阵乘法的最好效果一定程度上决定着模型在硬件上运行的上限;方块矩阵的计算性能,以每秒中运行多少个t的浮点计算作为指标。

分两种情况考虑:

两个简单向量的乘积,考虑做a与b的内积,浮点运算为n次乘法与n-1次加法之和,近似为2n

两个大小为n×n的矩阵的乘积,矩阵C中的每个元素是通过将矩阵A的第i行与矩阵B的第j列对应元素相乘然后求和得到的。

两个n×n矩阵相乘的总计算复杂度为𝑂(𝑛^3)。

在性能测量中,特别是在并行计算或高性能计算领域,我们经常使用FLOPS(每秒浮点运算次数)来衡量计算速度。对于n×n矩阵乘法,我们有:每个矩阵元素需要大约2次浮点运算(一次乘法和一次加法),总共需要 2n^3次浮点运算。

1.2 transformer模型的性能

其核心为Multi-Head Attention的性能和Feedforward Neural Network的性能。考虑的超参数:序列长度,批量大小;不变量:隐藏层大小

2.多头注意力机制

它扩展了传统的注意力机制,允许模型同时在不同的表示空间中学习多个注意力机制。

2.1 注意力机制

查询(Query): Query是用来寻找关注点的向量,可以理解为模型想要从输入中获取的信息。它决定了我们希望关注的内容。

键(Key): Key向量帮助确定输入中各个元素的重要性或相关性。它决定了每个元素在注意力机制中的影响力。

值(Value): Value向量是根据Key向量的重要性加权得到的,它们包含了真正用于输出的信息。在注意力机制中,Value向量根据Key的权重来调整,最终用于生成输出。

注意力机制是通过Query与Key的注意力汇聚(给定一个 Query,计算Query与 Key的相关性,然后根据Query与Key的相关性去找到最合适的 Value)实现对Value的注意力权重分配,生成最终的输出结果。

举个例子: 假设输入句子是:“The cat sat on the mat.”

Query (Q) :是用来询问“主语是什么”的问题,那么Query可能会是一个向量,表示“cat”。

Key (K) :将帮助模型理解每个词在句子中的重要性或联系性。在这个例子中,Key向量可以是每个词的词向量,帮助区分句子中不同词的作用和关系。

Value (V) :根据Key的重要性来选择每个词的输出信息。例如,如果Key向量指出“cat”在句子中很重要,那么对应的Value向量可能包含有关“cat”的详细描述或相关语义信息。

2.2 自注意力机制

2.2.1 基本介绍

自注意力机制(Self-Attention Mechanism) 是一种用于序列建模的注意力机制,最初在Transformer模型中广为使用。它解决了传统循环神经网络(RNNs)和卷积神经网络(CNNs)在处理长距离依赖和全局信息整合时的限制。传统的神经网络结构通常难以捕捉长距离的依赖关系,而自注意力机制能够在保持并行计算的同时,有效地捕捉长距离的依赖关系,使得模型更加具有全局感知能力。

自注意力机制广泛应用于各种自然语言处理任务,如机器翻译、语言建模、文本分类、问答系统等。例如,在Transformer模型中,自注意力机制作为核心组件被用于代替RNN或CNN,极大地提升了这些任务的性能和效率。

2.2.2 原理

自注意力机制允许模型在单个输入序列的不同位置之间建立依赖关系,而无需通过任何先验的位置信息。它的核心**是将序列中每个位置的信息转化为三个不同的向量:Query(查询)、Key(键)和Value(值)。这三个向量通过线性变换来计算,并且对整个序列中的每个位置都是相同的。

2.2.3 自注意力机制与注意力机制的区别

自注意力机制:在自注意力机制中,Query、Key和Value都来自同一个输入序列。每个位置的向量可以同时充当Query、Key和Value,使得模型在处理输入序列时能够同时考虑到全局和局部的依赖关系。

通常的注意力机制:在编码器-解码器结构中,通常使用的注意力机制是一种上下文相关的注意力。在编码器中,Query来自解码器的先前状态,而Key和Value来自编码器的输出序列,这种设计使得模型能够根据解码器的当前状态来动态地关注编码器输出的不同部分。

2.3 多头注意力机制

  1. KVcache

在推断阶段,KV cache是transformer模型加速推断的常用策略。

  1. 旋转嵌入RoPE(以Query向为例讲解)

由以上过程,我们已经为prompt中的每个token生成了query向量,但每个单独的query向量并不知道它在prompt中的具体位置。而RoPE通过将位置编码与输入向量进行旋转操作,能够自然扩展到更长的序列,提供了一种更灵活和高效的方式来捕捉相对位置。

假设我们有一个长文本输入,包含多个句子和段落。使用 RoPE 的 LLaMA 3 模型能够:

• 捕捉句子之间的关系:例如,在处理“我爱吃苹果”和“我今天吃了一个苹果”这两个句子时,RoPE 能够帮助模型理解“苹果”在两个句子中的位置关系。

• 处理复杂上下文:在推理时,如果输入序列超过了训练时的最大长度,RoPE 的旋转特性使得模型依然能够有效利用之前的上下文信息,而不会导致信息丢失。

举例:

假设我们有一个包含一系列文字的句子,如“今天天气很好”。在ROPE过程中,每个位置的单词会被嵌入为一个旋转向量,表示其在句子中的位置。通过旋转位置嵌入,模型可以更好地理解句子中不同单词之间的位置关系,比如“今天”和“天气”之间的近邻关系,或者“今天”和“很好”之间的远距离关系。

三. LLaMA的核心模块

  1. MHA模块

输入准备: 我们将输入序列首先转换为一系列的token,这些token通过嵌入层(Embedding Layer)被转换为向量表示。 对于每个token的嵌入向量,通过三个不同的线性变换(即全连接层)分别生成Q(查询)、K(键)和V(值)矩阵,这些线性变换的权重是模型在训练过程中学习得到的,它们会将嵌入向量映射到不同的子空间,以便进行注意力计算。

注意力得分计算: 注意力得分计算主要包括两个过程,分别为缩放点积注意力、softmax归一化,在每个token中,我们利用Q矩阵中的每个查询向量与K矩阵中的所有键向量进行点积运算,得到原始的注意力得分,这其中的每一项代表的就是每个 token 与其他 token 之间的关联度。具体来说,就是表示每个 token 的 query 向量与其 key 向量之间的相互关系。为了防止点积结果过大导致softmax函数进入梯度消失的区域,所以通常会将点积结果除以一个缩放因子(缩放因子常选用键向量维度的平方根);之后对缩放后的注意力得分进行softmax归一化处理,要确保所有注意力分数的和为1,从而得到归一化后的注意力权重。

加权求和: 在进行加权求和之前,我们首先要对注意力权重矩阵进行掩码处理,这是为了确保我们只学习使用过去的token来预测未来token。之后我们将将归一化后的注意力权重与对应的V矩阵中的值向量相乘。这一步实现了对V矩阵中向量的加权求和;在多头注意力机制中,每个token都会独立地进行上述计算,得到各自的输出,通过将这些输出拼接在一起,形成一个更大的矩阵。最后,令这个拼接后的矩阵通过一个额外的线性变换(通常是全连接层),得到最终的输出向量。 但在此基础上,我们需要将注意力机制的输出加到原始嵌入向量上,以更新嵌入信息,再做为后续网络层的输入进一步处理。这一步骤是模型架构中的一个重要环节。通常被称为残差连接(Residual Connection)或跳跃连接(Skip Connection),它是深度学习中一种常用的技术,旨在解决深层网络训练时可能出现的梯度消失或梯度爆炸问题,同时也有助于提高模型的性能。

  1. FFNN层

在MHA模块中经过输入准备、注意力得分计算以及加权求和等过程后,我们最终得到了一个输出向量,为了更好的提升模型的性能,我们选择将得到的输出向量添加到嵌入向量中,那么在此基础上我们再次进行归一化并运用前馈神经网络(FFN)增加模型的非线性。

在LLaMA中,我们的前馈神经网络采用的是SwiGLU前馈网络

SwiGLU(Switched Gated Linear Unit)前馈网络是一种在深度学习领域中,特别是在大型语言模型(LLaMA)中使用的特殊前馈神经网络(Feedforward Neural Network, FFN)结构。SwiGLU通过结合门控机制和非线性激活函数,对传统的FFN进行了优化和改进,以提高模型的性能和学习能力。

SwiGLU的基本概念 SwiGLU是Gated Linear Units(GLU)激活函数的一种变体,它结合了Swish激活函数和门控机制的特点。SwiGLU通过动态地调整信息的流动,使得模型能够更有效地学习和适应数据中的复杂特征。

SwiGLU的实现机制 在SwiGLU前馈网络中,输入数据首先经过线性变换,然后分别应用两个权重矩阵进行处理。其中一个分支的数据通过Swish激活函数进行非线性变换,另一个分支则保持线性变换。最后,两个分支的结果进行逐元素乘法(Hadamard product)操作,得到SwiGLU的输出。

循环迭代以及层归一化

在LLaMA中,循环迭代和归一化是处理数据并优化模型性能的关键步骤。 在Transformer模型中,词的嵌入会通过一个由多个相同结构层堆叠而成的,也就是我们所说的网络多层Transformer层,每一层都是由两部分组成:自注意力机制(Self-Attention Mechanism)和前馈网络(Feedforward Network,也常被称为多层感知机MLP)

在自注意力机制这一层,它允许模型在处理每个词元时,能够考虑到句子中其他所有词元的信息。它通过计算每个词元(Query)与句子中其他词元(Key)之间的相似度,然后基于这些相似度对词元(Value)进行加权求和来实现。

在这一过程中,每个词元的嵌入(现在已经是编辑后的嵌入)都会根据句子中其他词元的信息进行更新,从而捕获到更多的上下文信息。 经过自注意力层后,数据会通过一个由两层全连接层组成的前馈网络。这一层可以对数据进行更复杂的非线性变换,进一步提取特征。每一transformer层的MLP都是独立的,并且可以对自注意力层的输出进行独立的处理。

这种结构会重复多次,并且每一层都会根据前一层的输出进行进一步的处理和特征提取。随着层数的增加,模型能够捕获到的上下文信息和特征也会越来越复杂和深入。

在LLaMA模型中,归一化通常通过层归一化(Layer Normalization)来实现。层归一化可以用于加速训练过程并提高模型的稳定性。 在每个Transformer层的开始和结束处,都会进行层归一化操作。这有助于控制数据的分布,使其保持在合理的范围内,从而避免梯度消失或爆炸的问题。

具体来说,层归一化会对每个词元的隐藏状态进行归一化处理,使其均值为0,方差为1(或某个固定的方差)。然后,这个归一化后的状态会被缩放和平移(通过可学习的参数),以恢复模型的表达能力。

通过循环迭代和归一化的结合,Transformer模型能够逐层提取和整合信息,最终生成一个能够全面理解并预测下一个token的嵌入向量。

About


Languages

Language:Python 100.0%