Skip to main content

LLM 通用基础

·21795 words·44 mins

1. 损失函数
#

1.1 均方误差损失(Mean Squared Error, MSE)
#

公式:

LMSE=1ni=1n(yiy^i)2 L_{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2
  • 其中:
    • yiy_i :真实值(ground truth)
    • y^i\hat{y}_i :模型预测值
    • nn :样本数量

解释:

  • MSE度量的是预测值与真实值之间的 欧氏距离的平方,常用于回归任务。
  • 直观上,它让预测结果尽可能接近真实值,误差越大,损失惩罚越大(因为平方项会放大偏差)。

它最小化的目标:

  • 最小化预测值与真实值的 均方差,等价于让预测的期望值趋近于真实值。
  • 数学上,MSE 的最小化逼近的是条件期望 E[yx]E[y|x]

1.2 交叉熵损失(Cross-Entropy Loss)
#

公式(多分类情况):

LCE=i=1Cyilog(y^i) L_{CE} = - \sum_{i=1}^{C} y_i \log(\hat{y}_i)
  • 其中:
    • CC :类别数
    • yiy_i :真实标签的 one-hot 编码(正确类别为 1,其余为 0)
    • y^i\hat{y}_i :模型预测的该类别概率(通常由 softmax 输出) 解释:
  • 交叉熵度量了 真实分布与预测分布之间的差异
  • 如果预测概率完全与真实一致(即正确类别概率为 1),交叉熵损失为 0。
    它最小化的目标:
  • 最小化真实分布与预测分布的 KL 散度
    DKL(PQ)=iP(i)logP(i)Q(i) D_{KL}(P \parallel Q) = \sum_i P(i) \log \frac{P(i)}{Q(i)}

1.3 二元交叉熵损失
#

设:

  • y{0,1}y \in \{0,1\} :真实标签(1 表示正类,0 表示负类)
  • y^[0,1]\hat{y} \in [0,1] :预测的正类概率(通常由 sigmoid 输出)

公式:

LBCE=[ylog(y^)+(1y)log(1y^)] L_{BCE} = - \big[ y \cdot \log(\hat{y}) + (1-y) \cdot \log(1-\hat{y}) \big]

解释:

  • y=1y=1(正类)时:

    L=log(y^) L = -\log(\hat{y})

    预测概率 y^\hat{y} 越接近 1,损失越小。

  • y=0y=0(负类)时:

    L=log(1y^) L = -\log(1-\hat{y})

    预测概率 y^\hat{y} 越接近 0,损失越小。

多分类交叉熵

L=i=1Cyilog(y^i) L = - \sum_{i=1}^{C} y_i \log(\hat{y}_i)
  • C=2C=2 时,softmax 的输出为 (y^,1y^)(\hat{y}, 1-\hat{y}),代入上式后可以化简为: L=[ylog(y^)+(1y)log(1y^)] L = - \big[ y \log(\hat{y}) + (1-y) \log(1-\hat{y}) \big]

结论:二分类交叉熵是多分类交叉熵在 C=2C=2 时的特例

1.4 损失函数总结对比
#

  • MSE

    • 用于回归任务
    • 最小化预测值与真实值之间的平方误差
    • 收敛到条件期望
  • 交叉熵

    • 用于分类任务
    • 最小化预测分布与真实分布之间的差异
    • 收敛到真实概率分布

1.5 损失函数与目标函数
#

​ 在深度学习论文中,经常会出现 损失函数(Loss Function)目标函数(Objective Function) 两个概念。两者既有联系,也有区别。

1.5.1 损失函数(Loss Function)
#

定义: 针对 单一样本,衡量模型预测与真实值之间差异的函数。

作用: 描述模型在一个样本上的“错误程度”。

常见例子:

  • 回归:均方误差(MSE)
    L(x,y)=(yy^)2 L(x,y) = (y - \hat{y})^2
  • 分类:交叉熵损失(CE)
    L(x,y)=iyilog(y^i) L(x,y) = - \sum_i y_i \log(\hat{y}_i)

1.5.2 目标函数(Objective Function)
#

定义: 在整个数据集上,模型最终要 优化/最小化/最大化 的函数。

关系: 通常是对所有样本的损失函数取平均(或加总),有时还会加上正则化项

形式:

J(θ)=1Ni=1NL(xi,yi;θ)+λR(θ) J(\theta) = \frac{1}{N} \sum_{i=1}^N L(x_i, y_i; \theta) + \lambda R(\theta)

其中:

  • R(θ)R(\theta) :正则化项
  • λ\lambda :正则化系数

👉 损失函数是“局部”的,目标函数是“全局”的。

1.5.3 在概率建模(如 GPT)中的情况
#

在 GPT 等生成模型论文中,常说 目标函数是最大化似然函数(MLE)

  • GPT 建模条件概率:

    Pθ(x)=t=1TPθ(xtx<t) P_\theta(x) = \prod_{t=1}^T P_\theta(x_t \mid x_{<t})
  • 最大化似然:让训练数据的概率尽可能大

    J(θ)=maxθt=1TlogPθ(xtx<t) J(\theta) = \max_\theta \sum_{t=1}^T \log P_\theta(x_t \mid x_{<t})
  • 对应的 损失函数 是负对数似然(NLL):

    L(x;θ)=t=1TlogPθ(xtx<t) L(x; \theta) = - \sum_{t=1}^T \log P_\theta(x_t \mid x_{<t})
  • 整体目标函数就是最小化 NLL 的平均:

    J(θ)=minθ1Ni=1NL(xi;θ) J(\theta) = \min_\theta \frac{1}{N} \sum_{i=1}^N L(x_i; \theta)

👉 最大化似然函数 ↔ 最小化负对数似然损失

1.5.4 总结对比
#

概念损失函数 (Loss)目标函数 (Objective)
作用衡量单个样本预测的误差衡量整体模型好坏
范围针对单一样本针对整个数据集
数学形式L(x,y)L(x,y)J(θ)=L(x,y)J(\theta) = \sum L(x,y) 或加正则化
在 GPT 中单个 token 的 NLL整个序列的似然(或其平均 NLL)

2. KL散度
#

2.1 熵的定义
#

**熵(Entropy)**是信息论中的核心概念,用来衡量一个随机变量的不确定性或平均信息量。

**离散情况:**设随机变量 XX 具有概率质量函数(PMF) P(x)P(x),则熵定义为:

H(P)=xP(x)logP(x) H(P) = - \sum_{x} P(x) \log P(x)
  • 这里的 P(x)P(x) 表示随机变量取值 xx 的概率。
  • 熵越大,表示分布越不确定。

**连续情况:**设随机变量 XX 的概率密度函数(PDF)为 p(x)p(x),则熵的定义为:

H(P)=p(x)logp(x)dx H(P) = - \int p(x) \log p(x) \, dx
  • 这时的熵被称为 微分熵(Differential Entropy)
  • 注意:微分熵可能为负数,不同于离散情形总是非负。

直观理解

  • 如果一个事件概率很大(确定性强),其信息量小。
  • 如果一个事件概率很小(不确定性强),其信息量大。
  • 熵是分布的 平均信息量

例子:

  1. 公平抛硬币:

    P()=0.5,  P()=0.5 P(正)=0.5,\; P(反)=0.5

    熵为:

    H(P)=(0.5log0.5+0.5log0.5)=1 比特 H(P) = - (0.5 \log 0.5 + 0.5 \log 0.5) = 1 \ \text{比特}
  2. 偏置硬币:

    P()=0.9,  P()=0.1 P(正)=0.9,\; P(反)=0.1

    熵较小,因为结果更可预测。

2.2 KL散度的定义
#

KL散度(Kullback-Leibler divergence),可以以称作相对熵(relative entropy)或信息散度(information divergence)。KL散度的理论意义在于度量两个概率分布之间的差异程度,当KL散度越大的时候,说明两者的差异程度越大;而当KL散度小的时候,则说明两者的差异程度小。如果两者相同的话,则该KL散度应该为0。


设:

  • P(x)P(x) :真实分布(目标分布)
  • Q(x)Q(x) :模型分布(近似分布)

如果我们用Q(x)Q(x)去近似P(x)P(x),则KL散度可以表示为:

离散情况

DKL(PQ)=xP(x)logP(x)Q(x) D_{KL}(P \parallel Q) = \sum_x P(x) \log \frac{P(x)}{Q(x)}

连续情况

DKL(PQ)=P(x)logP(x)Q(x)dx D_{KL}(P \parallel Q) = \int P(x) \log \frac{P(x)}{Q(x)} \, dx

从上面的公式可以看出:

  • KL散度具有非负性DKL(PQ)0D_{KL}(P \parallel Q) \geq 0

  • 当且仅当 P(x)=Q(x)P(x) = Q(x) 对所有 xx 成立时,DKL(PQ)=0D_{KL}(P \parallel Q) = 0

  • KL散度不具备对称性,也就是说PP对于QQ的KL散度并不等于QQ对于PP的KL散度:

    DKL(PQ)DKL(QP) D_{KL}(P \parallel Q) \neq D_{KL}(Q \parallel P)

在离散情况下将KL散度公式展开可得:

KL(PQ)=P(x)logP(x)Q(x)=P(x)log(Q(x))+P(x)log(P(x))=H(P,Q)H(P) KL(P∣∣Q)=∑P(x)log \frac{P(x)}{Q(x)}=−∑P(x)log(Q(x))+∑P(x)log(P(x))=H(P,Q)−H(P)

最后得到的第一项 H(P,Q)H(P, Q) 称作 PPQQ 的交叉熵(cross entropy),后面一项 H(P)H(P) 就是熵。

在信息论中,熵代表着信息量,H(P)H(P) 代表着基于 PP 分布自身的编码长度,也就是最优的编码长度(最小字节数)。

H(P,Q)H(P,Q) 则代表着用 QQ 的分布去近似 PP 分布的信息,自然需要更多的编码长度。并且两个分布差异越大,需要的编码长度越大。所以两个值相减是大于等于0的一个值,代表冗余的编码长度,也就是两个分布差异的程度。所以KL散度在信息论中还可以称为相对熵(relative entropy)。

对深度学习中的生成模型来说,我们希望最小化真实数据分布与生成数据分布之间的KL散度,从而使得生成数据尽可能接近真实数据的分布。在实际场景中,我们是几乎不可能知道真实数据分布 Pdata(x)P_{data}(x) 的,我们使用训练数据形成的生成分布在逼近 Pdata(x)P_{data}(x)

2.3 KL散度和交叉熵
#

由上推导可得:

DKL(PQ)=H(P,Q)H(P) D_{KL}(P \parallel Q) = H(P, Q) - H(P)

其中:

  • 熵(Entropy):H(P)=xP(x)logP(x)H(P) = - \sum_x P(x) \log P(x)
  • 交叉熵(Cross-Entropy):H(P,Q)=xP(x)logQ(x)H(P,Q) = - \sum_x P(x) \log Q(x)
  • KL散度:DKL(PQ)D_{KL}(P \parallel Q)

交叉熵损失函数 是深度学习中常见的优化目标。

  • 标签分布 PP:真实标签(通常是 one-hot)
  • 模型分布 QQ:预测的 softmax 概率

它与 KL 散度 的关系为:

L=H(P,Q)=xP(x)logQ(x)=DKL(PQ)+H(P) L=H(P,Q) =- \sum_x P(x) \log Q(x)= D_{KL}(P \parallel Q) + H(P)
  • 因为 H(P)H(P) 与模型无关,所以: 最小化交叉熵 ↔ 最小化 KL 散度。

3. 线性回归、逻辑回归、Softmax回归
#

3.1 线性回归(Linear Regression)
#

目标: 用于预测连续型数值。

  • 模型形式:

    y=wTx+b y = \mathbf{w}^T \mathbf{x} + b
  • 输出: 直接给出一个实数值,适合房价预测、销量预测等回归问题。

  • 损失函数: 通常采用均方误差 (MSE):

    L=1ni=1n(yiy^i)2 L = \frac{1}{n}\sum_{i=1}^n (y_i - \hat{y}_i)^2

3.2 逻辑回归(Logistic Regression)
#

目标: 用于二分类问题。

  • 核心思想: 在回归结果外加一个 Sigmoid 函数,把连续实数映射到区间 [0,1][0,1],表示概率。

  • 模型形式:

    P(y=1x)=σ(wTx+b)=11+e(wTx+b) P(y=1|\mathbf{x}) = \sigma(\mathbf{w}^T \mathbf{x} + b) = \frac{1}{1 + e^{-(\mathbf{w}^T \mathbf{x}+b)}}
  • 输出: 概率值,可根据阈值(通常为 0.5)进行分类。

  • 损失函数: 对数似然损失(交叉熵):

    L=1ni=1n[yilog(y^i)+(1yi)log(1y^i)] L = -\frac{1}{n}\sum_{i=1}^n \Big[ y_i \log(\hat{y}_i) + (1-y_i)\log(1-\hat{y}_i)\Big]

3.3 Softmax回归(Softmax Regression)
#

目标: 逻辑回归的多分类扩展。

  • 核心思想: 对每一类计算一个线性函数,然后通过 Softmax 函数 把它们转化为概率分布。

  • 模型形式:

    对于 KK 类分类:

    P(y=kx)=ewkTx+bkj=1KewjTx+bj P(y=k|\mathbf{x}) = \frac{e^{\mathbf{w}_k^T \mathbf{x} + b_k}}{\sum_{j=1}^K e^{\mathbf{w}_j^T \mathbf{x} + b_j}}
  • 输出: 每一类的概率,取概率最大的类作为预测类别。

  • 损失函数: 多分类交叉熵损失:

    L=1ni=1nk=1Kyi,klogy^i,k L = -\frac{1}{n}\sum_{i=1}^n \sum_{k=1}^K y_{i,k} \log \hat{y}_{i,k}

    其中 yi,ky_{i,k} 是 one-hot 标签。

3.4 区别与联系
#

  1. 模型基础相同: 三者都是基于 线性模型(权重和输入特征的线性组合),区别主要在于输出层和损失函数。
  2. 输出空间不同:
    • 线性回归输出的是一个实数(无范围限制)。
    • 逻辑回归输出的是 [0,1][0,1] 概率(二分类)。
    • Softmax 回归输出的是多维概率分布(多分类)。
  3. 应用场景不同:
    • 线性回归:预测连续数值(回归问题)。
    • 逻辑回归:预测是否属于某一类(二分类问题)。
    • Softmax 回归:预测属于哪一类(多分类问题)。
  4. 演变关系:
    • 逻辑回归可以看作在线性回归的基础上加 Sigmoid 的“分类版”。
    • Softmax 回归是逻辑回归的多分类推广。

4. 混淆矩阵
#

​ 在二分类问题中,我们有两个类别:正类(Positive)和负类(Negative)。根据模型对每个样本的预测值和label值之间的关系,每个预测结果可以落在四个格子中的一个。然后对每个格子中的样本计数。

真实正类(Positive)真实负类(Negative)
预测正类True Positive(TP)False Positive(FP)
预测负类False Negative(FN)True Negative(TN)

**TP:**模型正确地将正样本预测为正类的数量。

**FP:**模型错误地将负样本预测为正类的数量(误报)。

**FN:**模型错误地将正样本预测为负类的数量(漏报)。

**TN:**模型正确地将负样本预测为负类的数量。

有了混淆矩阵,对于准确率的定义就可以表示为:

Accuracy=TP+TNTP+TN+FP+FN Accuracy= \frac{TP+TN}{TP+TN+FP+FN}

4.1 精确率
#

**精确率:**被预测为正例的样本中,真正正例的比例。它的公式为:

Preciosn=TPTP+FP Preciosn=\frac{TP}{TP+FP}

4.2 召回率
#

**召回率:**真实为正类的样本中,被正确预测为正类的比例。

Recal=TPTP+FN Recal=\frac{TP}{TP+FN}

4.3 F1-Score
#

F1-Score:

​ 精确率衡量的是预测为正例的情况下真正为正例的百分比。选择精确率作为项目的目标,可以保证你得到的正例,实际为正例的比例很高。在逻辑回归中,你可以提高sigmoid输出大于0.5,比如0.8以上作为正例来提高精确率。但是这样做可能会把一些本来是正例的样本误判为负例。

​ 召回率衡量的是真正的正例中你发现的比率。还是以对罕见病预测的例子,10万个人中,只有1个是正例,你预测10万个人都是正例,召回率是1,但是这个模型也没有什么用。

​ 好的模型应该同时能兼顾精确率和召回率,F1-Score就是一个同时兼顾两者的指标,它的公式为:

F1=2PrecisonRecallPrecision+Recall F1=2*\frac{Precison*Recall}{Precision+Recall}

5. Batch Norm, Layer Norm, Instance Norm & Group Norm
#

跨通道与跨样本的关键区别

  • 跨通道:在同一个样本内,跨所有通道计算均值和方差(如 Layer Normalization 和 Group Normalization中的一部分)。举例:RGB 图像中,三个颜色通道的统计量被一起计算。
  • 跨样本:在同一通道内,跨所有样本(比如在一个 batch内)计算均值和方差(如 Batch Normalization)。举例:在一个批次中所有图片的 R 通道上计算统计量。
    1.jpg

5.1 Batch Norm
#

针对单个通道,在批次维度 (Batch) 上计算均值和方差。(跨样本单通道)

公式计算如下:

x^=xμbatchσbatch2+ϵ \hat{x}=\frac{x-\mu_{\text{batch}}}{\sqrt{\sigma^2_{\text{batch}}+\epsilon}}

其中:

  • μbatch,σbatch2\mu_{\text{batch}}, \sigma^2_{\text{batch}}:某一通道在整个 Batch 的均值和方差。
  • ϵ:小常数,防止除零。

通俗理解: 想象输入了 8 张图片(Batch Size = 8,宽高分别为4*4),每张图片的 RGB 通道单独计算均值和方差。Batch Norm 就是对每个通道的所有图片(总共 8×4×4=128 个值)统一归一化,让数据在训练中更稳定。

优缺点:

  • 优点:适合大批量训练,能有效提高训练收敛速度和模型精度。
  • 缺点:对小批量数据(例如,内存限制导致每次只训练少量样本)表现较差,统计量估计不稳定

5.2 Layer Norm
#

在每个样本的,所有通道 (Channel) 上归一化。(单样本跨通道)

公式计算如下:

x^=xμlayerσlayer2+ϵ \hat{x}=\frac{x-\mu_{\text{layer}}}{\sqrt{\sigma^2_{\text{layer}}+\epsilon}}

其中:

  • μbatch,σbatch2\mu_{\text{batch}}, \sigma^2_{\text{batch}}:某一样本在整个 Batch 的均值和方差。

通俗理解: 假设我们只看一张图片(例如大小 3×4×4)。Layer Norm 会把这张图片所有通道的数据(3 个通道的 4×4=48 个值)统一归一化。适合处理单张图片的场景。

优缺点:

  • 优点:独立于批次大小,适合 RNN 等顺序模型。
  • 缺点:对视觉任务(如图像分类)性能不如 BN,因为假设所有通道的分布相似,这在卷积层中可能不成立。

5.3 Instance Norm
#

在每个样本的每个通道上归一化,只使用空间维度。(单样本单通道)

计算公式如下:

x^=xμinstanceσinstance2+ϵ \hat{x}=\frac{x-\mu_{\text{instance}}}{\sqrt{\sigma^2_{\text{instance}}+\epsilon}}

其中:

  • μinstance,σinstance2\mu_{\text{instance}}, \sigma^2_{\text{instance}} :单张图片的某个通道内的均值和方差。

通俗理解: Instance Norm 针对单张图片的每个通道进行独立归一化。例如对红色通道的 4×4=16 个值归一化,绿色和蓝色通道分别独立归一化。适合图像生成任务,如风格迁移。

优缺点:

  • 优点:常用于生成模型(如风格迁移),对每个样本进行独立处理。
  • 缺点:忽略了通道间的依赖关系,表达能力较弱。

5.4 Group Norm
#

将通道划分为若干组 (Groups),在每组内计算归一化。(单样本跨几个通道,LN 的简化版本)

x^=xμgroupσgroup2+ϵ \hat{x}=\frac{x-\mu_{\text{group}}}{\sqrt{\sigma^2_{\text{group}}+\epsilon}}

其中:

  • μgroup,σgroup2\mu_{\text{group}}, \sigma^2_{\text{group}} :某一组通道的均值和方差。

通俗理解: 假设我们有 32 个通道,Group Norm 将其分成 4 组,每组 8 个通道。然后对每组的所有值进行归一化。例如:红、绿、蓝可能被分配到不同的组内,每组内单独计算均值和方差。适合小 Batch 的训练。

优缺点:

  • 优点:摆脱了对批次大小的依赖,在各种批次大小下都能表现稳定。
  • 缺点:计算复杂度略高于 BN。

6. 字符编码
#

​ 我们知道,计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从00000000到11111111。

6.1 ASCII编码
#

​ ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。

​ ASCII 码使用指定的 7 位8 位二进制数组合来表示128 或256 种可能的字符。标准ASCII 码也叫基础ASCII码,使用 7 位二进制数(第一位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号, 以及在美式英语中使用的特殊控制字符。如下图所示:

35.png

其中:

​ 0~31及127(共33个)是控制字符或通信专用字符(其余为可显示字符),如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(响铃)等;通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等;ASCII值为8、9、10 和13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示有不同的影响。

​ 32~126(共95个)是字符(32是空格),其中48~57为0到9十个阿拉伯数字。

​ 65~90为26个大写英文字母,97~122号为26个小写英文字母,其余为一些标点符号、运算符号等。

​ 后128个称为扩展ASCII码。许多基于x86的系统都支持使用扩展(或“高”)ASCII。扩展ASCII 码允许将每个字符的第8 位用于确定附加的128 个特殊符号字符、外来语字母和图形符号。如下图所示:

36.png

6.2 GBK编码
#

​ 由于ASCII编码不支持中文,因此,当中国人用到计算机时,就需要寻求一种编码方式来支持中文。 于是,国人就定义了一套编码规则:当字符小于127位时,与ASCII的字符相同,但当两个大于127的字符连接在一起时,就代表一个汉字,第一个字节称为高字节(从0xA1-0xF7),第二个字节为低字节(从0xA1-0xFE),这样大约可以组合7000多个简体汉字。这个规则叫做GB2312。 ​ 但是由于中国汉字很多,有些字无法表示,于是重新定义了规则:不在要求低字节一定是127之后的编码,只要第一个字节是大于127,就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。这种扩展之后的编码方案称之为GBK标准,包括了GB2312的所有内容,同时新增了近20000个新的汉字(包括繁体字)和符号。 ​ 但是,中国有56个民族,所以,我们再次对编码规则进行了扩展,又加了近几千个少数民族的字符,于是再次扩展后得编码叫做GB18030。中国的程序员觉得这一系列编码的标准是非常的好,于是统统称他们叫做"DBCS"(Double Byte Charecter Set 双字节字符集)。

6.3 Unicode字符集
#

​ 因为世界国家很多,每个国家都定义一套自己的编码标准,结果相互之间谁也不懂谁的编码,就无法进行很好的沟通交流,所以及时的出现了一个组织ISO(国际标准化组织)决定定义一套编码方案来解决所有国家的编码问题,这个新的编码方案就叫做Unicode。注意Unicode不是一个新的编码规则,而是一套字符集(为每一个「字符」分配一个唯一的 ID(学名为码位 / 码点 / Code Point)),可以将Unicode理解为一本世界编码的字典。 ​ ISO规定:每个字符必须使用俩个字节,即用16位二进制来表示所有的字符,对于ASCII编码表里的字符,保持其编码不变,只是将长度扩展到了16位,其他国家的字符全部统一重新编码。由于传输ASCII表里的字符时,实际上可以只用一个字节就可以表示,所以,这种编码方案在传输数据比较浪费带宽,存储数据比较浪费硬盘。

​ Unicode的问题如下:

​ 需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

​ 比如,汉字严的 Unicode 是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

​ 这里就有两个严重的问题,第一个问题是,如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

​ 它们造成的结果是:

​ 1)出现了 Unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 Unicode。

​ 2)Unicode 在很长一段时间内无法推广,直到互联网的出现。

