Skip to content

语言模型定义及信息理论

📅 发表于 2025/06/28
🔄 更新于 2025/06/28
👁️ -- 次访问
📝 0 字
0 分钟
llm
#自回归语言模型
#温度参数
#极大似然估计
#信息量
#熵
#交叉熵
#困惑度
#N-Gram
#神经语言模型
#分词算法
#词向量
#word2vec
#BPE

语言模型

语言模型定义🎓

LM 定义

LM 定义

语言模型LM:一种对Token序列的概率分布。

  • LM可以为token序列赋予一个概率p(x1,...,xk)=?

  • LM具有卓越世界知识,才能通过概率准确评估序列好坏

    p(a kid eat an apple )>p(an apple eat a kid )
  • LM可以做生成任务,以概率p(x1:k)进行采样。

    • 但我们通常不直接从LM进行采样,因为:
      • 真实语言模型限制
      • 期望得到最佳序列,而非平均序列

N-gram

N-Gram模型
  • 定义:在n-gram模型中,xi只依赖于相邻前n-1个字符,而非整个历史 🔑。
p(xi|x1:i1)=p(xi|xi(n1):i1)
  • 例如:trigram(n=3),只依赖于前2个字符
p(cheese | the mouse ate the)=p(cheese | ate the)
  • 概率计算:基于n-gram在文中的出现次数来计算的,并做数据平滑避免0概率。
  • n-gram的限制
    • n太小:无法捕获长距离信息
    • n太大:统计上不好得到概率估计,很多都会为0.

神经语言模型🐸

神经语言模型
  • 概率由神经网络计算,而非由统计信息得出。
  • 😈上下文长度仍然受n的限制
p(xi|xi(n1):i1)=neural_network(xi(n1):i)p(cheese | ate the)=neural_network(ate the mouth)
  • 关键发展
    • RNN/LSTM:使得xi的条件分布可以依赖整个上下文x1:i1,有效使得n,但难以训练。
    • Transformer:2017年提出的新架构,再次使用上下文长度n,但利用GPU并行更易于训练。GPT-3 n=2048。

自回归LM

自回归语言模型
  • 自回归生成序列,每次生成1个token: x1,,xkxip(xi|x1:i1)

  • 可以用前馈神经网络计算每个条件概率p(xi|x1:i1)

  • 链式法则计算条件概率

p(x1:k)=p(x1)p(x2|x1)p(x3|x1,x2)p(xk|x1:k1)=i=1kp(xi|x1:i1)

温度参数T🎇

温度参数T

🔥随机性温度参数T

  • 定义:xip(xi|x1:i1)1T

  • 1T:⭐意味着压缩或放大原始概率,调整概率分布的陡峭程度,💥控制生成的随机性和多样性

  • 压缩后需要重新进行标准化,即退火调节🔥

3️⃣三种可能性

  • T = 1:概率保持不变,从原LM中正常采样
  • T > 1 (∞):大的概率会变小📉⬆️,🌟概率会被压平,趋近于均匀分布
  • T < 1 (0):大的概率会变大📈⬇️,🌟在每一步都选择最有可能的token

💡举个例子

  • T=1:p(cheese)=0.6,p(mouse)=0.4
  • T=0.5:
    • 计算:p(cheese)=0.62=0.36,p(mouse)=0.42=0.16
    • 标准化:p(cheese)=0.360.36+0.16=0.69,p(mouse)=0.360.36+0.16=0.31
  • T从10.5的变化:🔑
    • p(cheese):0.60.69略微增加 ⬆️
    • p(mouse):0.40.31略微下降 ⬇️

常用数学公式

极大似然估计(MLE)✏️

似然函数

似然函数

🤔似然和概率

概率(probability)

  • 参数已知预测结果

  • 某个事件发生概率P(x|θ)θ 已知。

  • 概率是关于结果的函数,概率和为1。

