大模型必知必会的问题及答案

以问题为导向来检验自己学习的效果。以下是一些大模型必知必会的问题,快来检查一下掌握程度吧~

数据预处理

1.什么是 BPE?它如何工作?

Byte Pair Encoding (BPE),又称 digram coding 双字母组合编码,是一种数据压缩 算法,用来在固定大小的词表中实现可变⻓度的子词。该算法简单有效,因而目前它是最流行的方法。

2.BPE工作原理?

合并:找到数据集中最频繁的字符对,将其合并为一个新单元。
重复:迭代上述过程,直到达到预设的合并次数。
输出:生成固定大小的子词词表,可以覆盖高频词和罕见词。

过程如下:

1.将每个词拆分为字符序列,并统计每个字符出现的频次,

2.将最高频的两个字符组合在一起,形成新的’组合字符’(频次为两个字符同时出现的频次a),同时原来的两个字符频次减去a.

3.重复第二个步骤直到,直到词表中单词数达到设定量 或下一个最高频数为 1 ,如果已经打到设定量,其余的词汇直接丢弃。

3.BPE 优缺点?

优点

  • 有效地平衡词典大小和将预料编码所需要的token数量

  • 不同语种通用

  • 对于未知单词也适用

缺点

  • 就是会产生一些不完整的单词(subword)
  • 适合欧美语言拉丁语系,不适合中文汉字,中文的处理通常只有分词和分字。

4.什么是 Tokenization?NLP 中常见的 Tokenization 方法有哪些?

在解释Tokenization之前,先说说什么是Token。Token,也称为标记或词元,是语言处理中的一个基本单元。它通常代表一个单词、标点符号或一个特定的符号序列。Token是文本的基本组成单元,用于表示文本中的有意义的语言元素。例如,“Hello, world!”这个句子可以被划分为多个Token:“Hello”、“,”、“world”和“!”。

Tokenization是将连续的文本分割成一个个独立的Token的过程。它是NLP中的一项基础任务,通常在文本预处理阶段完成。Tokenization的目的是将文本分解成更小的、易于处理和分析的单元,以便于后续的词法分析、句法分析等任务。

Tokenization 常用方法:

词粒度:就跟人类平时理解文本原理一样,常常用一些工具来完成,例如英文的NLTK、SpaCy,中文的jieba、LTP等。

字粒度:英文就是以字母为单位(对于大小写不敏感的任务,甚至可以先转小写再切分),中文就是以字为单位。

Subword粒度:

  • BPE
  • WordPiece
  • ULM

ULM算法:

它不是从一组基本符号开始,而是从一个庞大的词汇量开始,例如所有预处理的单词和最常见的子字符串,并逐步减少。

  1. 准备足够大的语料库
  2. 定义好所需要的词表大小
  3. 给定词序列优化下一个词出现的概率
  4. 计算每个subword的损失
  5. 基于损失对subword排序并保留前X%。为了避免OOV,保留字符级的单元
  6. 重复第3至第5步直到达到第2步设定的subword词表大小或第5步的结果不再变化。

WordPiece算法:

WordPiece最初用于解决日语和韩语语音问题。它在许多方面类似于BPE,只是它基于可能性而不是下一个最高频率对来形成一个新的子词。算法步骤如下:

  1. 用文本中的所有字符初始化词单元库。
  2. 使用第一步中的库在训练数据上构建一个语言模型
  3. 通过结合当前词库中的两个单元来生成一个新的词单元,从而使词单元库增加一个
  4. 在所有可能的新词单元中选择一个,当添加到模型中时,它能最大程度地提高训练数据的可能性
  5. 重复第二步,直到达到预定义的词单元限制或可能性增加低于某个阈值。
  6. 重复第5步直到达到第2步设定的subword词表大小或概率增量低于某一阈值
小结

简单几句话总结下Subword的三种算法:

  • BPE:只需在每次迭代中使用「出现频率」来确定最佳匹配,直到达到预定义的词汇表大小;
  • Unigram:使用概率模型训练LM,移除提高整体可能性最小的token;然后迭代进行,直到达到预定义的词汇表大小;
  • WordPiece:结合BPE与Unigram,使用「出现频率」来确定潜在匹配,但根据合并token的概率做出最终决定.

SentencePiece 是一个由谷歌开发的开源文本处理工具,它主要用于神经网络文本生成系统中的无监督文本分词(tokenization)和合词(detokenization)。这个工具的核心思想是将文本分词问题视为一个无监督学习问题,它不依赖于语言特定的预处理或后处理。

5.Tokenization 的选择对模型训练有什么影响?

  • 词表大小

大词表(如 Word-based Tokenization):
优点:训练更快,序列长度较短。
缺点:内存占用大,OOV 问题严重。
小词表(如 Subword 或 Character-based Tokenization):
优点:内存占用小,泛化性更好。
缺点:序列长度增加,计算成本提高。

  • 序列长度

