y.transpose(-2, -1)
把y的倒数第2个维度和倒数第1个维度转置
y.transpose(-2, -1)
把y的倒数第2个维度和倒数第1个维度转置
ZeRO 显存优化
让每张卡只存一部分优化器状态、梯度和参数。优化器状态:每个优化器额外存储:一阶矩估计、二阶矩估计
流水线并行(PP
把不同层给不同设备训练。加入transformer有八层,串行时每个算4层。算前4层时,后4层在等待。改成并行计算吞吐能大幅度提升。
张量并行(TP)
把单个矩阵切碎给多卡用
以及 Transformer 如何用 Self-Attention 解决它们
(1) attention一次性把所有向量矩阵(token)输入模型,实现并行计算。self-attention的核心是矩阵运算,把所有词存入矩阵一次性计算。
(2)每个token之间是直接连接的,可以直接(一步)计算每两个token的注意力分数,而RNN不同距离的token存在远近距离,因此会遗忘。
(头数)x 128(head_dim
头*head_dim= 隐藏层维度 有多个大小为隐藏层维度的隐藏层,这里隐藏层数是32
LayerNorm
两个Layernorm的作用: (1) 稳定Q,K,V的分布 (2) 稳定FFN的输入
干净
这里公式只给出了前向传播,
post-Norm 前向传播时梯度要先被LN求导。
反向传播时\alpha L/y*(1+\alpha LN\x), L对y的求导路径是干净的。
结果只依赖于两个 token 的相对位置差
sin: x+PE, 会改变原始的数值表达,PE是远近的绝对位置 RoPE: R*X, 选择 相对位置n-m,同样会有很多维度表示变化频率不同的远近。因为有多个维度,所以不用担心360度重复的问题。
iii 是维度索引
假如有维度0,维度1
维度0:变化快,区分相邻单词 维度1:变化慢,区分远距离单词
AllReduce
W1 按列切分:每个 GPU 拿到不同的中间特征(升维后的结果)。
W2 按行切分:每个 GPU 用自己那部分继续算最终输出。
这样中间完全不需要通信,只在最后把各 GPU 算出的最终结果加起来(做一次 AllReduce)就行。
M
M=1000,000
d×d
Q,K,V权重矩阵维度:d_model * d_model Q,K,V维度: (N,d) 序列长度*隐藏层维度
Online Softmax 算法将其合并为一遍扫描,FlashAttention 正是基于此实现了 Attention 的高效融合
online softmax: 两遍扫描变成一遍 flashattention: 在GPU上的高效硬件实现
?
Tokenizer 会直接决定序列长度,因此影响 attention 计算量(序列长度为L,则计算量为L^2)、KV cache、显存和有效上下文长度(切分的太碎计算成本高);同时它也决定 embedding 的参数共享方式(词拆分成token的形式影响学习能力),从而影响稀有词、新词、多语言、数字和代码的学习效率。切得太碎会增加计算成本,切得太粗会产生大量低频 token。因此 tokenizer 虽然不直接决定模型上限,但会显著影响 LLM 的训练效率、推理成本和最终任务表现。
?
一个好的 tokenizer 并不是单纯追求最大压缩率,而是要在序列长度、词表大小、覆盖能力和语义稳定性之间做 trade-off。粒度太细会导致 token 数过多,增加 Transformer 的计算和 KV cache 开销;粒度太粗则会导致词表爆炸、稀有 token 数据不足以及新词泛化能力下降。因此主流 tokenizer 通常采用 subword 方法,让高频词或高频片段成为长 token,而低频词继续拆分,从而兼顾压缩效率和泛化能力。
并行归约
并行归约是指:在并行计算中,将分布在 N 个不同处理单元(线程/核心) 上的大量数据,通过某个满足结合律(Associative)和交换律(Commutative)的二元运算符(如 +、*、max、min),“多对一”地合并成最终的一个(或一小批)结果的过程。
串行思维:for i in range(N): sum += arr[i](需要 N 步,依次等待)。
并行思维:N 个人各拿一个数,两两配对相加,不断合并,直到剩下最后一个人拿着总和。 2^k=N,经过k轮运算,每轮处理一半的数据,处理完N个样本。复杂度为O(log(N))
并行归约的本质是利用树形拓扑将对一维数组的累加复杂度从 O(N) 降到 O(log N)
Softmax + 交叉熵的简洁梯度
要求掌握这里结论的推导过程
LogSumExp
推导logsumupexp和logsoftmax的区别 logsum就是原softmax的分母部分
LSE(z)=m+logj∑ezj−m
zj=zj-m+m, LSE=logsum(e^(zj-m+m)) LSE=loge^msum(e^(zj-m)) = m +logsum(e^(zj-m))
dtype 容差
dtyper容差:不同精度允许参考误差不同 极端验证:测大值、小数、极端情况是否正确
exp 溢出、除零、消减或长归约误差
溢出:exp指数超出float 除零错误 消减误差:大数相减,小精度丧失 长规约误差:多个小数相加,后面的小数省略产生误差。
广播、转置或非连续 stride
广播:多个变量访问一块内存 转置:矩阵转置 stride是矩阵的访问步长,矩阵元素在gpu中连续存储,用stride控制如何访问(如访问第几行第n个元素),当stride和尺寸不一致,访问不连续
理论最小访存量
这个问题分析:一个 kernel 到底是算力瓶颈还是内存瓶颈。 假设矩阵A(MK),B(KN),C(MN),则共需要读写MN+MK+KN次。 好的kernel希望一次加载,多次复用,计算强度AI=FLOPS/memory. 优化后一个tile,可以供多个计算步骤使用。
能否分块?
分块 tileling 不能分块的情况: (1). 前面一个对后面一个存在强依赖关系,前面结果是后面的输入 (2) 数据量太小,分块后通信开销比不分块大 (3)计算需要全局信息。分块后前面信息丢失,无法计算完整结果
归约
矩阵乘法:A=MK,B=KN, C=AB=M*N,则维度K被规约
分布式均值
每个GPU计算的样本数量不一定相同,每个GPU有一个均值计算所有GPU就要分布式均值。将一个batch切分,放到多个GPU上并行运行。accuracy,loss等都需要所有batch计算后的整体均值
Online Softmax 的分块合并
把大块attention切分成小块attention减少显存开销。 原来大块attention需要保存S^2矩阵在显存中,计算小块attention,不用保存完整attention.用完就丢,节省显存
Dh\sqrt{D_h}Dh
每个head的Q,K维度为S*D, attention score =QK^T,每个token和哪个token有关。
QK^T得到矩阵维度为S*S,但每个元素的长度都是Dh,由Dh次乘法加法得到,用于归一化
M
M是因果掩码/上三角掩码,不允许模型看到之后的值,把未来的值都用-无穷掩盖。
X
X乘权重W,维度是W(H,H),乘完后Q,K,V维度为BSH。 1. 因为Transformer使用多头注意力机制,有N个头,每个都维度为D。所以BSND 2. 因为attention需要计算QK^T, 希望每个head单独计算,因此希望维度为BNSD。(每个head单独计算的Q,K维度为S*D).因为一次batch和head.都希望作为并行维度,所以前面要再乘B,N.
使用transpose可以交换指定轴的维度transpose(1,2),交换1,2维维度
反向传播中的 FP16 小梯度可能下溢为 0
混合精度训练(FP16/BF16)中的 Loss Scaling(损失缩放)技术,反向传播时FP16能表示的最小为6*10^-8,若最小梯度为10^-8,则下溢为0。
把梯度先放大,反向传播后再除S恢复正确数值。
不能被二进制浮点精确表
无限循环小数只能被二进制有限表示。当绝对数值越大,精度越差。 如1.m2^e, m是尾数,e是指数,如1.2310^4.e越大,数值范围越大,尾数固定,由于指数导致的范围很大,可表示的精度就越小
7 LayerNorm
归一化层,LayerNorm是归一化公式
7.8 RMSNorm
Layernorm的简化版本,RMSEnorm计算更快 LayerNorm:需要: 求mean 求variance 标准化
RMSNorm:只需要: 求平方和 开根号
减少: reduction次数 memory访问 kernel计算
LayerNorm(xi)=γiσ2+ϵxi−μ+β
归一化公式
残差
x+loss,防止梯度爆炸或消失问题,使整体变化平稳。
Adam
反向传播时需要参数更新,SGD是传统参数更新方法。然而只考虑当前梯度,当batchsize太小时,会出现噪声而导致更新不准确。(batch中一次全是猫,一次全是狗)。
动量把历史值通过权重考虑进去,Adam在动量的基础上又考虑了多个参数更新时量级不一致的问题。如w1=10000eta,w2=0.00001eta, 可能一次更新某个参数基本无变化。Adam通过一阶m(梯度方向),二阶v(步长大小),解决不同参数的更新问题
world_size: int
共有多少个进程
shard
切分数据分配给进程