6.4 UTF-8编码
#

​ 由于Unicode比较浪费网络带宽和硬盘,因此为了解决这个问题,就在Unicode的基础上,定义了一套编码规则(将「码位」转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)),这个新的编码规则就是UTF-8,采用1-4个字符进行传输和存储数据。

​ 编码规则:使用下面的模板进行转换:

​ 如果一个字节以“0”开头,说明该字符采用单字节编码方式,这与传统的ASCII编码保持兼容。若一个字节以“10”开头,则表明它不是字符的起始字节,而是某个多字节字符的中间部分,需要向前寻找起始位置。若以“110”开头,则表示该字符使用两个字节进行编码;以“1110”开头则代表采用三个字节;而若以“11110”开头,则说明该字符由四个字节构成。

Unicode符号范围十六进制	  	|     UTF-8编码方式(二进制)
------------------------------------------------------------------------
0000 0000-0000 007F     	   |     0xxxxxxx						(ASCII码)
0000 0080-0000 07FF            |     110xxxxx 10xxxxxx
0000 0800-0000 FFFF            |     1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF            |     11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

6.5 Little endian 和 Big endian
#

​ UCS-2 格式可以存储 Unicode 码(码点不超过0xFFFF)。以汉字严为例,Unicode 码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,这就是 Big endian 方式;25在前,4E在后,这是 Little endian 方式。

