← 返回首页
llm-from-scratch · 名词表 glossary

名词表 · 一句话讲清那些术语

各章节里出现的关键词,都在这里有一条简短、面向直觉的解释。正文中带虚线下划线的词, 鼠标悬停会弹出气泡,点"更多"就跳到这里对应词条。

张量batch嵌入 tokenizer缺省上下文长度 嵌入维度 logitssoftmax归一化 交叉熵梯度梯度消失 梯度清零优化器 自注意力Q/K/V点积 下三角因果掩码缩放 位置嵌入多头注意力SFT MLPFeedForwardReLU残差连接 LayerNormBlockDropout 前向传播采样自回归 prompttop_k贪心解码KV-cache 后训练偏好对齐全量微调 PEFTLoRAloss mask 对话模板DPORLHF BPEFineWeb-EdushardAdamWbf16Flash-Attention Attention Is All You Need
A基础概念

张量 tensor

多维数组,深度学习里数据的基本容器。标量是 0 维、向量 1 维、矩阵 2 维,再高维就统称张量。 形如 (B, T, C) 的数据就是一个 3 维张量:B 个序列 × 每序列 T 个位置 × 每位置 C 维向量。

batch / batch_size

一次喂给模型并行处理的一组样本。batch_size=32 表示一次处理 32 条序列。 批越大,梯度估计越稳,但越吃显存。注意它和"向量维度"是两码事 —— 一个是"几条样本",一个是"每个 token 几个数字"。

嵌入 embedding

把离散的 token(整数 id)映射成一个可训练的稠密向量nn.Embedding 本质是一张查找表: 第 i 行就是第 i 个 token 的向量。训练让语义相近的 token 拥有相近的向量。

分词器 tokenizer

把文本和数字互相转换的工具:encode 把字符串变成整数 id 序列,decode 反过来。 本项目用最简单的"字符级"切分 —— 每个字符一个 id。

缺省 / 默认参数 default argument

函数定义时给参数设的默认值,调用时不传就用它。例如 forward(self, idx, targets=None)targets 缺省为 None —— 只想前向出 logits、不算 loss 时,就不传 targets。

上下文长度 block_size / context length

模型一次能看到的最大 token 数block_size=8 意味着每个位置最多回看前 8 个字符; 更早的历史会被截断(generate 时要 idx[:, -block_size:])。这是注意力的"视野上限"。

嵌入维度 n_embd

每个 token 用多长的向量来表示,本项目 n_embd=32。它决定了 token_embedding、 位置表、Wq/Wk/Wv 的形状。⚠️ 本章里它和 batch_size、 head_size 数值都撞成 32,但含义完全不同:一个是"每个 token 几个数字(维度)", 一个是"一次几条句子",一个是"注意力头的输出宽度"。看到 32 先问"这是谁的 32"。

B损失与训练

logits

模型最后一层输出的、未经 softmax 的原始打分。可正可负,数值大小代表"倾向"; 过 softmax 后才变成概率。形状常见为 (B, T, vocab_size) —— 每个位置对词表里每个字符都打一个分。

softmax

把一组任意实数(打分)变成一组和为 1 的正数(概率分布):每个数取 exp 再除以总和。 分数越大,概率越大。它天生保证"每行加起来 = 1"。

归一化 normalize

把一组数按比例缩放,使其满足某种总量约束。本项目里特指"每行除以该行的和", 让每行加起来 = 1,从而变成一组权重(概率分布)。softmax 内部做的也是这件事。 它管的是"尺度",和"哪些位置为 0"(因果)是两件正交的事。

交叉熵 cross_entropy

分类任务的损失函数。先对 logits 做 softmax 得概率,取正确类别的概率 p, loss = -ln(p)。模型越确信正确答案(p→1),loss→0;越瞎猜,loss 越大。 随机初始时 loss ≈ ln(vocab_size)

梯度 gradient

loss 对每个参数的偏导数,指出"参数往哪个方向调、loss 下降最快"。 loss.backward() 负责把它算出来,优化器再据此更新参数。

梯度消失 vanishing gradient

梯度在传播中变得极小,参数几乎不更新、模型学不动。 softmax 过于"尖锐"(某一项概率接近 1)时就会发生 —— 这正是注意力要对分数做缩放的原因。

梯度清零 zero_grad