较短的序列(如 Word-based):
计算效率更高。
较长的序列(如 Character-based):
提高对细粒度信息的处理能力,但增加了计算开销。

  • OOV 问题

Word-based Tokenization:
对未登录词无法处理,会丢失信息。
Subword 或 Character-based Tokenization:
通过拆分单词解决 OOV 问题,提高泛化能力。

  • 训练效率

复杂的 Tokenization(如 BPE 或 WordPiece):
需要较大的预处理时间,但训练更加稳定。
简单的 Tokenization(如 Character-based):
初始处理快,但序列长度显著增加,导致训练时间变长。

  • 模型泛化能力

Subword-based Tokenization 通常在泛化能力和训练效率之间实现了较好的平衡。
Character-based Tokenization 能够捕获更细粒度的信息,但在小数据集下可能不足以学习高层语义

模型细节

1.多头注意力的时间复杂度?空间复杂度?

复杂度

对于一个由n个单词组成的输入序列,假设有d个维度的特征,那么查询矩阵、键矩阵和值矩阵的维度都将是 n × d。

阅读 Transformer 相关的论文,在讨论 self-attention 的时间和空间复杂度时,都会提到是
$O(N^2)$,其中 $N$ 是序列长度。

我们来看下 $\textbf{scaled dot-product attention}$ 的时间和空间复杂度:

$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T}{\sqrt{d}}\right)$

为了分析时间和空间复杂度,我们把上述的计算过程拆分为:
$
S = Q K^T, \quad S = \frac{S}{\sqrt{d}}, \quad S V.
$

只要我们分析出每个计算的复杂度,就可以得到整体计算的复杂度。

我们先来看第一个矩阵乘法 $QK^T$,$Q \in \mathbb{R}^{N \times d}$, $K \in \mathbb{R}^{N \times d}$,矩阵乘法的朴素算法时间复杂度是:
$
O(N \cdot d \cdot N) = O(N^2 \cdot d)
$,代码实现其实就是三个for循环。

至于空间复杂度,只有存储 $QK^T$ 计算结果,复杂度是:
$O(N^2)$
但是也不要觉得这个数字很大,如果 $N < d$,其实存储 $Q$ 和 $K$ 要比 $QK^T$ 更占内存(显存)。除非序列很长 $N > d$,空间复杂度 $O(N^2)$ 才会是瓶颈。

2.为什么要用位置编码?

位置编码提供了位置信息,使 Transformer 能够捕捉序列的顺序关系,从而更有效地理解上下文依赖

3.为什么要用多头注意力?手写多头注意力代码?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import math
import torch
import torch.nn as nn
import torch.nn.functional as F

# 定义一个 MultiHeadAttention 类,它继承自 nn.Module
class MultiHeadAttention(nn.Module):
def __init__(self, heads, d_model, dropout=0.1):
# 调用父类的构造函数
super().__init__()
# 保存模型维度和头数
self.d_model = d_model
self.d_k = d_model // heads # 每个头对应的维度
self.h = heads # 头的数量

# 初始化线性层,用于将输入转换为查询(Q)、键(K)和值(V)
self.q_linear = nn.Linear(d_model, d_model)
self.k_linear = nn.Linear(d_model, d_model)
self.v_linear = nn.Linear(d_model, d_model)
# 初始化Dropout层,用于正则化
self.dropout = nn.Dropout(dropout)
# 初始化输出线性层,用于将多头注意力输出转换为模型维度
self.out = nn.Linear(d_model, d_model)

# 定义注意力机制的计算过程
def attention(self, q, k, v, mask=None):
# 计算Q和K的矩阵乘积,然后除以根号下d_k
scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.d_k)
# 如果提供了掩码,则将掩码对应的位置设置为负无穷,这样在softmax后这些位置的值为0
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
# 应用softmax函数获得注意力权重
scores = F.softmax(scores, dim=-1)
# 应用dropout
scores = self.dropout(scores)
# 将注意力权重和V相乘得到输出
output = torch.matmul(scores, v)
return output

# 定义前向传播过程
def forward(self, q, k, v, mask=None):
batch_size = q.size(0)
# 将输入Q、K、V通过线性层,并调整形状以进行多头注意力计算
q = self.q_linear(q).view(batch_size, -1, self.h, self.d_k).transpose(1, 2)
k = self.k_linear(k).view(batch_size, -1, self.h, self.d_k).transpose(1, 2)
v = self.v_linear(v).view(batch_size, -1, self.h, self.d_k).transpose(1, 2)
# 计算注意力输出
scores = self.attention(q, k, v, mask)
# 将多头输出合并,并调整形状以匹配模型维度
concat = scores.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
# 通过输出线性层
output = self.out(concat)
return output