​ 这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big-endian)敲开还是从小头(Little-endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

​ 第一个字节在前,就是"大头方式"(Big endian),第二个字节在前就是"小头方式"(Little endian)。

​ 那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

​ Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(zero width no-break space),用FE FF表示。这正好是两个字节,而且FF比FE大1。

​ 如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

计算机中notebook的编码方式:

​ 有四个选项:ANSI,Unicode,Unicode big endian和UTF-8

1)ANSI是默认的编码方式:对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对 Windows 简体中文版,如果是繁体中文版会采用 Big5 码); 2)Unicode编码这里指的是notepad.exe使用的 UCS-2 编码方式:即直接用两个字节存入字符的 Unicode 码,这个选项用的 little endian 格式; 3)Unicode big endian编码与上一个选项相对应:我在下一节会解释 little endian 和 big endian 的涵义; 4)UTF-8编码:也就是上一节谈到的编码方法。

6.6 字符编码的转换
#

UTF-8与Unicode的转换:

​ UTF-8区分每个字符的开始是根据字符的高位字节来区分的,比如用一个字节表示的字符,第一个字节高位以“0”开头;用两个字节表示的字符,第一个字节的高位为以“110”开头,后面一个字节以“10开头”;用三个字节表示的字符,第一个字节以“1110”开头,后面俩字节以“10”开头;用四个字节表示的字符,第一个字节以“11110”开头,后面的三个字节以“10”开头。