PyTorch 的梯度默认累加(backward 把新梯度加到旧的上)。所以每轮训练开头必须先 optimizer.zero_grad() 清零,否则会带着上一轮的陈旧方向越走越偏。 顺序:zero_grad → backward → step

优化器 optimizer / AdamW

拿到梯度后,真正决定"每个参数走多大一步"的算法。AdamW 是 Adam 的改良版(带权重衰减), 是当下训练 Transformer 的常用默认选择。lr(学习率)控制步子大小。

C注意力机制

自注意力 self-attention

序列内部每个位置,通过 query/key/value 机制, 按相关性从其它位置(因果设定下只看过去)聚合信息,得到融合了上下文的新表示。 "self"指 q、k、v 都来自同一个序列。

Q / K / V query / key / value

同一个输入经三个不同的线性投影得到的三种角色。query=我在找什么; key=我宣传自己是什么(被检索);value=你看我我给你什么(被取走的信息)。 用 query 比对所有 key 算出权重,再用权重聚合 value。

点积 dot product

两个等长向量对应元素相乘再求和,得到一个标量。结果越大,表示两向量方向越一致。 注意力用 q · k 来衡量"query 和 key 有多相关",作为关注分数。

下三角 lower-triangular / tril

一个方阵,对角线及其左下方保留,右上方全部为 0torch.tril 生成。 注意力用它做因果掩码:让第 i 个位置只能看到 0..i,看不到未来。 它管的是"哪些位置必须为 0"(结构),和归一化管的"尺度"互相独立。

因果掩码 causal mask

在注意力分数里,把"未来位置"设成 -∞,经 softmax 后它们权重变 0。 保证预测下一个字符时不能偷看答案。靠下三角实现: masked_fill(tril==0, -inf)

缩放 scaling (÷√d)

注意力把 q·k 的分数除以 √head_size。因为点积的方差随维度增大, 不缩放会让 softmax 过于尖锐、把权重几乎全压给一个位置,导致梯度消失。 除以 √d 把分数尺度拉回正常。

位置嵌入 positional embedding

因为注意力本身看不出顺序(打乱输入,输出只跟着打乱,权重不变), 所以额外给"第几个位置"也学一个向量,加到 token 嵌入上,模型才知道谁先谁后。 代码:x = tok_emb + pos_emb

多头注意力 multi-head attention

把注意力拆成若干个并行的:每个头在 n_embd 的一个子空间里独立 打分聚合(每头 head_size = n_embd / n_head 维),最后把各头输出拼接(cat)再过一个 proj 线性层融合,回到 n_embd。 要点:不是把模型加宽,而是把同一块 n_embd 切成几份 —— 切几份总料不变,显存/算力基本持平。 每个头会在训练中自发分化出不同专长(盯前一词、回看句首、配对括号…),没人指定; 这与 Q/K/V 那种"公式钦定"的分工不同。本项目第 3 关开始用。

SFT Supervised Fine-Tuning · 监督微调

预训练之后的一步:用「问 → 答」成对数据继续训练同一批参数(包括 Wq/Wk/Wv), 把模型调成"以助手口吻回答"的姿态。要点:"抓相关上下文"的能力是预训练就建好的,SFT 只是在上面拧风格 —— 它不会"激活" QKV 里某个为问答预留的用途(QKV 2017 年为翻译而生,SFT 2022 年才出现,不存在"提前挖坑")。 属于对齐阶段,本项目 Phase 2 才正式动手;这里先建立概念。

DTransformer 组件

MLP multi-layer perceptron · 多层感知机

最基础的神经网络:几层全连接(Linear)中间夹非线性(如 ReLU)。 "多层"指它不止一层线性变换。Transformer 里每个 BlockFeedForward 就是一个很小的 MLP (Linear → ReLU → Linear),负责对每个位置的向量单独"加工"。

FeedForward(FFN) 前馈网络

Transformer 层里的小 MLP:Linear(n_embd, 4·n_embd) → ReLU → Linear(4·n_embd, n_embd),中间放大 4 倍再压回。 它是逐位置(position-wise)的 —— 对每个 token 的向量单独加工,位置之间不交换信息。 分工:注意力让 token 互相"沟通",FFN 让每个 token 自己"思考"。

ReLU rectified linear unit · 激活函数

最常用的非线性激活函数:ReLU(x) = max(0, x),把负数清零、正数保留。 作用是给网络引入非线性 —— 没有它,多层 Linear 叠起来在数学上还是一个线性变换,层数白加。