# 主函数,用于测试 MultiHeadAttention 类
if __name__ == "__main__":
# 初始化模型参数
heads = 4
d_model = 128 # d_model应该是heads的整数倍。
dropout = 0.1

# 创建 MultiHeadAttention 实例
model = MultiHeadAttention(heads, d_model, dropout)

# 创建随机数据作为输入
batch_size = 2
seq_len = 5
q = torch.rand(batch_size, seq_len, d_model) # Query
k = torch.rand(batch_size, seq_len, d_model) # Key
v = torch.rand(batch_size, seq_len, d_model) # Value

# 执行前向传播
output = model(q, k, v)

# 打印输出形状,应该是 [batch_size, seq_len, d_model]
print("Output shape:", output.shape)

# 检查模型是否可以进行反向传播
loss = output.mean() # 创建一个简单的损失函数
loss.backward() # 执行反向传播
print("Backward pass completed.") # 如果没有错误,则表示反向传播成功

4.多头注意力的优化方式?

优化

共用KV Cache(MQA和GQA):

MQA(Multi Query Attention)多查询注意力是MHA多头注意力的变体。两者主要区别是MQA中不同头共享一组KV,每个头只保留查询参数Q。KV矩阵只有一份,大幅减少内存。
由于MQA改变注意力机制结构,模型需要从训练开始就支持MQA,或通过对已训练好的模型微调支持MQA,仅需约5%的原始数据量即可达到不过效果。Falcon、SantaCoder、StarCoder 等模型都采用了MQA机。

GQA (Grouped Query Attention,分组查询注意力),介于MHQ和MQA之间的折中方案。按查询头Q分组,每个组共享一个K和V。表达能力与推理性能兼顾。

5.各种Norm介绍和解释?

6.BERT使用的编码?
7.BERT的loss?
8.BERT的架构?

9.BERT,GPT等比较主流大模型,一些细节,比如位置编码,训练loss,激活,架构些许不同这种。自回归重点

框架相关内容

各种并行方式,优缺点。DeepSpeed,Megatron可以看看源代码,Flash-Attention等内容。这个点也经常考代码题。

1.并行方式有哪些?

  • 数据并行

​ 所谓数据并行,就是由于训练数据集太大;因此,将数据集分为N份,每一份分别装载到N个GPU节点中,同时,每个GPU节点持有一个完整的模型副本,分别基于每个GPU中的数据去进行梯度求导。然后,在GPU0上对每个GPU中的梯度进行累加,最后,再将GPU0聚合后的结果广播到其他GPU节点。

  • 流水线并行

    所谓流水线并行,就是由于模型太大,无法将整个模型放置到单张GPU卡中;因此,将模型的不同层放置到不同的计算设备,降低单个计算设备的显存消耗,从而实现超大规模模型训练。 如下图所示,模型共包含四个模型层(如:Transformer层),被切分为三个部分,分别放置到三个不同的计算设备。即第 1 层放置到设备 0,第 2 层和第三 3 层放置到设备 1,第 4 层放置到设备 2。

  • 张量并行

    和流水线并行类似,张量并行也是将模型分解放置到不同的GPU上,以解决单块GPU无法储存整个模型的问题。和流水线并行不同的地方在于,张量并行是针对模型中的张量进行拆分,将其放置到不同的GPU上。

    模型并行是不同设备负责单个计算图不同部分的计算。而将计算图中的层内的参数(张量)切分到不同设备(即层内并行),每个设备只拥有模型的一部分,以减少内存负荷,我们称之为张量模型并行

数据并行 vs 张量并行 vs 流水线并行?
数据并行、张量并行和流水线并行是在并行计算中常见的三种策略,它们有不同的应用场景和优势:

1、数据并行(Data Parallelism):

概念: 数据并行是指将整个模型复制到每个处理单元上,不同处理单元处理不同的数据子集。每个处理单元独立计算,并通过同步更新模型参数来实现训练。
适用场景: 数据并行适用于大型模型和数据集,特别是在深度学习中。每个处理单元负责计算不同数据子集上的梯度,然后同步更新模型参数。
优势: 易于实现,适用于大规模数据和模型。
2、张量并行(Tensor Parallelism):

概念: 张量并行是指将模型分解成多个部分,每个部分在不同处理单元上进行计算。通常,这涉及到在层与层之间划分模型,并在不同的 GPU 或处理单元上执行这些部分。
适用场景: 张量并行适用于非常大的模型,其中单个 GPU 的内存容量无法容纳整个模型。它允许将模型的不同部分分配到不同的处理单元上,从而扩展模型的规模。
优势: 适用于大型模型的规模扩展,可用于解决内存限制问题。
3、流水线并行(Pipeline Parallelism):

