大模型(LLMs)学习笔记(1)——基础知识

文摘   2024-11-06 00:09   河北  


微信号:
python__matlab


后台滴滴小英熊学长欧~

目录:

一. 大模型介绍

二. Layer Normalization

三. 激活函数

四. Attention

五. transformers函数

六. 损失函数

七. 相似度函数




一.大模型介绍

1.目前主流的开源模型体系有哪些?

(1)Causal Decoder(因果解码器)
介绍:从左到右的单项注意力
代表模型:Chat GPT、LLaMA-7B、LLaMa系列。

(2)Prefix Decoder(前缀解码器)
介绍:输入双向注意力,输出单向注意力
代表模型:ChatGLM、Chat GLM2、U-PaLM

(3)Encoder-Decoder
介绍:输入双向注意力,输出单向注意力
代表模型:T5、BERT、Flan-T5



2.三种主流体系的区别是什么?

 主要体现在attention mask的不同:

(1)Causal Decoder

自回归语言模型,预训练和下游应用是完全一致的,严格遵守只有后面的 token 才能看到前面的 token 的规则。适用于文本生成任务。优点是训练效率高,zero-shot 能力更强,具有涌现能力。


(2)Prefix Decoder

Prefix部分的token互相能看到,Causal Decoder和Encoder Decoder折中。缺点是训练效率低。


(3)Encoder-Decoder

在输入上采用双向注意力,对问题的编码理解更充分。适用于在偏理解的 NLP 任务上。缺点是在长文本生成任务上效果差,训练效率低。


3.大模型LLM的训练目标是什么?

(1)语言模型

 根据已有词预测下一个词,训练目标为最大似然函数:

训练效率:

Prefix Decoder<Causal Decoder,Causal Decoder结构会在所有 token上计算损失,而PrefixDecoder只会在输出上计算损失。


(2)去噪自编码器

随机替换掉一些文本段,训练语言模型去恢复被打乱的文本段。目标函数为:

去噪自编码器的实现难度更高。采用去噪自编码器作为训练目标的任务有GLM-130B、T5。

4.涌现能力是什么原因?

(1)任务的评价指标不够平滑

(2)复杂任务 vs 子任务

假设某个任务T有5个子任务Sub-T构成,每个sub-T随着模型增长,指标从40%提升到60%,但是最终任务的指标只从1.1% 提升到了 7%,也就是说宏观上看到了涌现现象,但是子任务效果其实是平滑增长的。


5.为何大部分大模型是Decoder only结构?

 因为 decoder-only结构模型在没有任何微调数据的情况下zero-shot 的表现能力最好。而encoder-decoder 则需要在一定量的标注数据上做multitask-finetuning 才能够激发最佳性能。


目前的 LargelM 的训练范式还是在大规模语料shang 做自监督学习,很显然zero-shot 性能更好的 decoder-only 架构才能更好的利用这些无标注的数据。


大模型使用decoder-only架构除了训练效率和工程实现上的优势外,在理论上因为Encoder的双向注意力会存在低秩的问题,这可能会削弱模型的表达能力。就生成任务而言,引入双向注意力并无实质的好处。而Encoder-decoder模型架构之所以能够在某些场景下表现更好,大概是因为它多了一倍参数。所以在同等参数量、同等推理成本下,Decoder-only 架构就是最优的选择了。


6.简单介绍一下大模型(LLMs),后面的B是什么

 大模型一般指1亿以上参数的模型,但是这个标准一直在升级,目前万亿参数以上的模型也有了。大语言模型(Large LanguageModel,LLM)是针对语言的大模型。175B、60B、540B等,指参数的个数,B是Billion/十亿的意思,175B 是 1750 亿参数,这是 ChatGPT 大约的参数规模。


7.简单介绍一下大模型(LLMs)优缺点。

(1)优点

可以利用大量的无标注数据来训练一个通用的模型,然后再用少量的有标注数据来微调模型,以适应特定的任务。这种预训练和微调的方法可以减少数据标注的成本和时间,提高模型的泛化能力;可以利用生成式人工智能技术来产生新颖和有价值的内容,例如图像、文本、音乐等。这种生成能力可以帮助用户在创意、娱乐、教育等领域获得更好的体验和效果;可以利用涌现能力(Emergent Capabilities)来完成一些之前无法完成或者很难完成的任务,例如数学应用题、常识推理符号操作等。这种涌现能力可以反映模型的智能水平和推理能力。