残差连接 residual connection · skip connection

把子层的输出加回它的输入:x = x + 子层(x)。那个 + 是一条梯度高速公路, 反向传播时梯度能绕过子层直达底层,避免 梯度消失,深网络才堆得动。 子层只需学"在原信号上加什么修正"。出自 2015 年 ResNet,Transformer 全靠它。

LayerNorm 层归一化

每个位置那一根向量(沿特征维)做 归一化:减均值、除标准差,把数值拉回稳定范围,深网络训练才不发散。 它不跨位置、不跨 batch,与序列长度无关。pre-norm(先 norm 再进子层,x + 子层(ln(x)))比原始 Transformer 的 post-norm 更好训。

Block Transformer 层

Transformer 的一层 = 注意力子层 + FFN 子层,各自带 残差LayerNorm: x = x + sa(ln1(x)) 然后 x = x + ffwd(ln2(x))(沟通 + 思考)。 完整 GPT 就是把 n_layer 个 Block 摞起来。

Dropout 随机失活

训练时随机丢弃一部分连接(如 10%),逼网络别过度依赖某几条路径,防过拟合。 只在训练时生效,推理时关闭。模型变大后(第 3 关)容易死记硬背,所以加了它。

前向传播 forward pass

把输入从头到尾过一遍网络、算出输出的过程 —— 这里就是 idx → 嵌入 → Block×N → ln_f → lm_head → logits训练和推理都要做前向;训练还会接着反向传播更新权重,推理则到 logits 就停、拿去采样。

采样 sampling

按模型输出的概率分布随机抽一个 token 当下一个字符(代码 torch.multinomial(probs, 1)), 不是永远取最高分(argmax)。取最高分会陷入重复死循环;随机采样保多样,所以同一个开头每次生成都可能不同。

自回归 autoregressive

自己刚生成的字符接回输入,再预测下一个,如此循环。GPT 生成文本就是这样一个字一个字滚出来的: 每多一个字,就把整条序列重新做一次前向传播

prompt 提示词

喂给模型的开头文本base 模型不理解"任务",只会顺着 prompt 续写最可能的下一个 token —— 想让它"听懂指令答题"是 SFT 之后的事。

top_k 采样 top-k sampling

每步只保留概率最高的 k 个 token,其余打分置 −∞(概率 0)再归一化采样,把长尾低概率 token 一刀切掉,避免偶尔抽到离谱的词。默认 k=50。

贪心解码 greedy · argmax

每步直接取概率最高的 token,不掷骰子。结果唯一、可复现,但无多样性、易陷入复读死循环 —— 等价于 top_k=1。随机采样正是为了跳出这种死循环。

KV-cache 键值缓存

把过去每个 token 算出的 K/V 向量缓存下来,生成新 token 时只算新一列、复用历史,避免每步把整段注意力重算一遍。计算量从平方级降到线性,本项目实测推理提速约 2.5–3.1×。

G预训练工程(124M)

BPE 子词分词 · Byte-Pair Encoding

把文本切成子词单元的分词法,介于字符级和整词级之间。GPT-2 的 BPE 词表有 50257 个 token —— 本项目 124M 复现就用它(代码里向上取整到 50304,凑 128 的倍数更省 GPU)。

FineWeb-Edu 教育向网页语料

经过教育质量筛选的大规模英文网页语料,常用于预训练。本项目用其子集(300M / 10B token)做 GPT-2 124M 复现 —— 全英文,所以模型不会中文

shard 数据分片

把超大数据集切成的一块块文件(这里是 .npy),训练时一片片顺序读入,不必把整个 10B token 数据集一次塞进内存。

AdamW 带权重衰减的 Adam

优化器的事实标准:Adam 的改良版,把权重衰减从梯度里拆出来单独做。本项目用 betas=(0.9, 0.95),并对参数分组(权重给衰减、bias/LayerNorm 不给)。

bf16 混合精度 · bfloat16

16 位浮点。前向用它算更快、省一半显存,数值范围和 fp32 一样大、精度几乎无损 —— 大模型训练的常规操作。需要 N 卡支持。

Flash-Attention 省显存的注意力实现

注意力算得又快又省显存的实现(F.scaled_dot_product_attention):不显式构造 T×T 注意力矩阵,边算边融合。和普通注意力数学等价,只是更高效。

