Transformers generate 怎样读取每条序列的分数
来源:17golang原创
时间:2026-11-01 03:21:44 249浏览 收藏
如果只调用 model.generate(),通常先拿到的是 token 序列;想知道每一步选中的 token 分数,不能只在返回值上猜字段,而要在调用时同时打开 return_dict_in_generate=True 和 output_scores=True。前者把结果变成带字段的输出对象,后者保留每个生成步的词表分数。随后用 compute_transition_scores() 把“选中的 token”与对应分数对齐。
官方文档:https://huggingface.co/docs/transformers/main_classes/text_generation
return_dict_in_generate决定是否返回包含可选字段的 ModelOutput,output_scores决定是否保留生成阶段的分数。outputs.scores是按生成步组织的词表分数,不能直接当作每条序列的最终总分。- decoder-only 模型要从输入长度之后切出生成 token;beam search 还要把
beam_indices交给对齐函数。
先让 generate 返回分数,而不是只返回 token 序列
这两个开关解决的是不同问题。return_dict_in_generate=True 让返回值拥有 sequences、scores 等命名字段;output_scores=True 才会要求生成过程保留各步预测分数。只开前者,可能得到一个有字段但没有逐步分数的结果;只关注后者,又无法稳定地按字段读取。
from transformers import AutoModelForCausalLM, AutoTokenizer
model_name = "openai-community/gpt2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)
inputs = tokenizer("The quick brown", return_tensors="pt")
outputs = model.generate(
**inputs,
max_new_tokens=4,
return_dict_in_generate=True, # 让结果带有 sequences、scores 等字段。
output_scores=True, # 保留每个生成步的词表分数。
)
print(outputs.sequences.shape)
print(len(outputs.scores)) # 通常对应实际生成的步数。
outputs.sequences 保存最终 token 序列,outputs.scores 是一个按生成步排列的元组;每个元素通常包含当前批次中各候选 token 的分数。它们的用途不同:前者回答“生成了什么”,后者回答“每一步候选的模型分数是什么”。

用 transition scores 把分数对齐到生成 token
如果直接遍历 outputs.scores,你拿到的是每一步完整词表的分数,仍要知道最终序列在每一步选中了哪个 token。compute_transition_scores() 会根据序列、逐步分数和可选的 beam 路径,提取每个已选 token 对应的分数。
transition_scores = model.compute_transition_scores(
outputs.sequences,
outputs.scores,
normalize_logits=True, # 转成可比较的对数概率,便于解释。
)
# decoder-only 模型的序列包含输入提示词,所以从输入长度后开始对齐。
input_length = inputs.input_ids.shape[1]
generated_tokens = outputs.sequences[:, input_length:]
for token_id, score in zip(generated_tokens[0], transition_scores[0]):
# 只打印生成部分,避免把提示词误当作模型新生成内容。
token_text = tokenizer.decode(token_id)
print(token_id.item(), token_text, float(score))
这里最容易错的是切片位置。对 decoder-only 模型,sequences 包含原始输入,所以 input_length 是输入 token 数;对 encoder-decoder 模型,文档示例通常把它视为解码端起始位置,不能机械套用 decoder-only 的切片。文章的重点是让 token 与分数使用同一段生成区间,而不是把输入提示词算进生成评分。
beam search 需要额外保留路径信息
贪心或采样场景通常只需要 sequences 和 scores。使用 beam search 时,一个最终序列可能在不同时间步来自不同 beam,单独按批次下标读取分数会丢失路径信息,因此要把 outputs.beam_indices 一起传给对齐函数。
beam_outputs = model.generate(
**inputs,
max_new_tokens=4,
num_beams=3,
num_return_sequences=3,
return_dict_in_generate=True, # 保留 beam 结果字段。
output_scores=True, # 保留每个 beam 的逐步分数。
)
beam_transition_scores = model.compute_transition_scores(
beam_outputs.sequences,
beam_outputs.scores,
beam_outputs.beam_indices, # 指明最终序列经过的 beam 路径。
normalize_logits=False, # 重建官方序列分数时保持原始口径。
)
print(beam_transition_scores.shape)
print(beam_outputs.sequences_scores)
transition_scores 是逐 token 的分数,而 sequences_scores 是 beam search 的序列级结果,二者不能当成同一个字段。官方文档还说明,若要从 transition scores 重建序列分数,归一化选项和长度惩罚必须与生成配置保持一致;展示单 token 置信度时可以选择归一化,但做序列分数复算时要先明确口径。

兼容边界:不要把四种长度和分数混在一起
| 对象 | 它回答的问题 | 常见误读 |
|---|---|---|
sequences | 最终返回的 token 序列是什么 | 把开头输入提示词也当作新生成内容 |
scores | 每个生成步对整个词表的预测分数 | 把一个步的词表张量当成序列总分 |
transition_scores | 最终选中 token 在各生成步的分数 | 忽略 beam 路径导致 token 与分数错位 |
sequences_scores | beam search 的序列级评分 | 直接与单 token 对数概率比较 |
落地时可以按这份清单复查:一是确认两个输出开关都打开;二是按模型类型确定输入长度;三是 beam search 传入 beam_indices;四是说明是否做 logits 归一化;五是把“逐 token 分数”和“序列级分数”分别保存。这样既能打印生成内容,也能为候选排序、调试解码策略留下可解释数据。
常见问题
为什么打开 output_scores 后还是没有 scores 字段?
先确认同时设置了 return_dict_in_generate=True,并检查实际调用使用的是同一个结果对象。只保留分数而不返回 ModelOutput 时,读取方式不会按本文字段组织。
normalize_logits 应该设为 True 还是 False?
如果想把每步分数解释为可比较的对数概率,通常选择 True;如果要按官方示例重建 beam search 的序列分数,应先保持与生成过程相同的未归一化口径,并配合长度惩罚理解结果。
为什么生成 token 数和输入长度容易算错?
decoder-only 的最终序列通常包含提示词,生成片段应从输入 token 数之后切出;encoder-decoder 的解码起点不同,应该依据模型类型和返回序列语义调整,不要复制同一条切片表达式。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
248 收藏
-
253 收藏
-
165 收藏
-
211 收藏
-
424 收藏
-
435 收藏
-
265 收藏
-
471 收藏
-
329 收藏
-
120 收藏
-
422 收藏
-
284 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习