(2)缺点

需要消耗大量的计算资源和存储资源来训练和运行,这会增加经济和环境的负担。据估计,训练一个 GPT-3 模型需要消耗约30 万美元,并产生约284 吨二氧化碳排放需要面对数据质量和安全性的问题,例如数据偏见、数据泄露数据滥用等。这些问题可能会导致模型产生不准确或不道德的输出,并影响用户或社会的利益;需要考虑可解释性、可靠性、可持续性等方面的挑战,例如如何理解和控制模型的行为、如何保证模型的正确性和稳定性、如何平衡模型的效益和风险等。这些挑战需要多方面的研究和合作,以确保大模型能够健康地发展。




二.Layer Normalization

1.Layer Norm

计算公式:

γ是可训练的再缩放参数,β是可训练的再偏移参数。

2.RMS Norm

均方根Norm计算公式:

RMS Norm相比于Layer Norm,简化了Layer Norm去除掉计算均值进行平移的部分。RMS Norm的计算速度更快,效果基本相当,甚至略有提升。


3.Deep Norm

Deep Norm方法在执行Layer Norm之前,up-scale了残差连接(alpha>1);另外,在初始化阶段down-scale了模型参数(beta<1),代码实现:
def deepnorm(x):    return LayerNorm(x*a + f(x))def deepnorm_init(w):    if w is ['ffn','v_proj','out_proj']:        nn.init.xavier_normal_(w,gain-6)    elif w is['q_proj','k_proj']:        nn.init.xavier_normal_(w,gain=1)

Deep Norm可以缓解爆炸式模型更新的问题,把模型更新限制在常数,使得模型训练过程更稳定。

4.Layer Norm位置

(1)Post-LN
layer norm在残差链接之后。Post LN 在深层的梯度范式逐渐增大,导致使用post-LN的深层transformer容易出现训练不稳定的问题。

(2)Pre-LN
layer norm在残差链接中。相比于Post-LN,Pre LN 在深层的梯度范式近似相等,所以使用Pre-LN的深层transformer训练更稳定,可以缓解训练不稳定问题。相比于Post-LN,Pre-LN的模型效果略差。

(3) Sandwich-LN
在pre-LN的基础上,额外插入了一个layer norm。Cogview用来避免值爆炸的问题。训练不稳定,可能会导致训练崩溃。


5.Layer Normalization对比




三.激活函数

1.FFN块计算公式

FFN(Feed-Forward Network)块是Transformer模型中的一个重要组成部分,接受自注意力子层的输出作为输入,并通过一个带有 Relu 激活函数的两层全连接网络对输入进行更加复杂的非线性变换。实验证明,这一非线性变换会对模型最终的性能产生十分 重要的影响。FFN由两个全连接层(即前馈神经网络)和一个激活函数组成。下面是FFN块的计算公式:

输入是x,第一层全连接层进行线性变换,然后使用Relu激活函数,第二层全连接层进行线性变换。

2. GeLU 计算公式?

GeLU(Gaussian Error Linear Unit)激活函数,常用于神经网络中的非线性变换。它在Transformer模型中广泛应用于FFN(Feed-Forward Network)块。计算公式

相对于 Sigmoid 和 Tanh 激活函数,ReLU 和 GeLU 更为准确和高效,因为它们在神经网络中的梯度消失问题上表现更好。而 ReLU 和 GeLU 几乎没有梯度消失的现象,可以更好地支持深层神经网络的训练和优化。而 ReLU 和 GeLU 的区别在于形状和计算效率。ReLU 是一个非常简单的函数,仅仅是输入为负数时返回0,而输入为正数时返回自身,从而仅包含了一次分段线性变换。但是,ReLU 函数存在一个问题,就是在输入为负数时,输出恒为0,这个问题可能会导致神经元死亡,从而降低模型的表达能力。GeLU 函数则是一个连续的 S 形曲线,介于 Sigmoid 和 ReLU 之间,形状比 ReLU 更为平滑,可以在一定程度上缓解神经元死亡的问题。不过,由于 GeLU 函数中包含了指数运算等复杂计算,所以在实际应用中通常比 ReLU 慢。


3. Swish计算公式?

常用于神经网络的非线性变换。Swish函数的计算公式如下:

Swish函数的特点是在接近零的区域表现得类似于线性函数,而在远离零的区域则表现出非线性的特性。相比于其他常用的激活函数(如ReLU、tanh等),Swish函数在某些情况下能够提供更好的性能和更快的收敛速度。Swish函数的设计灵感来自于自动搜索算法,它通过引入一个可调节的超参数来增加非线性程度。当beta为0时,Swish函数退化为线性函数;当beta趋近于无穷大时,Swish函数趋近于ReLU函数。


4.使用GLU线性门控单元的FFN块计算公式


5.使用GeLU的GLU块计算公式

使用GeLU作为GLU块的激活函数可以增强模型的非线性能力,并在某些情况下提供更好的性能和更快的收敛速度。这种结构常用于Transformer模型中的编码器和解码器,用于对输入向量进行非线性变换和特征提取。

6.使用Swish的GLU 块计算公式

使用Swish作为GLU块的激活函数可以增强模型的非线性能力,并在某些情况下提供更好的性能和更快的收敛速度。GLU块常用于Transformer模型中的编码器和解码器,用于对输入向量进行非线性变换和特征提取。




四.Attention

1.Attention简介

(1)传统 Attention 存在哪些问题
传统 Attention 存在 上下文长度约束问题;速度慢,内存占用大;

(2)优化方向
提升上下文长度;加速、减少内存占用。

(3)Attention变体
• 稀疏attention。将稀疏偏差引入 attention 机制可以降低了复杂性; 
• 线性化attention。解开 attention 矩阵与内核特征图,然后以相反的顺序计算attention以实现线性复杂度;
• 原型和内存压缩。这类方法减少了查询或键值记忆对的数量,以减少注意力矩阵的大小; 
• 低阶self-Attention。这一系列工作捕获了 self-Attention 的低阶属性; 
• Attention与先验。该研究探索了用先验 attention 分布来补充或替代标准 attention;
• 改进多头机制。该系列研究探索了不同的替代多头机制。

2.Multi-Query Attention
(1)存在的问题
不会显著影响训练过程,训练速度不变,会引起非常细微的模型效果损失;推理过程中反复加载巨大的 KV cache , 导致内存开销大,性能是内存受限;

(2)结构图示

Multi-Query Attention 在所有注意力头上 共享 key 和 value.

(3)对比Multi-head Attention和Multi-Query Attention
• Multi-head Attention:每个注意力头都有各自的query、key和value。 
• Multi-query Attention: 在所有的注意力头上共享key和value。


Falcon、PaLM、ChatGLM2-6B都使用了Multi-query Attention,但有细微差别。为了保持参数量一致,Falcon把隐藏维度从4096增大到了4544。多余的参数量分给了Attention块和FFN块 ;ChatGLM2 把FFN中间维度从11008增大到了13696。多余的参数分给了FFN块。

Multi-Query Attention 这样做的好处是减少 KV cache 的大小,减少显存占用,提升推理速度。代表模型:PaLM、ChatGLM2、Falcon等

3.Grouped-query Attention
Grouped query attention介于multi head和multi query之间,多个key和value。ChatGLM2,LLaMA2-34B/70B使用了Grouped query attention。

4.FlashAttention
• 核心:用分块softmax等价替代传统softmax
• 优点:节约HBM,高效利用SRAM,省显存,提速度 
• 代表模型:Meta推出的开源大模型LLaMA,阿联酋推出的开源大模型Falcon都使用了Flash Attention来加速计算和节省显存 
• 关键词:HBM、SRAM、分块Softmax、重计算、Kernel融合。

5.并行 transformer block
用并行公式替换了串行,提升了15%的训练速度。在8B参数量规模,会有轻微的模型效果损失;在62B参数量规模,就不会损失模型效果。Falcon、PaLM都使用了该技术来加速训练.




五.transformers函数

1.如何利用transformers加载 Bert 模型

