登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

Transformers StoppingCriteriaList 怎样组合生成终止条件

来源:17golang原创

时间:2026-10-27 15:39:36 325浏览 收藏

StoppingCriteriaList 可以把多个生成终止条件装进一个列表,再一次传给 model.generate()。它的核心不是“按顺序执行到第一个条件就返回”,而是让每个条件针对当前 input_ids 和 scores 产生布尔结果,最后按 batch 样本逐位合并;因此长度、时间和业务标记可以同时作为停止信号。

官方文档地址:https://huggingface.co/docs/transformers/en/internal/generation_utils

先分清单个条件和条件列表的职责

StoppingCriteria 是单个规则的抽象基类,调用签名接收 input_ids、可能为空的 scores 以及额外参数,并返回形状接近 (batch_size,) 的布尔张量。StoppingCriteriaList 本身继承 Python 的 list,它只是把多个规则组织起来并提供统一的调用入口。

官方实现先创建一个全为 False 的 batch 向量,然后对列表中的每个条件执行按位 OR。换句话说,任意一个条件对某个样本返回 True,这个样本在合并结果中就会被标记为停止;不同样本可以在同一轮得到不同结果。

StoppingCriteriaList与长度、时间、自定义停止条件的原创结构图
原创结构图:多个条件共享当前生成输入,列表把各条件的布尔结果按位合并。

把最大长度、最长时间和自定义条件放入同一个列表

最小组合通常包含 MaxLengthCriteria、MaxTimeCriteria 和一个自定义条件。长度条件约束完整序列长度;对 decoder-only 模型,官方说明这个长度包含原始提示词。时间条件接收秒数,并可用 initial_timestamp 指定计时起点。自定义条件则适合“生成到某个业务标记就停止”这类领域规则。

import torch
from transformers import (
    MaxLengthCriteria,
    MaxTimeCriteria,
    StoppingCriteria,
    StoppingCriteriaList,
)

class StopOnMarker(StoppingCriteria):
    def __init__(self, marker_id: int):
        self.marker_id = marker_id

    def __call__(self, input_ids, scores, **kwargs):
        # 只检查每个样本最后一个 token,返回 batch 维度的布尔向量。
        return input_ids[:, -1].eq(self.marker_id)

stopping = StoppingCriteriaList([
    # max_length 是完整序列上限,包含提示词部分。
    MaxLengthCriteria(max_length=256),
    # max_time 使用秒作为单位,避免单次生成无限等待。
    MaxTimeCriteria(max_time=8.0),
    # 业务标记条件与内置条件共享同一套调用接口。
    StopOnMarker(marker_id=32000),
])

# 生成时把组合后的容器作为一个参数传入。
output = model.generate(
    **inputs,
    stopping_criteria=stopping,
    do_sample=False,
)

这个组合表达的是“任一条件满足即可停止”,不是“所有条件都满足才停止”。如果业务要求同时满足多个条件,应把联合逻辑写在一个自定义 StoppingCriteria 中,而不是期待列表自动做 AND。

在 generate 中传入列表并处理 scores 依赖

自定义条件如果只看最新 token 或序列长度,scores 可以不参与逻辑;如果条件依赖当前预测分数,就必须在生成配置中请求分数。官方文档特别说明,只有设置 return_dict_in_generate=True 和 output_scores=True,依赖 scores 的条件才会拿到相应数据。

class StopWhenConfidenceIsLow(StoppingCriteria):
    def __init__(self, threshold: float):
        self.threshold = threshold

    def __call__(self, input_ids, scores, **kwargs):
        # 没有 scores 时不能假设存在概率,先按未触发处理。
        if not scores:
            return torch.zeros(input_ids.shape[0], dtype=torch.bool, device=input_ids.device)
        # 只取最后一步分数,避免把历史步骤误当成当前判断。
        probabilities = scores[-1].softmax(dim=-1)
        last_token = input_ids[:, -1]
        confidence = probabilities.gather(1, last_token.unsqueeze(1)).squeeze(1)
        return confidence 

示例只展示接口关系,没有把输出写成已经在本机运行得到的结果。实际项目中还要根据模型、设备和显存代价决定是否长期打开 output_scores。

按 batch 结果理解提前停止

停止条件返回的是逐样本向量,不是一个全局布尔值。例如 batch 中三个样本的长度条件分别为 [True, False, False],时间条件为 [False, True, False],列表合并后是 [True, True, False]。这表示前两个样本已经满足至少一个条件,第三个样本仍未满足。

按batch样本合并Transformers停止信号的原创结构图
原创结构图:停止结果以 batch 行为单位合并,不应把一个样本的 True 当成整批文本相同。

因此自定义条件不要返回 Python 的单个 True 或 False 来代替 batch 向量。最稳妥的做法是始终根据 input_ids.shape[0] 创建同设备的布尔张量,避免 CPU 与 GPU 张量混用。

参数冲突时先看这几项

现象优先检查
列表没有按预期停止自定义条件是否返回每个 batch 样本一个布尔值,设备和 dtype 是否匹配
依赖分数的条件拿不到数据是否同时设置 return_dict_in_generate=True 与 output_scores=True
长度比预想更快触发decoder-only 模型的 max_length 包含提示词,必要时改用明确的长度预算
列表和 generate 的长度参数不一致不要同时维护互相矛盾的最大长度;官方辅助逻辑会检查并可能补入长度条件

可以把组合逻辑记成一句话:每个条件负责一个明确边界,列表负责按位 OR;条件内部负责返回正确的 batch 形状,生成调用负责提供它声明需要的输入。这样既能把硬上限和业务停止符放在一起,也不会把一个样本的停止误判成整批都结束。

StoppingCriteriaList 是 AND 还是 OR?官方实现对各条件结果做按位 OR,任一条件对某个样本为真即可停止。自定义条件一定要读取 scores 吗?不需要,只有条件依赖预测分数时才应显式请求 scores。能否只传自定义列表而不设置 max_length?可以,但仍应为生成任务设计清晰的长度或时间兜底,避免业务条件失效时无界生成。

参考:Hugging Face Transformers 生成工具文档、官方 stopping_criteria.py。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>