​ 比如汉字“智”,utf-8编码是“\xe6\x99\xba”对应的二进制为:“111001101001100110111010”,由于utf-8中一个汉字是3个字节,所以对应的模板为“0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx”。

11100110   10011001     10111010
1110xxxx   10xxxxxx     10xxxxxx
    0110     011001       111010

​ 0110011001111010代表十六进制667A,因此根据规则转换得出“智”Unicode的位置为为“667A”。同样,根据Unicode中字符的编码位置,也能找到对应的utf-8编码。

Unicode与GBK的转换:

​ 比如汉字“路”,在gbk中的编码为“\xc2\xb7”,对应的二进制为:“1100 0010 1011 0111”。同时“路”在Unicode字符集中的位置是“\u8def”(python中的Unicode类型),因此可以通过“\u8def”在Unicode字符集中找到“路”对应的编码为“4237”,对应的二进制为:“0100 0010 0011 0111”,由于gbk的俩个字节的高字节是为了区分中文和ASCII,所以将“1100 0010 1011 0111”高字节的“1”去掉后,就对应Unicode字符集中的0100 0010 0011 0111”。

UTF-8和Unicode与GBK的关系

​ utf-8——–decode(解码)—–>Unicode类型<——-decode(解码)—–gbk

​ utf-8<——–encode(编码)—–Unicode类型——-encode(编码)—–>gb

