语言模型(Language Modeling)中的评估指标理解与总结

引言

语言模型(Language Model,LM),即给出一句话的前k个token,希望它可以预测第k+1个token是什么,即给出一个第k+1个token可能出现的概率的分布 p ( x k + 1 ∣ x 1 , x 2 , . . . , x k ) p(x_{k+1}|x_1,x_2,...,x_k) p(xk+1x1,x2,...,xk)

本文试图理清Language Modeling的评估指标基本计算过程和指标含义,目的有二:
(1)本文介绍的评估指标对于机器学习或者NLP从业人员来说是比较常用,但未必系统学习过、未必能说清楚这些指标之间的关系和指标本身的含义,掌握这些知识不管是对工作、求职面试都是有帮助的。
(2)企图设计新的指标为本人进一步的AGI模型的建模研究做铺垫,这是主要的。

交叉熵(Cross-Entropy)

定义

在language modeling中,要评价训练模型的好坏,可以通过度量模型预测序列Q和真实序列P的分布之间的差异来评价。相对熵的定义恰好就是度量两个分布差异的,相对熵又称Kullback-Leibler散度(简称KL散度)。那实际language modeling及其他机器学习问题中为什么很少用相对熵而用交叉熵呢?用关于信息熵、相对熵、交叉熵的定义、关系及推导可以参考本人另一篇文章《度量方法总结》。此处不再详细介绍,下面直接给出几个主要计算公式。
信息熵H(P(X)):
H ( P ( X ) ) = E [ f ( x i ) ] = − ∑ i n P ( x i ) l o g   P ( x i ) \begin {alignedat}{2} H(P(X))&=E[f(x_i)] \\ &=-\sum_i^n P(x_i) log\ P(x_i) \end {alignedat} H(P(X))=E[f(xi)]=inP(xi)log P(xi)

相对熵 D K L ( P ( X ) ∣ ∣ Q ( X ) ) D_{KL}(P(X)||Q(X)) DKL(P(X)∣∣Q(X))
D K L ( P ( X ) ∣ ∣ Q ( X ) ) = ∑ i = 1 n P ( x i ) l o g ( P ( x i ) Q ( x i ) ) \begin {alignedat}{2} D_{KL}(P(X)||Q(X)) = \sum_{i=1}^nP(x_i)log(\frac{P(x_i)}{Q(x_i)}) \end {alignedat} DKL(P(X)∣∣Q(X))=i=1nP(xi)log(Q(xi)P(xi))

交叉熵 H ( P ( X ) , Q ( X ) ) H(P(X),Q(X)) H(P(X),Q(X))
H ( P ( X ) , Q ( X ) ) = − ∑ i = 1 n P ( x i ) l o g ( Q ( x i ) ) \begin {alignedat}{2} H(P(X),Q(X)) = −∑_{i=1}^{n}P(x_i)log(Q(x_i)) \end {alignedat} H(P(X),Q(X))=i=1nP(xi)log(Q(xi))
三者之间的关系:
D K L ( P ( X ) ∣ ∣ Q ( X ) ) = − H ( P ( X ) ) + H ( P ( X ) , Q ( X ) ) \begin {alignedat}{2} D_{KL}(P(X)||Q(X)) =-H(P(X))+H(P(X),Q(X)) \end {alignedat} DKL(P(X)∣∣Q(X))=H(P(X))+H(P(X),Q(X))

深入理解

引用香农在信息论中的一句话:“Entropy can be interpreted as the average number of bits required to store the information in a variable.”这句话意思就是说当我们的熵,也就是Entropy越小时,存储信息需要的bits数越少,因为信息的结构更有序了。
从bits数视角看:

信息熵H(P(X))是存储真实序列P所需的平均bit数;
相对熵 D K L ( P ( X ) ∣ ∣ Q ( X ) ) D_{KL}(P(X)||Q(X)) DKL(P(X)∣∣Q(X))是基于预测的Q序列来编码真实序列P所需要的额外bit数;
交叉熵 H ( P ( X ) , Q ( X ) ) H(P(X),Q(X)) H(P(X),Q(X))是存储真实序列P所需的平均bit数与基于预测的Q序列来编码真实序列P所需要的额外bit数的总和。

从评价语言/模型的角度说,如果基于预测的Q序列来编码真实序列P所需要的额外bit数越少,即相对熵越小,那么模型从从真实序列P中学习到的知识也越多。
从优化的角度说,相对熵和交叉熵都能达到相同的优化效果,但交叉熵计算更简单一些。

BPC(Bits-Per-Character)

在language modeling中,BPC也是衡量预测序列Q和真实序列P之间差异的指标,只不过做了一下平均。BPC和Cross-Entropy之间有如下计算关系:
BPC = 1 T ∑ i = 1 T H ( P ( X ) , Q ( X ) ) \text{BPC} = \frac {1} {T} \sum^T_{i=1} H(P(X),Q(X)) BPC=T1i=1TH(P(X),Q(X))
也就是说BPC/BPW是cross-entropy对字符/单词长度T的平均,可以很容易地得出它的信息论含义:
基于预测的Q序列来编码P序列所需要的额外bit数在句子长度上的平均,也就是平均每一个字母/单词需要额外的bit数。这也是它名字的由来,也是我们为什么要从存储bit数量的角度来解释Cross-Entropy。
注意:T这里是字符/单词的个数,不是token的数量,因为不同编码方式下token可能是不一样的。