F后训练与对齐(Phase 2)

后训练 / 预训练 / 基座模型 post-training · pre-training · base model

预训练:在海量无标注文本上做"预测下一个 token",产出只会续写的基座模型(base model) —— Phase 1 做的就是这步。 后训练:在 base 之上继续调,让它"会听话":包括 SFT偏好对齐。 现代大模型 = 预训练 → SFT → 偏好对齐 一条流水线,后一段都站在前一段权重的肩膀上。

偏好对齐 preference alignment

后训练的一段,目标是让回答更合人类口味、更有用更安全。数据是"同一问题的两个回答 + 人类判断 A 比 B 好"。 它是目标,不是某个具体算法:实现它有两条路 —— RLHF(走强化学习)和 DPO(不走强化学习)。 所以"偏好对齐 = 强化学习"是把目标和其中一种手段画了等号。

全量微调 full fine-tuning

微调时更新模型的全部参数。它是一种"手段"(怎么改权重),不是一种"任务" —— 既能用来做 SFT,也能用来做 DPO。 所以"全量微调 = SFT"是把手段误当成任务。它和 LoRA二选一的两种手段,不是先后步骤。效果直接,但每个任务都要存一份完整模型,显存/硬盘开销大。

PEFT parameter-efficient fine-tuning · 参数高效微调

一类"只更新极少量参数"的微调手段的统称,目的是省显存、省存储。LoRA 是其中最流行的一种(还有 QLoRA = LoRA+量化 等)。 与 全量微调 相对,二者是同一件事(微调)的两种改权重方式。

LoRA Low-Rank Adaptation · 低秩适配

一种 PEFT 手段:冻结原模型,在某些 Linear 旁边挂两个低秩小矩阵 A、B,只训练它俩。 可训练参数常只占 ~1%,却能逼近全量微调的效果;一个底座还能挂多个适配器随时切换。它是"怎么省钱地微调"的手段, 可叠加在 SFTDPO 上。本项目 07_lora.py 会手搓一遍。

loss mask 标签掩码

SFT 的关键一步:把整条"指令+回答"喂进去做前向,但只对回答段算 loss, 指令/模板段的标签设成 -100(PyTorch 的 ignore_index)被忽略。这样模型只学"给定指令该怎么答", 而不会去学"生成用户的指令"。SFT 和预训练用同一个 loss,差别主要就在这一处掩码。

对话模板 / EOS chat template · end-of-sequence

把"指令"和"回答"拼成一条序列时套的固定格式(用 <|user|> / <|assistant|> 等特殊标记标出角色边界), 让模型分清谁说的、该自己答哪段。结尾的 EOS(结束标记)尤其重要:base 模型的毛病是不会停, SFT 在每条回答末尾放 EOS 并算进 loss,就是教模型"答完就停"。

DPO Direct Preference Optimization · 直接偏好优化

一种不走强化学习偏好对齐方法:把 RLHF 的目标推成闭式解, 直接在"chosen 好 / rejected 差"的偏好对上做一个类监督损失,拉高 chosen、压低 rejected。 不需要奖励模型、不需要在线采样、没有 RL 循环,单机就能跑。它不是 PPO 的变体, 而是和 RLHF 平行的另一条路;卖点是"不用 RL 那套笨重机器也能拿到 RLHF 的效果"。本项目偏好对齐只做 DPO(08_dpo.py)。

RLHF / PPO Reinforcement Learning from Human Feedback

强化学习偏好对齐:先用偏好数据训一个奖励模型给回答打分, 再用 PPO(一种 RL 算法)让模型最大化奖励。要在线采样 rollout、要价值网络,工程量比 DPO 大数倍。 它和 DPO 是实现同一目标的两条路(RLHF 走 RL,DPO 不走)。本项目只在白皮书里讲原理,不写成脚本

E里程碑

Attention Is All You Need 2017 · Vaswani et al.

Google 2017 年的论文,提出 Transformer 架构:用自注意力彻底取代 RNN / CNN 来建模序列依赖, 并引入多头注意力位置编码。它是 GPT、BERT 等几乎所有现代大模型的共同基石。 本项目第 2 关搭的单头自注意力是它的核心零件,第 3 关会完整复现它的架构(多头 + 残差 + LayerNorm + 前馈网络)。 🥚 它的"前世今生"(8 位作者、翻译起源、家谱)有个小故事 → 学习札记