import torchfrom transformers import BertModel, BertTokenizer # 这里我们调用bert-base模型,同时模型的词典经过小写处理model_name = 'bert-base-uncased' # 读取模型对应的tokenizertokenizer = BertTokenizer.from_pretrained(model_name) # 载入模型model = BertModel.from_pretrained(model_name) # 输入文本input_text = "Here is some text to encode" # 通过tokenizer把文本变成 token_idinput_ids = tokenizer.encode(input_text, add_special_tokens=True) # input_ids: [101, 2182, 2003, 2070, 3793, 2000, 4372, 16044, 102]input_ids = torch.tensor([input_ids]) # 获得BERT模型最后一个隐层结果with torch.no_grad(): last_hidden_states = model(input_ids)[0]  # Models outputs are now tuples
""" tensor([[[-0.0549, 0.1053, -0.1065, ..., -0.3550, 0.0686, 0.6506], [-0.5759, -0.3650, -0.1383, ..., -0.6782, 0.2092, -0.1639], [-0.1641, -0.5597, 0.0150, ..., -0.1603, -0.1346, 0.6216], ..., [ 0.2448, 0.1254, 0.1587, ..., -0.2749, -0.1163, 0.8809], [ 0.0481, 0.4950, -0.2827, ..., -0.6097, -0.1212, 0.2527], [ 0.9046, 0.2137, -0.5897, ..., 0.3040, -0.6172, -0.1950]]]) shape: (1, 9, 768) """

2.如何输出 Bert 指定 hidden_state
Bert 默认是 十二层,但是有时候预训练时并不需要利用全部利用,而只需要预训练前面几层即可,此时该怎么做呢?下载到bert-base-uncased的模型目录里面包含 配置文件 config.json, 该文件中包含 output_hidden_states,可以利用 该参数来设置 编码器内隐藏层层数。
{ "architectures": [ "BertForMaskedLM" ], "attention_probs_dropout_prob": 0.1, "hidden_act": "gelu", "hidden_dropout_prob": 0.1, "hidden_size": 768, "initializer_range": 0.02, "intermediate_size": 3072, "max_position_embeddings": 512, "num_attention_heads": 12, "num_hidden_layers": 12, "type_vocab_size": 2, "vocab_size": 30522 }

3. BERT 获取最后一层或每一层网络的向量输出
(1) transformer 最后一层输出的结果

last_hidden_state:
shape是(batch_size, sequence_length, hidden_size),hidden_size=768,它是模型最后一 层输出的隐藏状态 pooler_output:shape是(batch_size, hidden_size),这是序列的第一个token(classification token)的最后一 层的隐藏状态,它是由线性层和Tanh激活函数进一步处理的,这个输出不是对输入的语义内容的一个很好的总结, 对于整个输入序列的隐藏状态序列的平均化或池化通常更好。
hidden_states:
这是输出的一个可选项,如果输出,需要指定config.output_hidden_states=True,它也是一个元 组,它的第一个元素是embedding,其余元素是各层的输出,每个元素的形状是(batch_size, sequence_length, hidden_size) attentions:这也是输出的一个可选项,如果输出,需要指定config.output_attentions=True,它也是一个元组, 它的元素是每一层的注意力权重,用于计算self-attention heads的加权平均值。

(2) 获取每一层网络的向量输出
##最后一层的所有 token向量outputs.last_hidden_state ## cls向量outputs.pooler_output ## hidden_states,包括13层,第一层即索引0是输入embedding向量,后面1-12索引是每层的输出向量hidden_states = outputs.hidden_statesembedding_output = hidden_states[0]attention_hidden_states = hidden_states[1:]



六.损失函数

1.KL散度简介

KL(Kullback-Leibler)散度衡量了两个概率分布之间的差异。其公式为:


2.交叉熵函数

交叉熵损失函数(Cross-Entropy Loss Function)是用于度量两个概率分布之间的差异的一种损失函数。在分类问题中,它通常用于衡量模型的预测分布与实际标签分布之间的差异。


3.KL散度和交叉熵区别

KL散度指的是相对熵,KL散度是两个概率分布P和a差别的非对称性的度量。KL散度越小表示两个分布越接近。也就是说KL散度是不对称的,且KL散度的值是非负数。(也就是熵和交叉熵的差)

交叉熵损失函数是二分类问题中最常用的损失函数,由于其定义出于信息学的角度,可以泛化到多分类问题中。KL 散度是一种用于衡量两个分布之间差异的指标,交叉损失函数是 KL散度的一种特殊形式。在二分类问题中,交叉函数只有一项,而在多分类问题中有多项。


4.多任务学习各loss差异过大怎么办

多任务学习中,如果各任务的损失差异过大,可以通过动态调整损失权重、使用任务特定的损失函数、改变模型架构或引入正则化等方法来处理。目标是平衡各任务的贡献,以便更好地训练模型

5.分类问题为什么用交叉熵损失函数不用均方误差(MSE)