PPL(Perplexity)

定义

PPL也是用来衡量语言模型好坏的指标。它主要是根据每个词来估计一句话出现的概率,并用句子长度n作normalize,PPL的计算公式推导:
PPL = 2 H ( P ( X ) , Q ( X ) ) = 2 1 n ∑ i = 1 n H i ( P ( X ) , Q ( X ) ) = 2 1 n ∑ i = 1 n ∑ j = 1 n − P ( x j ) log ⁡ 2 Q ( x j ) = 2 − 1 n ∑ i = 1 n log ⁡ 2 Q ( x i ) = ( ∏ i = 1 n Q ( x i ) ) − 1 n = p ( x 1 , x 2 , . . x n ) − 1 n \begin {align} \text{PPL} &=2^{H(P(X),Q(X))} \\ &= 2^{\frac{1}{n} \sum_{i=1}^n {H_i(P(X),Q(X))}}\\ &= 2^{\frac{1}{n} \sum_{i=1}^n \sum_{j=1}^n -P(x_j) \log_2^{Q(x_j)}}\\ &= 2^{-\frac{1}{n} \sum_{i=1}^n \log_2^{Q(x_i)}}\\ &= (\prod_{i=1}^n{Q(x_i)})^{-\frac{1}{n}}\\ &= p(x_1,x_2,.. x_n) ^{-\frac{1}{n}}\\ \end {align} PPL=2H(P(X),Q(X))=2n1i=1nHi(P(X),Q(X))=2n1i=1nj=1nP(xj)log2Q(xj)=2n1i=1nlog2Q(xi)=(i=1nQ(xi))n1=p(x1,x2,..xn)n1
这里有几点细节需要注意理解:

  • 底数取2并不是必须的,取自然对数底 e e e或者其他值对计算结果并没有影响,取2更容易从bit数角度理解。
  • 式(2)对句子的n个token都计算了交叉熵并求和取平均值,取平均的目的是为消除句子长度不一对困惑值的影响。
  • 式(3)中真实值P(x)采用one-hot编码时会得到式(4)。
  • 式(5)采用uni-gram语言模型(一元语言模型)作为假设条件时会得到式(6),其采用了单个token概率独立的简化假设,即token序列的概率等于每个token概率的乘积。
  • 式(6)中 p ( w 1 , w 2 , . . w n ) − 1 n p(w_1,w_2,.. w_n) ^{-\frac{1}{n}} p(w1,w2,..wn)n1取的是概率倒数的几何平均,概率越大,倒数越小,几何平均越小;取几何平均的目的是为消除句子长度的影响,否则当句子的长度越长时,概率倒数反而会越大这。

Perplexity的影响因素

  1. 训练数据集越大,PPL会下降得更低,1billion dataset和10万dataset训练效果是很不一样的;
  2. 数据中的标点会对模型的PPL产生很大影响,一个句号能让PPL波动几十,标点的预测总是不稳定;
  3. 预测语句中的“的,了”等词也对PPL有很大影响,可能“我借你的书”比“我借你书”的指标值小几十,但从语义上分析有没有这些停用词并不能完全代表句子生成的好坏。

所以,语言模型评估时我们可以用perplexity大致估计训练效果,作出判断和分析,但它不是完全意义上的标准,具体问题还是要具体分析。

pytorch实现:

def evaluate(model, val_dataloader, config):
    model.eval()
    total_val_loss = 0
    with torch.no_grad():
        for step, batch in enumerate(val_dataloader):
            batch[0].clone().detach().to(config.device)
            batch[1].clone().detach().to(config.device)
            loss, logits = model(batch[0], token_type_ids=None, attention_mask=(batch[0] > 0), labels=batch[1])
            if isinstance(model, torch.nn.DataParallel):
                loss = loss.mean()
            total_val_loss += loss.mean().item()
    average_val_loss = total_val_loss / len(val_dataloader)
    perplexity = math.exp(average_val_loss)
    return loss, perplexity

总结

  1. 困惑度的计算和比较中有诸多陷阱参见文献 [1],一些细节上的差错会导致不同方法或者不同工作中的PPL不可比较。如果哪天你惊喜地发现自己的模型PPL超越了SOTA,很可能是你用错误的方法计算了PPL,需要仔细检查,下面是一些可以关注的点:
    • 当使用PPL来评估语言模型时,需要固定数据集,并确保数据集的预处理等细节与比较对象一致。
    • 当使用PPL来评估生成质量时,确保使用同一个打分的语言模型PPL定义中使用了 ,但是一般使用pytorch, tensorflow中实现的交叉熵 ,所以直接使用交叉熵计算的PPL与定义会有一些差距,最好确定比较对象的具体计算方式。
    • 对于同样的数据集,采用不同的分词方式可能会有很大的PPL差别,不可直接用于比较。比如使用字符级别(character), 子词级别(subword)或者词语(word)级别来分词。特别是像上述的采用了不同粒度分词的模型问题会更大。
  2. 使用BPC指标可以解决PPL指标某些条件下存在的不可比较问题。

参考资料

[1].Evaluation Metrics for Language Modeling,2019.10.18
[2].Perplexity of fixed-length models.
[3].一文搞懂Language Modeling三大评估标准, 硅谷谷主
[4].https://zhuanlan.zhihu.com/p/114432097
[5].https://blog.csdn.net/qq_41775769/article/details/121796159

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值