7. 激活函数
#

7.1 Sigmoid、ReLU、Tanh、GELU、Swish
#

7.1.1 Sigmoid(S型函数)
#

公式:

f(x)=11+ex f(x) = \frac{1}{1 + e^{-x}}

图像如下所示:

39. sigmoid.png
图像特征:

  • 输出范围在 (0, 1) 之间
  • x=0x=0 处取值为 0.5
  • x+x\to +\infty 时趋近于 1
  • xx \to -\infty 时趋近于 0

优缺点:

  • 优点:可平滑地将输入映射到有限区间
  • 缺点:存在梯度消失问题,不适合深层网络

7.1.2 ReLU(线性整流单元)
#

公式:

f(x)=max(0,x) f(x) = \max(0, x)

图像如下所示:

38. relu.png
图像特征:

  • x<0x < 0 时,输出为 0
  • x0x \ge 0 时,输出为 x
  • 输出范围:[0,+)[0, +\infty)

优缺点:

  • 优点:计算简单,梯度传播效率高,不易饱和
  • 缺点:“神经元死亡”问题(当权重更新使输出恒小于0时,梯度为0)

7.1.3 Tanh(双曲正切函数)
#

公式:

f(x)=tanh(x)=exexex+ex f(x)=tanh(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}

图像如下:

41. tanh.png
图像特征:

  • 输出范围在 (-1, 1) 之间
  • 关于原点对称(奇函数)
  • x+x \to +\infty 时,输出趋近于 1
  • xx \to -\infty 时,输出趋近于 -1
  • 在中间区域(接近 0)近似线性增长

  • 优缺点: **优点:**输出均值接近 0,有助于加快梯度下降收敛;相比 Sigmoid,饱和区间更小,梯度消失问题稍轻
  • **缺点:**当输入绝对值较大时,仍会出现饱和导致梯度消失;计算复杂度略高于 ReLU

7.1.4 GELU(高斯误差线性单元)
#

公式:

f(x)=xΦ(x)=x12[1+erf(x2)] f(x) = x \cdot \Phi(x) = x \cdot \frac{1}{2}\left[1 + \text{erf}\left(\frac{x}{\sqrt{2}}\right)\right]

其中 Φ(x)\Phi(x)为标准正态分布的累积分布函数,erf\text{erf} 为误差函数。

近似形式(更常用的计算形式):

f(x)0.5x(1+tanh[2π(x+0.044715x3)]) f(x) \approx 0.5x \left(1 + \tanh\left[\sqrt{\frac{2}{\pi}}(x + 0.044715x^3)\right]\right)

图像如下所示:

37. gelu.png

图像特征:

  • 介于 ReLU 与 Sigmoid 之间的平滑曲线
  • x<0x < 0 时有小的负输出
  • 平滑且连续

优缺点:

  • 优点:相比 ReLU 更平滑,适合 Transformer、BERT 等模型
  • 缺点:计算复杂度较高

7.1.5 Swish(自门控激活函数)
#

公式:

f(x)=xσ(x)=x1+ex f(x) = x \cdot \sigma(x) = \frac{x}{1 + e^{-x}}

图像如下所示:

40. swish.png
图像特征:

  • 介于 ReLU 与 Sigmoid 之间
  • x<0x < 0 时输出略为负值
  • 平滑且单调递增

优缺点:

  • 优点:连续可导、性能优于 ReLU
  • 缺点:计算略复杂于 ReLU

7.2 GLU()
#

GLU 的全称是 Gated Linear Unit(门控线性单元),它不是一个单纯的激化函数,而是一种 “门控机制(Gating Mechanism)”,通常出现在 序列建模、语言模型(如 Transformer、ConvSeq2Seq)中。


​ GLU 全称为 Gated Linear Unit,即门控线性单元函数。其计算过程如下:

​ 首先输入向量 xx 经过两个独立的卷积层/MLP层,得到向量 AA 和向量 BB 。此时,向量AA 和向量 BB 的公式为: A=xW+bB=xV+cA=x⋅W+b,B=x⋅V+c。然后向量 BB 经过一个 sigmoid 函数之后,σ(B)\sigma(B) 中的每个元素就都变为了0~1之间的值,就可以起到控制信息是否通过的作用。

​ 将向量 AAσ(B)\sigma(B) 逐个元素相乘之后就得到了GLU层的最终输出结果,把上面描述的整个过程结合起来,GLU的公式如下:

GLU(x)=Aσ(B)=(xW+b)σ(xV+c)(1) \text{GLU}(x)=A\otimes\sigma(B)=(x \cdot W+b) \otimes \sigma(x \cdot V+c)\tag{1}

​ 在该公式中,xx 表示输入向量,\otimes 表示两个向量逐元素相乘,σ\sigma 表示sigmoid函数。


​ 当GLU作为激活函数时一般不是上述公式的形式。激活函数 ReLU 的公式为 ReLU=max(0,x)\text{ReLU}=\max(0,x),其含义就是当输入向量 xx 的值小于 0 时直接阻断,当时输入向量 xx 的值大于 0 值直接通过。参考ReLU激活函数,激活函数GLU的公式为如下公式的形式:

GLU(x)=xσ(g(x))(2) \text{GLU}(x)=x \otimes \sigma(g(x))\tag{2}

​ 这里有一个新符号 g(x)g(x) 表示的是向量 xx 经过一层MLP或者卷积层,其他部分的符号与 公式(1) 中是相同的。可以看出 公式(2) 的右半部分与 公式(1) 的右半部分是完全一样的,所不同的是 公式(2) 中的左半部分直接就是向量 xx,这和上面描述的激活函数ReLU是相似的,当 σ(g(x))\sigma(g(x)) 趋近于 0 时表示对 xx 进行阻断,当 σ(g(x))\sigma(g(x)) 趋近于 1 时表示允许 xx 通过,以此实现门控激活函数的效果。


优缺点:

优点:

  • 能动态控制信息流,增强模型的表示能力
  • 在语言建模和序列任务中表现优异(如 CNN-based Transformer、GPT 变体)
  • 可以抑制噪声、选择性激活有用特征

缺点:

  • 引入了额外的参数和计算量(需要两个通道)
  • 不属于“逐元素非线性函数”,结构更复杂

7.3 GLU的变种
#

GLU 的问题:

  1. Sigmoid 输出区间过窄 → 容易饱和、梯度较小;
  2. 输出仅依赖线性组合 → 非线性能力有限;
  3. 在深层模型(如 Transformer FFN 层)中,ReLU / GELU 仍更高效。

因此研究者提出了一系列改进的“门控激活函数”:

ReGLU、GEGLU、SwiGLU 这些变体的主要思想是: 保留门控结构,但用更强的激活函数(ReLU、GELU、Swish)替代 Sigmoid。

7.3.1 ReGLU
#

ReGLU(A,B)=AReLU(B) \text{ReGLU}(A,B)=A \otimes \text{ReLU}(B)
  • 由 Google 的 PaLM 论文中提出。
  • 替换了 Sigmoid → ReLU,使门控具有稀疏性。
  • 优点:计算简单,梯度不易消失。
  • 缺点:不平滑,ReLU 在 0 处不可导。