交叉熵损失函数通常在分类问题中使用,而均方误差(MSE)损失函数通常用于回归问题。这是因为分类问题和回归问题具有不同的特点和需求。


分类问题的目标是将输入样本分到不同的类别中,输出为类别的概率分布。交叉熵损失函数可以度量两个概率分布之间的差异,使得模型更好地拟合真实的类别分布。它对概率的细微差异更敏感,可以更好地区分不同的类别。此外,交叉损失函数在梯度计算时具有较好的数学性质,有助于更稳定地进行模型优化。


相比之下,均方误差(MSE)损失函数更适用于回归问题,其中目标是预测连续数值而不是类别。MSE损失函数度量预测值与真实值之间的差异的平方,适用于连续数值的回归问题。在分类问题中使用MSE损失函数可能不太合适,因为它对概率的微小差异不够敏感,而且在分类问题中通常需要使用激活函数(如 sigmoid 或 softmax)将输出映射到概率空间,使得 MSE的数学性质不再适用。


综上所述,交叉熵损失函数更适合分类问题,而MSE 损失函数更适合回归问题。


6.什么是信息增益

信息增益是在决策树算法中用于选择最佳特征的一种评价指标。在决策树的生成过程中,选择最佳特征来进行节点的分裂是关键步骤之一,信息增益可以帮助确定最佳特征。


信息增益衡量了在特征已知的情况下,将样本集合划分成不同类别的纯度提升程度。它基于信息论的概念,使用来度量样本集合的不确定性。具体而言,信息增益是原始集合的与特定特征下的条件熵之间的差异。


在决策树的生成过程中,选择具有最大信息增益的特征作为当前节点的分裂标准,可以将样本划分为更加纯净的子节点。信息增益越大,意味着使用该特征进行划分可以更好地减少样本集合的不确定性,提高分类的准确性。

7.多分类的分类损失函数(Softmax)

多分类的分类损失函数采用 Softmax 交叉熵(Softmax Cross Entropy,损失函数。Softmax函数可以将输出值归一化为概率分布,用于多分类问题的输出层。Softmax 交叉熵损失函数可以写成:

8.softmax 和交叉熵损失怎么计算,二值交叉呢

softmax计算公式如下:

多分类交叉熵:

二分类交叉熵:

9.如果 softmax的e次方超过 float 的值了怎么办

将分子分母同时除以x中的最大值:




七.相似度函数

1.除了cosin还有哪些算相似度的方法

除了余弦相似度(cosine similarity)之外,常见的相似度计算方法还包括欧氏距离、曼哈顿距离、Jaccard相似度、皮尔逊相关系数等。

2.对比学习

对比学习是一种无监督学习方法,通过训练模型使得相同样本的表示更接近,不同样本的表示更远离,从而学习到更 好的表示。对比学习通常使用对比损失函数,例如Siamese网络、Triplet网络等,用于学习数据之间的相似性和差异 性。

3.对比学习负样本是否重要?负样本构造成本过高应该怎么解决?
对比学习中负样本的重要性取决于具体的任务和数据。负样本可以帮助模型学习到样本之间的区分度,从而提高模型 的性能和泛化能力。然而,负样本的构造成本可能会较高,特别是在一些领域和任务中。为了解决负样本构造成本过高的问题,可以考虑以下方法:
• 降低负样本的构造成本:通过设计更高效的负样本生成算法或采样策略,减少负样本的构造成本。例如,可以利用 数据增强技术生成合成的负样本,或者使用近似采样方法选择与正样本相似但不相同的负样本。 
• 确定关键负样本:根据具体任务的特点,可以重点关注一些关键的负样本,而不是对所有负样本进行详细的构造。这样可以降低构造成本,同时仍然能够有效训练模型。 
• 迁移学习和预训练模型:利用预训练模型或迁移学习的方法,可以在其他领域或任务中利用已有的负样本构造成 果,减少重复的负样本构造工作。

英熊学长会不定期发布相关设计内容包括但不限于如下内容:信号处理、通信仿真、算法设计、matlab appdesigner,gui设计、simulink仿真......希望能帮到你!有任何matlab和python相关的问题都可以在后台滴滴小英熊学长欧~

 

点下【在看】给小编加鸡腿

MatpyMaster
Matlab、Python程序定制。擅长专业:电子信息、通信工程、人工智能、电子电力。可进行算法复现,论文复现,如有需要加V:Matpy_Master
 最新文章