似然(likelihood)

  • 结果已知反推参数根据结果估计参数
  • 似然函数L(x|θ)x已知。给定观察到的数据/样本集合X,参数θθ1,θ2,.... 的可能性。
  • 似然是关于参数的函数,所有可能参数的似然值不一定唯一。不是概率,只是一个衡量像不像的指标。

极大似然估计

极大似然估计

📕极大似然估计

  • D为训练集,Dc是第c类样本集合,样本独立同分布。

  • 找到让样本似然/可能性最大的参数

    • 寻找最大化似然P(Dc|θc)的参数θc
  • 参数θcDc的似然

P(Dc|θc)=xDcP(x|θc)

💥 对数似然和负对数似然

  • 对数似然:乘法不好计算,所以取对数变成加法。求参数使其最大。
L(θ)=log(P(Dc|θc))=xDclog(P(x|θc))
  • 负对数似然: 由于概率[0,1]取对数导致对数似然取值为负数,所以增加负号。求参数θ使求其最小👍 。
L(θ)=xDclog(P(x|θc))

信息熵

信息/信息量/信息熵📌

信息、信息量、信息熵

信息和信息量

  • 常识:概率越低的事件,带来的信息量越大;概率越高的事件,带来的信息量越小。

  • 信息:用来消除不确定性的东西。

  • 💥信息量:衡量信息消除不确定性的程度,越不确定,信息量越大。

  • 🔑信息量的大小和信息发生的概率成反比概率越高,信息量越小;概率越低,信息量越大

  • 某事件x的发生概率为p(x),其信息量为:

I(x)=log(p(x))

信息熵/熵

  • 信息熵()为所有信息量的期望

    • 香浓理论:熵也是把变量x编码/压缩成bit串所需要的最少bit数🐮。
H(X)=i=1np(xi)log(p(xi))
  • 随机变量X的熵越大,说明不确定性也越大。

熵计算实现

熵计算代码实现

计算推导公式

  • zixilogits
  • p(xi)概率
p(xi)=ezxijezxj
  • 熵公式推导
H(X)=i=1p(xi)log(ezxijezxj)=i=1p(xi)(logezxilogezxj)=i=1p(xi)zxi+i=1p(xi)j=1logezxj=i=1p(xi)zxi+j=1logezxj

Verl-FSDP 熵计算

  • 和公式一样
python
# 计算流程
logits = output.logits
logits.div_(temperature)
logits = logits[:, -response_length - 1 : -1, :]  # (bsz, response_length, vocab_size)
log_probs = logprobs_from_logits(logits, micro_batch["responses"])
if calculate_entropy:
    if not self.config.entropy_checkpointing:
        entropy = verl_F.entropy_from_logits(logits)  # (bsz, response_length)
    else:
        entropy = torch.utils.checkpoint.checkpoint(verl_F.entropy_from_logits, logits)

# 核心方法
def entropy_from_logits(logits: torch.Tensor):
    """Calculate entropy from logits."""
    # 和公式一样
    pd = torch.nn.functional.softmax(logits, dim=-1)
    entropy = torch.logsumexp(logits, dim=-1) - torch.sum(pd * logits, dim=-1)
    return entropy

Verl-Megatron 熵计算

去掉部分分布式代码。