7.3.2 GEGLU
#

GEGLU(A,B)=AGELU(B) \text{GEGLU}(A,B)=A \otimes \text{GELU}(B)
  • 来自《PaLM: Scaling Language Models with Pathways》(Google, 2022)。
  • 使用 GELU 代替 Sigmoid
  • GELU 是平滑非线性函数,输出接近正态分布,更自然地控制信息流。
  • 实验显示**:GEGLU 在 Transformer 的 FFN(前馈层)中效果优于 ReLU/GLU**。

7.3.3 SwiGLU
#

SwiGLU(A,B)=ASwish(B) \text{SwiGLU}(A,B)=A \otimes \text{Swish}(B)
  • 来自《T5 v1.1》和后续 LLaMA 系列模型。
  • 使用 Swish 代替 Sigmoid 门控
  • Swish 比 GELU 更连续、非单调,梯度更平滑;
  • 性能和稳定性都非常好,因此 LLaMA2 / 3、GPT-NeoX、T5.1.1、Qwen 等模型都采用它。

7.3.4 总结对比
#

  1. 引入更强的非线性:门控层的激活函数由 Sigmoid → GELU/Swish,使模型更具表达能力。
  2. 梯度传播更平滑:GELU / Swish 的平滑特性避免了 ReLU 的梯度断层问题。
  3. 计算效率提升:仍然只需一次线性层输出 2 倍维度(如 2dff2d_{ff}2dff​),再分为 A,BA,BA,B,总体代价与传统 FFN 相近。
  4. 实际验证有效
    • PaLM 论文:GEGLU 比 ReLU 提升约 0.3–0.5 BLEU / perplexity。
    • LLaMA 论文:SwiGLU 提升稳定性与收敛速度。
名称公式门控函数特点与改进
GLUAσ(B)A \cdot \sigma(B)Sigmoid最初形式,容易饱和
ReGLUAReLU(B)A \cdot \text{ReLU}(B)ReLU门控更稀疏,计算简单
GEGLUAGELU(B)A \cdot \text{GELU}(B)GELU更平滑,表现优异,已用于 PaLM
SwiGLUASwish(B)A \cdot \text{Swish}(B)Swish平滑且自适应,已用于 LLaMA、T5 v1.1、GPT-NeoX 等

GLU 变体(ReGLU、GEGLU、SwiGLU)是通过替换门控函数,使门控机制更平滑、更高效,从而增强 Transformer 的非线性表达能力和训练稳定性。 ​ 其中 SwiGLU 是目前主流大语言模型(如 LLaMA、Qwen)默认采用的版本。

7.4 FFN公式及其变体
#

​ 我们知道FFN就是输入向量 xx 先经过一个MLP层,将维度上升到原来的4倍,然后过一个激活函数层,最后再经过一个MLP层,将维度还原回去。其公式为:

FFN(x,W1,W2,b1,b2)=ReLU(xW1+b1)W2+b2 \text{FFN}(x,W_1,W_2,b_1,b_2)=\text{ReLU}(xW_1+b_1)W_2+b_2

​ 有些研究,比如T5,将实验中的偏置项去掉了,这样FFN就变为了如下形式:

FFNReLU(x,W1,W2)=ReLU(xW1)W2 \text{FFN}_\text{ReLU}(x,W_1,W_2)=\text{ReLU}(xW_1)W_2

​ 把这里的激活函数由 ReLU 替换为 GeLU 或 Swish 之后,就得到两种新的FFN,公式如下,下面这两种也都有相应的实验结果。

FFNGeLU(x,W1,W2)=GeLU(xW1)W2 \text{FFN}_\text{GeLU}(x,W_1,W_2)=\text{GeLU}(xW_1)W_2 FFNSwish(x,W1,W2)=Swish(xW1)W2 \text{FFN}_\text{Swish}(x,W_1,W_2)=\text{Swish}(xW_1)W_2

​ 使用GLU 及其各种变体替换掉 FFN 中的第一个MLP和激活函数,就可以得到如下新版的 FFN 公式:

FFNGLU(x,W,V)=[σ(xW)(xV)]W2 \text{FFN}_\text{GLU}(x,W,V)=[\sigma(xW) \otimes (xV)]W_2 FFNBilinear(x,W,V)=[(xW)(xV)]W2 \text{FFN}_\text{Bilinear}(x,W,V)=[(xW) \otimes (xV)]W_2 FFNReGLU(x,W,V)=[ReLU(xW)(xV)]W2 \text{FFN}_\text{ReGLU}(x,W,V)=[\text{ReLU}(xW) \otimes (xV)]W_2 FFNGEGLU(x,W,V)=[GELU(xW)(xV)]W2 \text{FFN}_\text{GEGLU}(x,W,V)=[\text{GELU}(xW) \otimes (xV)]W_2 FFNSwiGLU(x,W,V)=[Swish(xW)(xV)]W2 \text{FFN}_\text{SwiGLU}(x,W,V)=[\text{Swish}(xW) \otimes (xV)]W_2

8. 优化器
#

8.1 SGD
#

**概念:SGD 是最基础的优化算法。它每次使用一个样本(或小批量样本)**来估计梯度,从而更新参数。

更新公式:

θt+1=θtηθL(θt) \theta_{t+1} = \theta_t - \eta \nabla_\theta L(\theta_t)

其中:

  • θt\theta_t:模型参数
  • η\eta:学习率
  • θL(θt)\nabla_\theta L(\theta_t):损失函数关于参数的梯度

特点:

  • 简单易实现;
  • 但梯度震荡较大,容易在谷底附近来回振荡;
  • 对学习率非常敏感。

8.2 Momentum
#

**概念:**Momentum 在 SGD 基础上引入“惯性”思想,模拟小球在曲面上滚动的过程。即在当前梯度方向上考虑之前累积的更新趋势,使优化过程更平滑。

更新公式:

vt=βvt1+(1β)θL(θt) v_t = \beta v_{t-1} + (1 - \beta)\nabla_\theta L(\theta_t) θt+1=θtηvt \theta_{t+1} = \theta_t - \eta v_t

其中:

  • vtv_t:动量项(梯度的指数加权平均
  • 有时在计算完 vtv_t 还会进行修正(v0=0v_0=0),修正公式:vtcorrect=vt1βtv_t^{correct}=\frac{v_t}{1-\beta^t}
  • β\beta:动量系数,常取 0.9

特点:

  • 减少震荡,加快收敛;
  • 在鞍点处更容易逃脱;
  • 若动量过大可能导致越过最优点。

8.3 RMSProp
#

概念:RMSProp 是一种自适应学习率算法。它对每个参数的梯度平方进行指数加权平均,从而自动调整学习率大小。

更新公式:

st=βst1+(1β)(θL(θt))2 s_t = \beta s_{t-1} + (1 - \beta)(\nabla_\theta L(\theta_t))^2 θt+1=θtηst+ϵθL(θt) \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{s_t + \epsilon}} \nabla_\theta L(\theta_t)

