Hugging Face Transformers 中的困惑度(PPL)评估:从公式到 GPT-2 滑动窗口实战
Hugging Face Transformers 中的困惑度PPL评估从公式到 GPT-2 滑动窗口实战【免费下载链接】transformers Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers本文基于 Transformers 官方文档《固定长度模型的困惑度》perplexity.md展开系统讲解语言模型困惑度Perplexity, PPL的数学定义、固定上下文长度带来的评估难点以及滑动窗口sliding window评估策略的原理并结合 GPT-2 在 WikiText-2 上的完整代码示例深入到 Transformers 源码中ForCausalLMLoss的实现层面说明“把重复的上下文 token 置为 -100 来避免重复计损”这一关键技巧为何成立。读完后你将能够正确区分因果语言模型与掩码语言模型的 PPL 适用性、实现可复制的 PPL 评估脚本并理解 stride 参数对最终 PPL 数值的影响机制。一、什么是困惑度以及它适用于哪些模型困惑度PPL是评估语言模型最常用的指标之一。在给公式之前必须先明确一个前提PPL 只定义于经典语言模型因果/自回归语言模型causal LM之上对于 BERT 这类掩码自回归填充式语言模型PPL 并没有良好定义参见官方文档中的模型概述 model_summary。对于符号序列 (X (x_0, x_1, \dots, x_t))其困惑度定义为$$\text{PPL}(X) \exp \left{ {-\frac{1}{t}\sum_i^t \log p_\theta (x_i|x_{i}) } \right}$$其中 (\log p_\theta (x_i|x_{i})) 是模型在第 (i) 个位置上、以全部前置 token (x_{i}) 为条件时对 token (x_i) 的对数概率。直观上PPL 衡量的是模型在一段数据上“平均每 token 预测的等效候选数”——数值越低模型对该序列的预测越确定。两个必须牢记的性质PPL 等于数据分布与模型预测之间交叉熵的指数因此它与 loss 直接挂钩可以直接用模型的训练损失来换算tokenizer 的选择会直接影响 PPL不同的分词方式会产生不同的 token 数 (t) 与不同的 token 概率因此比较不同模型的 PPL 时必须保证使用同一套 tokenizer 与同一段数据。二、固定长度模型的核心难题上下文被截断怎么办如果模型不受上下文长度限制理想的 PPL 计算方式是逐 token 解析整个序列每一步都用完整的前缀作为条件即逐步计算 (p_\theta(x_t | x_{t}))。但实际模型都有输入长度上限。以 GPT-2文档示例中的max_length model.config.n_positions读到的正是这个值。当 (t 1024) 时(p_\theta(x_t|x_{t})) 无法直接计算只能做近似。近似策略有两种1分块法chunked——非最优近似。把序列切成若干与模型最大输入等长的独立块每块单独做一次前向并各自计算 NLL再取平均。优点是速度快每块只需一次前向扫描缺点是大多数预测步骤里模型看到的上下文远小于理想情况通常会导致 PPL 偏高变差。2滑动窗口法sliding window——更接近真实分解。让上下文窗口沿序列逐步滑动使得每次预测时模型都能拿到尽可能多的前置上下文。理想极限是每次只滑动 1 个 token但这样每个数据 token 都要触发一次前向代价极大。实践中通常取一个折中以固定步长stride移动窗口比如每次前进 512 个 token这样既显著加速又保证每一步预测时模型至少拥有约 512 个 token 的上下文前提是前文足够长。三、实战用 GPT-2 在 WikiText-2 上计算 PPL下面是完整可运行的评估脚本与官方文档示例一致依赖transformers、datasets、torch。3.1 加载模型与数据from transformers import GPT2LMHeadModel, GPT2TokenizerFast device cuda model_id openai-community/gpt2-large model GPT2LMHeadModel.from_pretrained(model_id).to(device) tokenizer GPT2TokenizerFast.from_pretrained(model_id)from datasets import load_dataset test load_dataset(wikitext, wikitext-2-raw-v1, splittest) encodings tokenizer(\n\n.join(test[text]), return_tensorspt)WikiText-2 测试集很小且只做单轮前向扫描因此可以直接把整份数据一次性编码进内存encodings.input_ids形状为[1, seq_len]。3.2 滑动窗口评估循环核心思路把input_ids同时作为labels传入模型模型会返回“每个 token 的平均负对数似然NLL”作为 loss。但在滑动窗口中相邻窗口之间存在重叠——这些重叠 token 在当前窗口里只是“上下文”不应再次计入损失。解法是把它们对应的 label 置为-100ignore_index使损失计算自动跳过import torch from tqdm import tqdm max_length model.config.n_positions # GPT-2 的 1024 stride 512 seq_len encodings.input_ids.size(1) nlls [] prev_end_loc 0 for begin_loc in tqdm(range(0, seq_len, stride)): end_loc min(begin_loc max_length, seq_len) trg_len end_loc - prev_end_loc # 最后一轮可能与 stride 不同 input_ids encodings.input_ids[:, begin_loc:end_loc].to(device) target_ids input_ids.clone() target_ids[:, :-trg_len] -100 # 重叠的上下文部分不计损 with torch.no_grad(): outputs model(input_ids, labelstarget_ids) # 注意模型内部会把 logits/labels 左移一位对齐token n 预测 n # 因此实际参与损失计算的是 trg_len - 1 个目标位置 neg_log_likelihood outputs.loss nlls.append(neg_log_likelihood) prev_end_loc end_loc if end_loc seq_len: break ppl torch.exp(torch.stack(nlls).mean())参数含义速览变量含义说明max_length模型最大输入长度来自model.config.n_positionsGPT-2 默认 1024stride窗口滑动步长越小上下文越充分、PPL 越低但前向次数越多trg_len当前窗口中真正计入损失的 token 数最后一轮通常不等于stride-100损失忽略索引label 为 -100 的位置不参与交叉熵ppl最终困惑度对各窗口 NLL 取平均后再取指数3.3-100忽略机制的源码依据代码中target_ids[:, :-trg_len] -100这一行是否安全取决于框架是否真的会忽略 -100。从源码可以确认两点其一GPT2LMHeadModel.forward 的 docstring 明确声明labels的取值范围是[-100, 0, ..., config.vocab_size - 1]所有等于 -100 的 label 都会被忽略masked损失只对[0, ..., config.vocab_size - 1]中的 label 计算当labels is not None时forward 调用self.loss_function(logits, labels, vocab_size...)得到outputs.loss。其二默认的loss_function是 ForCausalLMLoss它先对 labels 做左移一位的因果对齐labels[..., 1:]使“位置 n-1 的 logits 预测 token n”再交给 fixed_cross_entropy——后者直接调用nn.functional.cross_entropy(..., ignore_index-100, reductionmean)。这正好解释了文档注释中的两点细节“模型只在trg_len - 1个标签上计算损失因为内部会左移一位”——左移由ForCausalLMLoss中的 pad labels[..., 1:]完成“损失使用 CrossEntropyLoss 对有效标签求平均”——即reductionmean且 -100 位置被ignore_index自动排除。因此把窗口重叠部分的 label 置 -100等价于告诉损失函数“这部分 token 只作上下文、不参与统计”各窗口的 NLL 拼接起来就是无重复计损的完整序列分解近似。四、stride 对结果的影响与经验数值文档给出了 GPT-2 large 在 WikiText-2 上的参考数值tokenizer 为该模型自带的 BPE策略strideWikiText-2 PPL分块法无重叠1024等于max_length19.44滑动窗口51216.45GPT-2 原论文报告值—19.93三点解读stride max_length时滑动窗口退化为无重叠的分块法即第二节中“非最优近似”得到的 19.44 与 GPT-2 论文报告的 19.93 基本一致差异来自 tokenizer/数据细节说明该实现与论文口径是可对标的换成stride 512后 PPL 从 19.44 降到 16.45——stride 越小每步预测可用的上下文越多PPL 通常越接近“完整前缀分解”的理想值但前向次数相应增加因此引用或比较 PPL 时必须同时说明 stride或是否滑动窗口否则不同数字可能仅反映评估协议差异而非模型能力差异——这正是文档反复强调“tokenizer 与评估方式必须纳入比较条件”的原因。五、小结与适用边界PPL 仅适用于因果语言模型对 BERT 等掩码式模型没有良好定义PPL 数据与模型分布交叉熵的指数可直接由model(input_ids, labelstarget_ids).loss换算ppl exp(NLL 平均)固定上下文长度下滑动窗口是比独立分块更忠实于序列概率分解的近似代价是每个 token 需要更多前向labels中置-100的 token 会被 ForCausalLMLoss 中的ignore_index机制忽略从而实现窗口重叠部分不重复计损比较 PPL 时模型、tokenizer、数据与 stride 四者必须全部对齐数字才有可比性。本文代码与结论均以当前仓库源码为准涉及 GPT-2 的实现可进一步参阅 modeling_gpt2.py 与 loss_utils.py。【免费下载链接】transformers Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