python
class _VocabParallelEntropy(torch.autograd.Function):
    def forward(ctx, vocab_parallel_logits: torch.Tensor) -> torch.Tensor:
        def mul_reduce(a, b):
            return (a * b).sum(dim=-1, keepdim=True)
				# 稳定性操作,避免溢出,减去最大值
        logits_max = vocab_parallel_logits.max(dim=-1, keepdim=True).values
        normalized_vocab_parallel_logits = vocab_parallel_logits - logits_max
        # exp_logits
        normalized_exp_logits = normalized_vocab_parallel_logits.exp_()
        # sum_exp_logits
        normalized_sum_exp_logits = normalized_exp_logits.sum(dim=-1, keepdim=True)
        # 计算每个logit概率
        softmax_logits = normalized_exp_logits.div_(normalized_sum_exp_logits)
        # p_i * logits_i
        sum_softmax_times_logits = mul_reduce(softmax_logits, vocab_parallel_logits)
        # 最终的熵,log_sum_exp_logits - sum_softmax_times_logits + logits_max
        entropy = logits_max + normalized_sum_exp_logits.log() - sum_softmax_times_logits
        ctx.save_for_backward(vocab_parallel_logits, softmax_logits, sum_softmax_times_logits)
        return entropy.squeeze(dim=-1)

    def backward(ctx, grad_output: torch.Tensor) -> torch.Tensor:
        vocab_parallel_logits, softmax_logits, sum_softmax_times_logits = ctx.saved_tensors
        # reuse softmax_logits as grad
        vocab_parallel_logits.sub_(sum_softmax_times_logits)
        softmax_logits.mul_(vocab_parallel_logits)
        softmax_logits.mul_(grad_output.unsqueeze(dim=-1))
        # recover vocab_parallel_logits
        vocab_parallel_logits.add_(sum_softmax_times_logits)
        softmax_logits.mul_(-1)
        return softmax_logits

KL散度/相对熵

KL 散度 (K1):无偏但高方差

相对熵/KL散度

KL散度定义

  • 衡量两个分布之间的差异

    • p和q越接近,KL散度越小;p和q相同时,为0。
    • KL(q, p):从分布q出发,到分布p的距离。但不是真的距离。
  • 用模型p来近似真实数据分布q时,造成的信息损失。

    • 本以为数据是按p分布的,但实际上数据是按q分布的。
    • KL(q, p):错误认知的代价。

数学公式

  • 第一个参数q真实分布、参考分布旧策略。分子,期望是从q中采样的。
  • 第二个参数p近似分布、模型分布新策略。分母;
DKL(||)=x(x)(x)log(x)(x)=Ex(x)[log(x)(x)]DKL(q,p)=xq(x)q(x)logq(x)p(x)=Exq(x)[logq(x)p(x)]
  • 另一种写法
DKL(q,p)=Exq(x)[logq(x)p(x)]=Exq(x)[logp(x)q(x)]=Exq(x)[logr]
  • k1
k1=logp(x)q(x)=logr=logq(x)p(x)

KL散度和交叉熵、信息熵的关系

DKL(q||p)=i=1nq(xi)logq(xi)p(xi)=(xXq(x)logp(x))p去近似q的交叉熵(xXq(x)log(q(x)))q/
K1 缺点

k1定义

  • 从q(x)取数据,计算多个k1(xi),然后求平均,近似KL值。
k1=logp(x)q(x)=logr=logq(x)p(x)r=p(x)q(x)
  • 无偏差只要采样样本足够多,平均值就会收敛,没有系统偏差
Exq[k1]=Exq[logq(x)p(x)]

缺点

  • 方差高。
    • k1, 当q(x)>p(x)q(x)<p(x)时,方差很大。
  • 例子
    • 真实KL[q,p]=0.01
    • 但样本 1.5, -0.8, 2.1, -3.0, 0.2, .,离均值0.01非常远,高方差。估计值不稳定

K2:低方差但有偏

K2

定义

k2=12(logp(x)q(x))2=12(logr)2

低方差

  • 永远非负。不会像k1那样正负跳跃。而且KL散度本身也是非负,更切合。
  • 平方。不关心谁大谁小,只关心差异的大小。

K2有偏的

Exq[k2]KL(q,p)

为何是有偏的

  • f散度
Df(p,q)=Exq[f(p(x)q(x))]
  • KL散度和k2
KLf(x)=log(x)k2:f(x)=12(log(x))2
  • KL和K2不同,会有一些偏差,但实验显示偏差其实很小;但方差大大降低

K3:无偏且低方差