其中:

  • sts_t:历史梯度平方的指数加权平均
  • ϵ\epsilon:防止除零的小常数(通常为 10810^{-8}

特点:

  • 对梯度大(变化剧烈)的参数自动减小学习率;
  • 对梯度小(变化缓慢)的参数自动增大学习率;
  • 收敛速度快,尤其适合非平稳目标。

8.4 Adam
#

**概念:**Adam 结合了 Momentum + RMSProp 的优点:既保留动量的加速效果,又具有自适应学习率的能力。

更新公式:

mt=β1mt1+(1β1)θL(θt) m_t = \beta_1 m_{t-1} + (1 - \beta_1)\nabla_\theta L(\theta_t) vt=β2vt1+(1β2)(θL(θt))2 v_t = \beta_2 v_{t-1} + (1 - \beta_2)(\nabla_\theta L(\theta_t))^2

(偏差校正)

m^t=mt1β1t,v^t=vt1β2t \hat{m}_t = \frac{m_t}{1 - \beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1 - \beta_2^t}

(参数更新)

θt+1=θtηv^t+ϵm^t \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{\hat{v}_t} + \epsilon}\hat{m}_t
  • 计算高效;
  • 适合大规模、稀疏梯度的任务;
  • 几乎不需要手动调整学习率;
  • 但有时会出现收敛到次优解的问题(AdamW 改进了这一点)。

8.5 AdamW
#

概念:AdamW 是对 Adam 的改进版本,用于更合理地进行权重衰减(正则化)。Adam 的原始实现中,权重衰减被隐式耦合在梯度更新中,这会影响优化方向;而 AdamW 将权重衰减与梯度更新显式分离

更新公式:

thetat+1=θtη(m^tv^t+ϵ+λθt) theta_{t+1} = \theta_t - \eta \left( \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} + \lambda \theta_t \right)

其中:

  • λ\lambda:权重衰减系数(类似于 L2 正则)

特点:

  • 避免了 Adam 的正则化偏差问题;
  • 改善了泛化性能;
  • 是现代 Transformer(如 BERT、GPT 系列)默认使用的优化器。

9. 权重衰减、正则化与梯度裁剪
#

9.1 权重衰退
#

概念

权重衰减是一种在优化过程中对权重参数进行衰减的技术,使模型的参数不会无限增大,防止过拟合。

其核心思想是:

在每次更新参数时,让参数值向零稍微靠近一点。

数学原理

在常规梯度下降中:

θt+1=θtηθL(θt) \theta_{t+1} = \theta_t - \eta \nabla_\theta L(\theta_t)

加入权重衰减后:

θt+1=(1ηλ)θtηθL(θt) \theta_{t+1} = (1 - \eta \lambda)\theta_t - \eta \nabla_\theta L(\theta_t)

其中:

  • λ\lambda:权重衰减系数(一般为 1e-4 ~ 1e-2)
  • η\eta:学习率

等价于在损失函数中加入一个 L2 正则项L=L+λ2θ2L' = L + \frac{\lambda}{2} \|\theta\|^2

实现方式

在 PyTorch 中:

optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)
  • 对于 SGDAdam 等优化器,weight_decay 参数控制衰减强度。
  • 注意: AdamW 明确将权重衰减与梯度更新分离(比 Adam 原始实现更正确)。

效果

  • 减少模型复杂度;
  • 防止权重过大导致过拟合;
  • 改善泛化性能;
  • 常用于 Transformer、CNN、RNN 等模型训练中。

9.2 正则化
#

概念:正则化是一类用于防止模型过拟合的技术,通过对模型参数或输出施加约束,使其更平滑、更具泛化能力。

常见类型:

类型数学表达式效果典型用途
L1 正则化$L’ = L + \lambda \sum_i\theta_i$
L2 正则化L=L+λ2iθi2L' = L + \frac{\lambda}{2}\sum_i \theta_i^2抑制大权重,提升泛化Ridge、神经网络
Dropout随机丢弃一部分神经元防止共适应,增强鲁棒性全连接网络
Early Stopping监控验证集损失,提前停止防止过拟合所有模型通用
BatchNorm/LayerNorm归一化激活值减小内部协变量偏移CNN/Transformer

L2 与权重衰减的关系

  • 在 SGD 中,权重衰减与 L2 正则是等价的;
  • 在 Adam / RMSProp 中,只有 AdamW 的实现才与 L2 正则严格等价;
  • 因此推荐用 AdamW(weight_decay=...) 而不是在损失中手动加正则项。

9.3 梯度裁剪
#

概念:梯度裁剪用于防止梯度爆炸(Gradient Explosion)——在反向传播时梯度过大导致参数更新剧烈,从而训练不稳定或发散。

数学原理

假设梯度向量为 gg,设定最大范数(L2范数) clip_norm\text{clip\_norm}

若:g2>clip_norm\|g\|_2 > \text{clip\_norm}

则缩放为: g=clip_normg2gg' = \frac{\text{clip\_norm}}{\|g\|_2} g

否则保持不变。这相当于“压缩”梯度向量长度。

实现方式

在 PyTorch 中:

torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)

或按数值裁剪(每个元素限制在 [-x, x]):

torch.nn.utils.clip_grad_value_(model.parameters(), clip_value=0.5)

应用场景

  • RNN / LSTM / GRU 等循环结构(梯度容易爆炸);
  • Transformer 大模型训练;
  • 一般与 AdamW 搭配使用,稳定训练过程。

10. Warm-up、学习率衰减策略、梯度检查点、梯度累加
#

10.1 Warm-up
#

**概念:**Warm-up 是在训练初期 逐步增加学习率 的策略,用于防止模型在初始阶段因为学习率过大而导致训练不稳定或梯度爆炸。

**原理:**模型刚开始训练时,参数是随机初始化的,若立即使用较大学习率,会导致 loss 振荡或发散。通过 Warm-up,学习率会从一个较小的值 线性或指数上升 到目标学习率。

常见公式(线性 warm-up):lrt=lrbase×tTwarmuplr_t = lr_{base} \times \frac{t}{T_{warmup}}

其中 tt 为当前步数,TwarmupT_{warmup}为预热步数。

**典型用法:**通常与学习率衰减(cosine、step、linear)配合使用,如 Transformer、YOLO 等模型。

10.2 学习率衰减策略
#

**概念:**学习率衰减是指在训练过程中 逐渐减小学习率 的方法,以便模型在后期更稳定地收敛。

常见策略:

  1. **Step Decay(阶梯衰减):**每隔一定 epoch 学习率下降一个固定比例。

    lr=lr0×γepoch/steplr = lr_0 \times \gamma^{\lfloor epoch / step \rfloor}

  2. **Exponential Decay(指数衰减):**学习率按指数规律下降。

    lr=lr0×ek×epochlr = lr_0 \times e^{-k \times epoch}

  3. **Cosine Annealing(余弦退火):**学习率按余弦曲线平滑下降,可周期性重启。

    lrt=lrmin+12(lrmaxlrmin)(1+cos(tTπ))lr_t = lr_{min} + \frac{1}{2}(lr_{max} - lr_{min})(1 + \cos(\frac{t}{T}\pi))

  4. **Linear Decay(线性衰减):**从初始值线性下降到某个最小值,常用于 fine-tuning。