银河麒麟Arm系统源码编译GCC 12.1全攻略:从依赖配置到避坑指南

银河麒麟Arm系统源码编译GCC 12.1全攻略:从依赖配置到避坑指南

简介:本资源为专适银河麒麟ARM架构操作系统的GCC 12.01编译器完整安装包,面向国产化平台开发者、嵌入式与服务器端C/C工程师及信创领域技术实践者,解决在鲲鹏等ARMv8-A硬件上缺乏高版本GCC支持、难以直接启用C20/23新特性、优化编译性能及安全…

2026/11/12 2:15:56 阅读更多 →
IOPaint Windows 快速安装教程:4 个高频卡点逐个击破,本地 AI 修图工具装完即用

IOPaint Windows 快速安装教程:4 个高频卡点逐个击破,本地 AI 修图工具装完即用

IOPaint Windows 快速安装教程:4 个高频卡点逐个击破,本地 AI 修图工具装完即用 【免费下载链接】IOPaint Image inpainting tool powered by SOTA AI Model. Remove any unwanted object, defect, people from your pictures or erase and replace(powe…

2026/10/25 16:18:04 阅读更多 →
圣女祸乱塞布里克:梦幻模拟战托伊瓦尔篇悬念拆解与剧情复盘指南

圣女祸乱塞布里克:梦幻模拟战托伊瓦尔篇悬念拆解与剧情复盘指南

《梦幻模拟战》手游的托伊瓦尔篇已经更新到很深的阶段,剧情讨论的热度却一点没降。最近很多玩家都在聊“圣女祸乱塞布里克”这条线,尤其是王储失踪的真相揭晓后,前面几十个章节留下的伏笔突然被串了起来。说实话,如果不把前一阶段…

2026/11/7 22:22:32 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/12 5:00:00 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/12 5:13:20 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/12 5:13:20 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/11 17:16:37 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/11 17:16:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/12 5:13:20 阅读更多 →

日新闻

周新闻

月新闻