K2

核心思想

  • 使用k1无偏估计增加r-1保证期望不变同时降低方差
    • r-1期望为0

K3定义

  • k1r
k1=logr=logp(x)q(x)=logq(x)p(x)r=p(x)q(x)
  • k3定义
k3=(r1)+k1=(r1)logrk3=p(x)q(x)1logp(x)q(x)

为何无偏

  • 公式推导出来是无偏的E[k3]=E[k1]+E[r1]=KL(q,p)+0=KL(q,p)

为何方差低

  • 同k2,永远非负,避免正负大波动x>0,logxx1(r1)logr>0

实现代码

交叉熵

交叉熵

👫交叉熵

  • 交叉熵:估计模型和真实概率分布之间的差异,q去近似p的熵。
H(p,q)=(xXp(x)logq(x))q去近似p的交叉熵=DKL(p||q)KL+H(p)
  • 实际应用yy为真实分布,yy为预测分布,用交叉熵去判断准确度
H(y,y)=iyilogyi=iylogy
  • 交叉熵简化:在训练过程中,标签通常采用one-hot编码,真实概率分布p(xi)=1,简化:
H(p,q)=xXlogq(x)
  • 交叉熵loss:交叉熵求平均,越小越好。
CE=1N(logp(x1)+logp(x2|x1)++logp(xn|x1,x2,xn1))=1Nlogp(x1x2xn)

困惑度

困惑度

😕困惑度

  • 困惑度:评估语言模型的基本准则,模型生成某个语料(句子)的概率
    • 模型重构输入的能力、模型原封不动还原原始语料的概率。
    • 1n:做归一化,惩罚因子,避免太长导致数值很低
ppl=p(x1x2xn)1n=eCE=2
  • 困惑度和交叉熵的推导
nCE=logp(x1x2xn)p(x1xn)=2nCEppl=p(x1xn)1nppl=(2nCE)1n=2CE

下面是一个pytorch计算交叉熵loss的一个真实示例:

python
# 输入数据
import torch
input=torch.rand(4,3)
tensor([[0.0515, 0.6730, 0.2852],
        [0.0362, 0.3434, 0.7450],
        [0.7136, 0.6566, 0.2402],
        [0.6989, 0.0917, 0.7857]])
# log soft max 计算
output=torch.nn.LogSoftmax(dim=1)(input)
tensor([[-1.4170, -0.7956, -1.1834],
        [-1.4796, -1.1724, -0.7708],
        [-0.9429, -0.9999, -1.4163],
        [-0.9691, -1.5762, -0.8823]])

# 假设标签为 
[1, 0, 2, 1]

# 手动计算loss
loss=−(−0.79561.47961.41631.5762)/4=1.3169

# pytorch计算loss,pytorch entropyloss 自动有softmax,而nllloss则无
target = torch.tensor([1,0,2,1])
loss = torch.nn.CrossEntropyLoss()
output = loss(input, target)
tensor(1.3169)

分词和词向量

中文分词算法🐒

英文使用空格,但中文没办法,具有以下难点。

  • 分词标准不统一:“花草” 或 “花” “草”?
  • 切分歧义:如“商务处女干事”,"商务/处女/干事" or “商务处/女干事”?
  • 未登录词:新词的影响远超歧义切分,难度更大。
基于词典的分词算法

最大匹配法

  • 正向最大匹配法:从左到右匹配,匹配度越长越好
  • 逆向最大匹配法:从右到左匹配,匹配度越长越好
  • 双向匹配分词法:两者混合使用,选择二者词汇数量较少者。

全切分路径选择法

核心思想:所有切分结果全部选出来,从中选择最佳的

  • n最短路径选择:切分结果组成有向无环图,找到总词频最大的切分路径
  • n元语法模型:采用n最短路径时,考虑词的上下文关系。
基于统计的分词算法