**作用:**早期快速学习,后期稳定收敛,防止震荡。


1. 步数的定义

步(step)= 一次参数更新(optimizer.step())

也就是说,每执行一次反向传播并更新模型参数,计作 1 个训练步。

2. 步数与 epoch、batch 的关系

假设:

  • 数据集共有 N 条样本
  • 批大小(batch size)为 B
  • 梯度累加步数(gradient_accumulation_steps)为 A
  • 训练轮数(epochs)为 E

那么训练的总步数计算公式为:total_steps=NB×A×E\text{total\_steps} = \frac{N}{B \times A} \times E

举例说明

假设你的数据集有 50,000 条样本:

  • batch_size = 16
  • gradient_accumulation_steps = 4
  • epochs = 3

则:total_steps=5000016×4×3=2343.752344\text{total\_steps} = \frac{50000}{16 \times 4} \times 3 = 2343.75 \approx 2344

即整个训练过程会执行约 2344 次参数更新

10.3 梯度检查点
#

概念: 梯度检查点是一种在训练深度神经网络时 节省显存(GPU Memory) 的方法。其核心思想是:用时间换空间 —— 在前向传播阶段不保存所有层的中间激活值,只在关键节点(称为“检查点”)保存少量激活,其余部分在反向传播时通过重新计算得到。

**原理:**在普通训练中,反向传播需要用到每层的激活值,因此这些值都会被保存在显存中。而在梯度检查点机制下,只保存若干层的输出,其他层的输出在反向传播时重新计算,从而显著减少显存占用。 这种方式能让深层模型(如 Transformer、YOLOv10、LLaMA 等)在相同显存条件下支持更大的 batch 或更长的输入序列。

示意:

常规训练层1  层2  层3  层4 全部保存激活
梯度检查点仅保存层1层4的激活层2层3在反向传播时重算

效果:

  • 显存占用可降低约 30%~60%;
  • 计算时间增加约 20%~50%,因为反向传播时需要重新执行部分前向计算。

典型用途:

  • 大模型(LLM、Transformer、YOLO)训练或微调时节省显存;
  • 低显存显卡(如单卡 3090)进行大 batch 训练或长序列任务;
  • 常与 LoRA / QLoRA混合精度训练(FP16/BF16) 一起使用以进一步优化显存。

PyTorch 实现:

from torch.utils.checkpoint import checkpoint

def forward_pass(x):
    return model_block(x)

out = checkpoint(forward_pass, input)

或直接在模型中启用:

model.gradient_checkpointing_enable()

10.4 梯度累加
#

**概念:**当 GPU 显存不足以支撑大批量(batch size)训练时,可通过梯度累加来 模拟更大的 batch

**原理:**不是每次反向传播都更新参数,而是累积多次 mini-batch 的梯度,再统一更新。

**公式示例:**若希望等效 batch size = 64,但 GPU 只能放下 16,可设置:accumulation_steps=64/16=4\text{accumulation\_steps} = 64 / 16 = 4

即每 4 次反向传播后再更新一次权重。

示例代码:

for step, batch in enumerate(dataloader):
    loss = model(batch)
    loss = loss / accumulation_steps
    loss.backward()
    if (step + 1) % accumulation_steps == 0:
        optimizer.step()
        optimizer.zero_grad()

优点:

  • 在显存受限条件下稳定训练
  • 保持梯度估计精度,改善收敛性

11. 大模型推理参数
#

​ 在大模型推理的最后一步,模型输出的是一个词表大小的向量(Logits)。推理参数主要用于干预这个 Logits 向量经过 Softmax 变成最终 Token 概率分布的过程,以及控制解码路径的搜索策略。

11.1 Temperature (温度系数)
#

公式:

Pi=exp(zi/T)jexp(zj/T) P_i = \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)}
  • 其中:
    • ziz_i :模型输出的原始 Logit 值
    • TT :温度系数

解释:

  • T0T \to 0 (Low Temperature)

    • 分母上的 TT 越小,Logit 值大的项经过指数运算后会被放大得越明显。
    • 概率分布变得非常 尖锐 (Peaked),模型趋向于选择概率最高的词(Greedy)。
    • 适用场景:代码生成、数学解题(需要确定性)。
  • TT \to \infty (High Temperature)

    • 分布趋向于 均匀分布 (Uniform)
    • 概率分布变 平坦 (Flat),低概率词被选中的机会增加。
    • 适用场景:创意写作、头脑风暴(需要多样性)。

11.2 Top-k & Top-p (采样策略)
#

​ 这两种策略用于截断概率分布的“长尾”,防止模型采样到极低概率的离谱词汇。

11.2.1 Top-k (硬截断)
#

**逻辑:**只保留概率最高的 kk 个 Token,将其他 Token 的概率清零,并重新归一化剩余的 Token。

优缺点:

  • 缺点kk 是固定的。若分布很尖,大 kk 会引入噪音;若分布很平,小 kk 会切掉合理选项。

11.2.2 Top-p (Nucleus Sampling / 核采样)
#

逻辑: 按照概率从高到低排序,选取累计概率之和达到阈值 pp(如 0.9)的那一组最小的 Token 集合。

特点:

  • 动态调整:当模型确信时,候选集小;当模型犹豫时,候选集自动变大。
  • 建议:通常建议 Top-p 和 Temperature 联用(先 Top-k/Top-p 截断,后 Temperature 缩放)。

11.3 Num_beams (集束搜索)
#

用于控制解码时的搜索路径数量,从 Sampling (采样) 转向 Search (搜索)

  • Greedy Search (num_beams=1)

    • 每一步只选概率最高的一个词。
    • 缺陷:容易陷入局部最优,无法回溯。
  • Beam Search (num_beams > 1)

    • 在每一步生成时,时刻保留 num_beams 条当前总概率最高的路径。
    • 特点:寻找全局最优解,生成的句子更通顺,但计算代价大。
    • 适用场景:机器翻译、文本摘要(需要高质量、确定性的结果)。

11.4 总结对比
#

参数核心作用数学/逻辑本质建议设置 (以 Qwen3 为例)
Temperature创造力 vs. 准确性Logits 的 Scaling FactorSFT 模型通常 0.7~0.9
Top-k排除绝对错误的词固定数量截断设为 50 左右兜底
Top-p动态调整候选池大小累积概率截断 (CDF)推荐 0.9 或 0.95
Num_beams搜索质量 vs. 速度广度优先搜索变体聊天/创作设为 1;翻译设为 3-5

参考:

彻底搞懂:Batch Norm, Layer Norm, Instance Norm & Group Norm

Batch Normalization(批归一化)和 Layer Normalization(层归一化)的一些细节可能和你想的并不一样

字符编码那点事:快速理解ASCII、Unicode、GBK和UTF-8

ASCII、Unicode、GBK、UTF-8之间的关系_gbk和ascii

GLU和SwiGLU

十分钟搞明白Adam和AdamW,SGD,Momentum,RMSProp,Adam,AdamW

用梯度检查点来节省显存 gradient checkpointing

大模型训练如何计算显存占用

10分钟搞明白如何设置大模型推理参数,top_k,top_p, temperature, num_beams。温度,beam search。