概念: 流水线并行是指将模型的不同层分配到不同的处理单元上,并通过将不同层的输出传递给下一层来实现计算。每个处理单元负责一个模型层的计算。
适用场景: 流水线并行适用于深层次的模型,其中各层之间的计算相对独立。它可以提高模型的整体计算速度,特别是在层之间存在较大的计算延迟时。
优势: 适用于深层次模型,减少整体计算时间。
这三种并行策略通常可以结合使用,具体取决于应用的场景和问题的性质。在深度学习等领域,常常会使用数据并行和张量并行相结合的方式,以提高模型的训练速度和规模。

4、3D并行,或者混合并行 (Hybrid Parallelism)

则是将以上三种策略结合起来使用,达到同时提升存储和计算效率的目的。Megatron-Turing NLG 就是先将 Transformer block 使用流水线和张量 2D 并行,然后再加上数据并行,将训练扩展到更多的GPU。

2.如果有N张显存足够大的显卡,怎么加速训练?

数据并行化 在数据并行化中,模型的多个副本在不同的 GPU 上训练相同的数据批次。每个 GPU 计算梯度,并将结果汇总到主 GPU 或进行参数更新。这种方法适用于模型过大而无法完全容纳在单个 GPU 内存中的情况。

模型并行化 在模型并行化中,模型的不同部分分配到不同的 GPU 上。每个 GPU 负责计算其分配的部分,并将结果传递给其他 GPU。这对于大型模型,特别是具有分层结构的模型(如大型神经网络)是有益的。

分布式训练 使用分布式框架(例如 TensorFlow 的 tf.distribute 或 PyTorch 的 torch.nn.parallel.DistributedDataParallel)来实现训练任务的分布式执行。这允许将训练任务分配到多个 GPU 或多台机器上进行加速。

优化批处理大小 增大批处理大小可以提高 GPU 利用率,但需要注意的是,批处理大小的增加也可能导致内存不足或梯度下降不稳定。因此,需要根据模型和硬件配置进行合理的调整。

混合精度训练 使用半精度浮点数(例如 TensorFlow 的 tf.keras.mixed_precision 或 PyTorch 的 AMP)来减少内存占用,加速训练过程。

模型剪枝和优化 对模型进行剪枝和优化以减少模型的大小和计算负荷,有助于提高训练速度和效率。

3.想要训练1个LLM,如果只想用1张显卡,那么对显卡的要求是什么?

显卡显存足够大,nB模型微调一般最好准备20nGB以上的显存。

4.如果显卡的显存不够装下一个完整的模型呢?

最直观想法,需要分层加载,把不同的层加载到不同的GPU上(accelerate的device_map)也就是常见的PP,流水线并行

4.常见的分布式训练框架哪一些,都有什么特点?

1、Megatron-LM

Megatron 是由 NVIDIA 深度学习应用研究团队开发的大型 Transformer 语言模型,该模型用于研究大规模训练大型语言模型。

Megatron 支持transformer模型的模型并行(张量、序列和管道)和多节点预训练,同时还支持 BERT、GPT 和 T5 等模型。

2、DeepSpeed

DeepSpeed是微软的深度学习库,已被用于训练 Megatron-Turing NLG 530B 和 BLOOM等大型模型。

DeepSpeed的创新体现在三个方面:

训练,推理,压缩
DeepSpeed具备以下优势:

训练/推理具有数十亿或数万亿个参数的密集或稀疏模型
实现出色的系统吞吐量并有效扩展到数千个 GPU
在资源受限的 GPU 系统上训练/推理
为推理实现前所未有的低延迟和高吞吐量
以低成本实现极致压缩,实现无与伦比的推理延迟和模型尺寸缩减

5.Flash-Attention?

模型训练

这个可能主要是工作经验相关,经常问比如训练loss炸掉了,如何解决,一些技巧之类的。面试时有些面试官会问一些很细节的东西,感觉是在确认确实上手跑过基座训练不是吹水。

模型评估

如何评估大模型,安全性,有效性,公开数据,个别考过手写eval框架(多选,生成)。

ChatbotArena:借鉴游戏排位赛机制,让人类对模型两两评价
SuperCLUE:中文通用大模型综合性评测基准,尝试全自动测评大模型
C-Eval:采用 1.4 万道涵盖 52 个学科的选择题,评估模型中文能力
FlagEval:采用“能力—任务—指标”三维评测框架

参考:https://zhuanlan.zhihu.com/p/448147465


觉得不错的话,支持一根棒棒糖吧 ୧(๑•̀⌄•́๑)૭



wechat pay



alipay

大模型必知必会的问题及答案
http://yuting0907.github.io/posts/b3b6ea6b.html
作者
Echo Yu
发布于
2025年1月16日
许可协议