核心:转换成序列标注问题B(开始) E(结束) M(中间) S(一个字表示的词)

  • 😈隐马尔可夫模型:观测序列/隐藏序列,条件转移概率.... jieba使用这个。
  • 😕条件随机场:详细看这里。
  • 💥深度学习/大模型:直接输出分词结果。

大模型分词🐹

tokenize的有3种粒度

  • Word-词:词级别独立语义,中文依赖分词算法,但长尾问题会导致词表超级大难以训练,一般不能超过5w。
  • Char-字符:字符,字符有限太少会导致字符承载的信息太多,难以训练。
  • Subword-子词:介于词和字符之间,平衡了词汇量和语义独立性。常用词保持原状,生僻词拆分成子词。

主要的分词算法

BPE(Byte Pair Encoding)

1、BPE(Byte Pair Encoding)

  • 将最常见的子词对合并直到词汇表到达既定大小
  • 步骤:先拆分成字符,再选择出现频率最高的相邻子词进行合并

2、WordPiece

  • BPE变种,使用语言模型概率来合并子词,而非采用出现频率。
  • 合并两个字符串A和B,应有最大的P(AB)P(A)P(B)

3、Unigram

  • 从一个大词汇表出发,逐渐删除一些词汇,直到词汇表达既定大小。
  • 选择删除词汇:使预定义的loss最小,挑出使loss增长最小的10%-20%词汇来删除。
  • 一般Unigram算法会与SentencePiece算法连用。

4、SentencePiece

  • 把句子当做整体,再拆成片段,使用BPE或Unigram算法来构造词表。

词向量🐫

参见之前的旧笔记:

1、早期one-hot编码存在的问题

  • 词汇表超级大,经常百万以上。
  • 词向量彼此正交,没有体现词和词之间的相互关系

2、通过训练把词向量映射到较短向量,Word2Vec

word2vec

🧠核心思想

  • 基于word和context做文章,学习word和context的co-occurrence。
  • 通过训练一个隐藏层神经网络,输入one-hot,输出one-hot,隐藏层则为词向量

🌟优点

  • 🚀极快的训练速度
    • 纯学词嵌入,大大简化模型,抛弃之前LM的MLE/困惑度等内容。
    • 利用HSoftmax负采样做加速,小时级别训练完成,之前LM要几周。
  • 🤴👸一个很酷炫的man-woman=king-queen的示例,使词向量成为一个热门研究方向,不只是参数。
  • 相比one-hot极大提升🆙,保留词间关系,词向量维度由大V降为d,d远小于V。
  • word2vec里有大量的tricks。
CBOW & SKIP-Gram

Skip-Gram

  • 核心思想:中心词c预测上下文o。中心词向量预测每个上下文词向量,根据各位置算loss。
  • 适用场景:适合大数据集
  • 缺点:基于窗口的模型,无法使用语料库中的共现统计,导致次有词向量

CBOW

  • 核心思想:上下文预测中心词。上下文向量求平均与中心词向量,越相近越好。
  • 适用场景:适合小数据集
  • 缺点:基于窗口的模型,无法使用语料库中的共现统计,导致次有词向量

优化提效技巧

  • 层次化softmax
    • 原词向量✖️矩阵后求平均 直接在输入测onehot词向量求平均
    • 原隐藏层到输出层矩阵W 哈夫曼树
      • 叶节点个数代表词汇数量,根节点到叶节点的路径决定了词向量
  • 💥负采样
    • 问题:期望设计一种方法每次只更新一部分权重,那么计算复杂度将大大降低
    • 核心思想:不采样整个词表,仅采样少数负样本,来进行计算代替整个词表。
      • 采样:可从噪声分布Pn(w)中进行负采样,采样概率可与词频相关。
    • 优点:加速模型计算,保证模型训练效果。
      • 每次只更新采样词的权重,不更新所有权重。👍
总访客数:   ·   总访问量:
PLM's Blog @ 2016 - 2025