Files
Obsidian/博客/AI与大模型/大语言模型算子详解.md
T

287 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 大语言模型算子详解:学术版 + 白话版
> **注!** 本文专业名词较多,对于各位同学我推荐先阅读白话版再阅读学术版。
---
## 📚 学习本文有什么用?
- 文章拆解到算子级别,有利于做模型部署/推理优化
- 有助于算法研究与模型设计
- 这是大模型 infra/算法岗的高频考点
---
# 第一部分:学术版
> 以 Qwen2.5-32B 大语言模型为例,将大语言模型的所有算子梳理一遍,并描述大模型推理的整个过程。
> **名词解释:**
> - **Qwen2.5-32B**:阿里巴巴通义千问团队开源的大语言模型,32B 表示 320 亿参数。"B" 是 Billion(十亿)的缩写
> - **算子梳理**:把模型推理涉及的每个计算步骤都列出来并解释
> - **推理的整个过程**:注意区分"训练"和"推理"。训练是模型学习的过程,推理是模型已经学好了,你给它输入,它给你输出的过程
---
大语言模型的底层算力,全部由算子承载。算子是模型推理/训练的最小执行单元,LLM 回答问题、学习知识,本质都是算子在做数学运算,没有算子就无法运行。
> **LLM 的最小执行单元** = 不可再拆分的运算步骤,如"两个矩阵相乘"就是 1 个算子。
## 一、整体流程概览
下图是完整流程:
![](https://com.miui.notes/note_image/59dd31e5e9566477ab18400de49530651908fe8b)
> ⚠️ 把图片下载下来!对着文字来读来看
其中:
- **B** 表示 Batch(批次)数,表示同时输入了多少个请求
- **S** 表示输入请求的 Sequence Length(序列长度)
> **名词解释:**
> - **Batch(批次)**:同时处理多少个请求。比如 Batch=4,就是同时给模型输入 4 句话
> - **Sequence Length(序列长度)**:每个请求有多少个 token。比如 "I like shanghai" 有 4 个 tokenI、like、shanghai,加上可能的起始 token
### 流程步骤
#### 步骤 1:输入 Prompt
一开始输入的是 B 个 Prompts,由一个个的 Token 组成,每个 Prompt 的 Token 个数为 S,比如 "I like shanghai" 等。
> **名词解释:**
> - **Prompt**:你给模型的输入提示/问题
> - **Token**:大模型处理文本的最小单位。注意不是按空格分词!比如 "shanghai" 可能是一个 token,但 "unbelievable" 可能被拆成 "un"、"believ"、"able" 三个 token。这取决于 Tokenizer 的训练方式
#### 步骤 2Token 编码
经过 Tokenizer 的 Encode 操作会将输入的所有 Token 转换成 Token ID。Token ID 我们可以理解为这个 Token 在词表中的索引。Qwen2.5-32B 的词表大小为 152064。
> **名词解释:**
> - **Tokenizer(分词器)**:负责把人类文字转换成模型能理解的数字。它有两个方向:
> - **Encode(编码)**:文本 → Token ID
> - **Decode(解码)**Token ID → 文本
> - **词表(Vocabulary**:模型认识的所有 token 的集合。每个 token 对应一个唯一 ID
> - **152064**Qwen2.5 的词表大小。这意味着模型输出时,每次要从 15 万多个候选中选下一个 token
#### 步骤 3Embedding
经过 Embedding 操作之后得到输入每个 Token 的特征向量,这个向量是模型训练的结果。
> **名词解释:**
> - **Embedding(嵌入)**:把离散的 Token ID 转换成连续的向量
> - **为什么需要 Embedding?** 因为神经网络处理的是数字,而 Token ID 只是索引(比如 ID=5231),不代表语义。Embedding 把每个 token 映射到一个高维空间(这里是 5120 维),语义相近的 token 在这个空间中距离也近
> - **"模型训练的结果"**:这些向量不是随机生成的,是模型在训练过程中学习到的
#### 步骤 4Transformer 处理
再经过如上图的 64 个 Layer 的 Transformer 模块的循环处理,后再做一次 RMSNorm 得到最终的 Hidden States。
> **名词解释:**
> - **64 个 Layer**Qwen2.5-32B 有 64 层 Transformer。层数越多,模型越深,能力通常越强
> - **Transformer**2017 年 Google 提出的架构,是当今大模型的基础。核心是自注意力机制(Self-Attention
> - **Hidden States(隐藏状态)**:数据在模型内部流动时的中间表示。可以理解为模型对当前输入的"理解"
> - **RMSNorm**:一种归一化方法,后面会详细讲
#### 步骤 5Token 预测
再经过 Token Linear(论文里面一般也叫:LM Head),得到每个输入请求的输出 Token ID。
> **名词解释:**
> - **Token Linear / LM HeadLanguage Model Head**:最后一层线性变换,把 Hidden States 映射到词表空间(152064 维),得到每个候选 token 的分数
#### 步骤 6Token 解码
再经过 Tokenizer 的 Decode 得到真正的 Token,这样就能完成整个 Prompt 输入再到 Token 输出的全流程推理。
> **名词解释:**
> - 这是**自回归生成**的过程——模型输出一个 token 后,把这个 token 拼回输入,再预测下一个 token,循环往复直到生成结束
---
## 二、算子详解
### Embedding 算子
如上图,Embedding 算子其实是一个 Gather 操作,他将输入的 Token ID 映射成一个 Embedding 的向量。
> **名词解释:**
> - **Gather 操作**:在编程中,Gather 就是"按索引取值"。比如词表是一个 [152064, 5120] 的矩阵,输入 Token ID=100,就取第 100 行的 5120 个数
**重要提醒:** 不是矩阵乘法!而是简单的查表(lookup)。但因为要处理大量 token,所以也需要优化。
**逻辑:** 遍历每个 Token ID,找到 Token ID 在 152064 中位置,取 Embedding Weight 中 Token ID 位置的 5120 个数据,复制到输出内存中。
> **名词解释:**
> - **Embedding Weight**:形状为 [词表大小, 隐藏维度] = [152064, 5120] 的参数矩阵。每个 token 被映射为一个 5120 维的向量
---
### RMSNorm 算子
取某个 Batch,某个请求的 5120 个特征向量,做 RMSNorm 操作。RMSNorm 公式为图中所示,d=5120。
> **名词解释:**
> - **Norm(归一化)**:让数据分布更稳定,帮助模型训练/推理更稳定
> - **RMSNormRoot Mean Square Normalization**:比 LayerNorm 更简单,去掉了均值计算,只保留方差归一化。做完图中公式的计算,得到输出的 5120 个数据 {y₀, y₁, ..., y₅₁₁₉}
> - **RMSNorm 是对每个 token 的向量单独做的,不是跨 batch 或跨 token**
---
### Multi Head Attention(多头注意力)
该模块的详细算子计算流程,见:[Attention 模块算子逻辑]()。
> **名词解释:**
> - **Multi-Head AttentionMHA**Transformer 的核心。把输入分成多组(头),每组独立计算注意力,最后拼接
> - **注意力机制**:计算 Query 和 Key 的相似度,决定 Value 的加权组合。通俗说就是"当前 token 应该关注哪些其他 token"
> - **GQAGrouped Query Attention**Qwen2.5 用的优化版,多个 Query 头共享一组 Key/Value 头,减少内存和计算
---
### Add 算子
如上图,对于两个输入数据,对应 Batch、对应请求、对应位置的元素相加就是 Add 算子逻辑。
> **名词解释:**
> - 这就是**残差连接(Residual Connection**`output = F(x) + x`
> - **作用**:缓解梯度消失,让深层网络更容易训练。在 Transformer 中,每个子层(Attention/MLP)后都有 Add
> - **ResNet 网络就是残差链接**,Kimi 最新提出了残差注意力机制,这是最新热点
---
### MLP 算子
该模块的详细算子计算流程,见:[MoE 模块的算子逻辑](),其中每个专家就是一个 MLP。
> **名词解释:**
> - **MLPMulti-Layer Perceptron**:多层感知机,即前馈神经网络。在 Transformer 中通常是两个线性层夹一个激活函数(如 SwiGLU)
> - **MoEMixture of Experts**:混合专家模型。Qwen2.5-32B 不是纯 Dense 模型,而是把 MLP 替换成多个"专家"网络,每次只激活部分专家。这能在不增加推理成本的情况下扩大模型容量
---
### Token-LinearLM-Head)算子
如上图,Token Linear 其实是一个矩阵乘,乘完之后得到每个请求的输出与词表中所有 Token 的近似程度。
> **名词解释:**
> - **矩阵乘法**`[batch×seq_len, hidden_dim] × [hidden_dim, vocab_size]`
> - **输出形状**`[batch×seq_len, 152064]`,即每个位置对每个 token 的"分数"
> - 这个过程我们可以理解为 Embedding 的逆向过程,因此有模型将 Embedding 权重与 Token Linear 权重共享
> - **权重共享**:输入 Embedding 和输出 LM Head 可以共用同一个权重矩阵。这是 GPT 系列的做法,减少参数量,且 empirically 效果不差
---
### Sample 模块:Softmax/Argmax
如上图,采样模块其实有挺多复杂操作,比如 Top-K、Top-P、惩罚项、温度等,后续做专题介绍。
> **名词解释:**
> - **Top-K**:只保留分数最高的 K 个候选,其余置零
> - **Top-PNucleus Sampling**:保留累积概率达到 P 的最小集合
> - **Temperature(温度)**:控制分布的"尖锐"程度。T→0 时接近贪婪,T 大时更随机
> - **惩罚项**:比如重复惩罚,避免模型一直重复同一个词
#### 最简单的采样逻辑
这里介绍一种最简单的逻辑,让整个推理闭环:
1. Token-Linear 输出的是 Token 落在词表中所有 Token 位置的近似程度(一般叫 Logits)
> **Logits**:神经网络的原始输出分数,未归一化,可正可负
2. 对其做 SoftMax 操作转换成概率,再取概率最大的 Token ID(索引),再去 Tokenizer Decode 就能得到最终的 Token
> - **Softmax**:把 logits 转换成概率分布(0~1 之间,和为 1)
> - **Argmax**:取最大值的索引。这是贪婪解码(Greedy Decoding),每次选概率最高的 token
3. 实际应用中还会用 Beam Search 等更复杂的解码策略
---
# 第二部分:白话版
## 核心概念
- **B** 就是 Batch 数,说白了就是"同一时间,有多少人在给这个模型发问题"
- **S** 就是输入请求的 Sequence Length,简单说就是"你发的那句话,被拆成了多少个最小的字或词块"
## 整体流程(白话版)
1. **输入问题**:一开始,模型会收到 B 个问题(也就是大家常说的 Prompt),每个问题都是由一个个最小的字或词块(Token)组成的,每个问题有多少个这样的小块,就是 S。比如 "I like shanghai" 这句话,就被拆成了 3 个这样的小块
2. **分词编码**:然后经过 Tokenizer(说白了就是分词、转码的工具)的 Encode(编码)操作,会把所有输入的字或词块(Token),都转换成一串数字编号(也就是 Token ID)。这个数字编号很好理解,就相当于这个字或词在模型"字典"里的页码,查这个页码就能找到对应的字或词。Qwen2.5-32B 的"字典"里,一共收录了 152064 个不同的字、词或符号
3. **理解语义**:再经过 Embedding(嵌入)操作,每个字或词块(Token)都会对应上一串数字(也就是语义向量)。这串数字不是随便来的,是模型之前经过大量训练学出来的,代表着这个字或词的意思,就相当于给每个字、每个词都贴了一个"意思标签",让模型能看懂它
4. **深度处理**:接着,这串代表意思的数字,会经过 64 层 Transformer 模块——这个模块就相当于模型的"大脑",会一层一层地琢磨、处理这些数字,把你的问题彻底看懂。处理完之后,再做一次 RMSNorm 操作,得到的就是模型"完全看懂你问题"后的结果(Hidden States
5. **预测下一个字**:之后,再经过 Token Linear(论文里叫 LM Head,不用管这个名字,知道它是负责预测下一个字的就行),就能算出每个问题接下来最可能出现的字或词的数字编号(也就是输出 Token ID)
6. **生成回答**:最后,再经过 Tokenizer 的 Decode(解码)操作,把算出来的数字编号,再转成我们能看懂的文字,这样就完成了"你发问题→模型给回答"的整个过程
---
## 算子详解(白话版)
### A. Embedding 算子
就像上图显示的那样,Embedding 算子其实就是一个简单的"查表"操作,专业上叫 Gather,说白了就是查字典,它的作用就是把前面得到的数字编号(Token ID),转换成对应的、代表意思的数字串(语义向量)。
说得再简单点:**一个一个看每个数字编号(Token ID),找到它在模型"字典"(152064 个词)里的位置,然后从模型提前存好的"意思数字表"Embedding Weight)里,把这个位置上的 5120 个数字,复制到指定的地方,这样就得到了这个字或词对应的、代表意思的数字串。**
---
### B. RMSNorm 算子
拿某个用户的问题对应的 5120 个代表意思的数字,做 RMSNorm 操作——说白了就是把这些数字调整得更均匀。RMSNorm 的公式就是上图里的,其中 d=5120。
具体怎么做呢?就是把这 5120 个数字,按照上图的公式算一遍,算完之后还是 5120 个数字。这么做的目的,就是让这些数字大小差不多,不会有的特别大、有的特别小,这样模型计算的时候才不会出问题,能稳定运行。
---
### C. Multi Head Attention
这个模块具体是怎么计算的(里面的算子怎么工作),大家可以去看:[Attention 模块算子逻辑 - 知乎](),里面讲得很详细。
我简单跟大家补一句:这部分是模型最核心的"大脑",主要作用就是看懂你问题的上下文——比如你说"他喜欢吃苹果,他也喜欢吃梨",模型能知道两个"他"是同一个人;还能判断哪个词更重要,从好几个角度去理解你说的话。
---
### D. Add 算子
就像上图显示的那样,Add 算子特别简单,一点不复杂:有两串数字,这两串数字要对应好——同一个用户、同一个问题、同一位置的数字,一一对应加起来就行,比如第一串的第一个数字加第二串的第一个数字,第二个加第二个,以此类推。
---
### E. MLP 算子
这个模块具体是怎么计算的(里面的算子怎么工作),大家可以去看:[MoE 模块的算子逻辑 - 知乎](),里面说的每个"小专家"(MoE 模块里的),其实就是一个 MLP。
我简单补一句:**MLP 的作用,就是把代表意思的数字串再加工一下,帮模型做逻辑推理。** 比如你说"我喜欢上海",模型就能通过 MLP 琢磨出"上海是大城市,所以我可能也喜欢大城市"。
---
### F. Token-LinearLM-Head)算子
就像上图显示的那样,Token Linear 其实就是做一次简单的数字矩阵相乘,算完之后,就能知道每个问题接下来的字,和模型"字典"里所有字、词的匹配程度(专业上叫 Logits,不用记这个名字)。
这个过程大家可以简单理解成,和前面的 Embedding 算子**反过来做**
- Embedding 是把"文字"变成"代表意思的数字串"
- Token Linear 是把"代表意思的数字串"变成"和每个文字的匹配程度"
所以很多模型会把这两个步骤用到的"数字表"(权重)共用,这样能节省空间,让模型运行得更高效。
---
### G. Sample 模块:Softmax/Argmax
就像上图显示的那样,这个采样模块其实有不少复杂的操作,比如 Top-K、Top-P、重复惩罚、温度调节这些,这些我后面会专门写一篇文章跟大家讲。
这里先跟大家讲一个最简单的逻辑,帮大家搞明白,从"匹配程度"到"最终回答",到底是怎么来的:
1. 前面我们说过,Token-Linear 算出来的,是"下一个字和模型字典里所有字、词的匹配程度"
2. 我们再做一次 SoftMax 操作,把这个匹配程度转换成 0 到 1 之间的概率(所有概率加起来刚好是 100%)
3. 然后挑出概率最大的那个字或词的数字编号(用 Argmax 操作,不用记名字,知道是挑概率最大的就行)
4. 再通过 Tokenizer 的 Decode 操作,把数字编号转换成我们能看懂的文字,这就是模型最终给你的回答了