Transformers 长文本怎样用 stride 生成重叠窗口
来源:17golang原创
时间:2026-10-14 11:24:39 197浏览 收藏
长文本交给 Transformer 时,最容易遇到的不是模型调用,而是输入超过最大 token 长度:直接截断会丢掉后半段,简单切片又可能把实体或句子从中间切开。更稳妥的做法是让 tokenizer 返回多个窗口,并用 stride 保留相邻窗口之间的重叠区域。这里的关键组合是 truncation=True、max_length、stride 和 return_overflowing_tokens=True。
官方文档:https://huggingface.co/docs/transformers/main_classes/tokenizer
本文只讨论文本预处理和原文对齐,不讨论具体模型训练,也不把静态配图当作运行截图。
一、先确定窗口上限和重叠长度
max_length 是单个编码窗口允许的最大长度,stride 是相邻窗口共享的 token 数。假设窗口上限为 256、重叠为 64,那么第二个窗口会带上第一个窗口末尾的一部分内容。这样做能降低实体刚好跨过切分点时的上下文损失,但也会增加窗口数量和后续合并成本。
设置时先记住两个边界:stride 必须小于有效窗口长度;如果使用了特殊 token,真正能容纳正文的 token 数还会比 max_length 少。长文档分类通常可以从较小重叠开始,问答或实体抽取则要根据实体长度和句子边界适当增加。
二、先把长文本窗口拆成三个对象
理解返回值时,可以把它拆成三部分:原始文本是输入,max_length 与 stride 是窗口配置,input_ids 和 attention_mask 是编码输出。return_overflowing_tokens=True 会让 tokenizer 把超出的部分整理成额外窗口,而不是静默丢弃。

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese", use_fast=True)
encoded = tokenizer(
text,
truncation=True,
max_length=256,
stride=64,
return_overflowing_tokens=True,
return_attention_mask=True,
return_offsets_mapping=True,
return_length=True,
)
# 每一项 input_ids 都是一个窗口;窗口数量可能大于一
window_ids = encoded["input_ids"]
window_masks = encoded["attention_mask"]
window_lengths = encoded["length"]
print(len(window_ids), window_lengths)
这里使用快速 tokenizer,是因为 return_offsets_mapping 依赖快速实现来提供 token 到字符区间的映射。attention_mask 和每个窗口的长度应与 input_ids 按同一个窗口下标配对,不能把所有窗口拍平成一条序列。
三、把窗口映射回原文,避免标签对不上
批量处理多条文本时,窗口下标本身还不够。Transformers 会返回 overflow_to_sample_mapping,它说明第几个窗口来自批量输入中的哪一条原始文本;offset_mapping 则记录 token 对应的字符起止位置。两者结合后,分类结果、实体 span 或问答答案才有机会回填到正确原文。

batch = ["第一篇很长的文本……", "第二篇也可能超过窗口上限……"]
encoded = tokenizer(
batch,
truncation=True,
max_length=256,
stride=64,
return_overflowing_tokens=True,
return_offsets_mapping=True,
padding=False,
)
mapping = encoded["overflow_to_sample_mapping"]
offsets = encoded["offset_mapping"]
for window_index, sample_index in enumerate(mapping):
# 用样本映射找到原文,再用字符区间定位窗口覆盖的文本范围
char_spans = offsets[window_index]
print(window_index, sample_index, char_spans[0], char_spans[-1])
示例中的 char_spans 只是展示读取方式,实际任务还要跳过特殊 token 的无效区间,并根据任务格式过滤空 span。做实体抽取时,可以把预测结果转成原文字符区间;做文档级分类时,则按 sample_index 聚合多个窗口的分数,而不是把窗口当成独立文档。
四、stride 过大、过小分别会怎样
| 设置 | 表现 | 适用判断 |
|---|---|---|
| stride = 0 | 窗口互不重叠,切分点附近上下文最少 | 内容边界天然清晰或只做粗粒度分类 |
| stride 适中 | 相邻窗口共享部分上下文,窗口数和信息保留较平衡 | 长文档问答、抽取、段落分类的常用起点 |
| stride 接近 max_length | 窗口高度重复,计算量和结果合并难度明显增加 | 只有在实体或语义跨度确实很长时才考虑 |
批量输入还要注意 padding 与窗口展开的顺序。先确认每个窗口仍能通过 overflow_to_sample_mapping 找到来源,再决定是否统一补齐;如果在业务层先合并列表,最容易发生的错误就是把不同样本的窗口或标签混到一起。
五、常见问题
为什么打开 stride 却只得到一个窗口?
通常是文本没有超过 max_length,或者没有同时打开 truncation=True 与 return_overflowing_tokens=True。先看输入长度是否真的触发溢出,再检查返回值是不是按批量列表读取。
offset_mapping 能直接用于所有 tokenizer 吗?
它主要依赖快速 tokenizer。若当前 tokenizer 不支持偏移映射,应先确认对应实现,不能把 token 下标直接当作字符串字符下标。
stride 越大是不是越准确?
不是。重叠越大通常意味着更多重复计算和更复杂的结果聚合。应按实体长度、句子边界和任务容错选择,并观察窗口数量是否超出处理预算。
归纳起来,max_length 决定窗口上限,stride 决定相邻窗口保留多少上下文,overflow_to_sample_mapping 和 offset_mapping 负责把展开后的窗口重新接回原文。只要这四个对象保持成对关系,长文本切分就不会停留在“截断后猜结果”的状态。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
354 收藏
-
371 收藏
-
386 收藏
-
448 收藏
-
203 收藏
-
140 收藏
-
328 收藏
-
146 收藏
-
365 收藏
-
278 收藏
-
395 收藏
-
492 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习