如何将SQuAD数据集的token索引映射至BERT分词器生成的对应token?
分词后答案索引错位的核心成因
- BertTokenizer采用WordPiece子词切分逻辑,会将长词拆分为多个带
##前缀的子片段;而SQuAD原标注的答案位置是基于原始纯文本的字符级坐标,和子词序列的token级坐标不属于同一映射体系,天然存在错位 - 分词前的预处理操作引入偏移:比如提前对段落做空格合并、全半角转换、大小写统一、换行符替换,都会打乱原标注对应的字符位置
- 特殊token插入、长文本截断带来的位置偏移:BERT输入需要拼接
[CLS]、[SEP]等特殊token,长段落截断时也会砍掉部分文本,直接复用原标注索引必然出现位置偏差
可行的错位解决思路
- 在分词过程中建立原文本字符位置与分词后token位置的双向映射,重新计算适配分词结果的答案token索引,作为模型训练的预测目标
- 对无法通过映射定位正确答案位置的无效样本做过滤,不纳入训练集避免引入噪声
- 放弃原字符索引的直接复用,在子词序列中通过字符偏移匹配定位答案所在的token跨度
同步修正答案索引的可行性
完全可以,这也是目前基于BERT做SQuAD答案跨度抽取的标准实现方案,不存在逻辑层面的问题。
核心逻辑是把原始字符级的答案边界,通过分词时记录的位置偏移,转换为分词序列上的token级边界,作为模型start/end预测头的训练目标,不需要改动模型本身的结构。
索引映射与修正的具体实现流程
- 分词阶段开启位置追踪
调用BertTokenizer时传入return_offsets_mapping=True参数,让分词过程在返回input_ids的同时,同步输出每个token对应的原始段落文本中的字符区间元组。特殊token([CLS]、[SEP])对应的偏移量统一设为(0,0),方便后续做边界过滤。 - 基于偏移量匹配答案边界
拿到SQuAD原始标注的答案字符级起始orig_start、结束orig_end(注意SQuAD的索引规则是左闭右开,即原文本中[orig_start, orig_end)区间的子串为标准答案),遍历所有token对应的偏移量:- 筛选出所有与答案字符区间存在重叠的token,取这类token在分词序列中的最小编号,即为修正后的答案起始token位置
- 取这类token的最大编号,即为修正后的答案结束token位置
- 边界异常的兜底处理
针对常见错位场景做兼容:- 答案边界落在被WordPiece拆分的子词中间时,只要token的字符区间和答案区间有重叠,就将该token纳入答案跨度,不需要刻意对齐到完整词的边界
- 长文本截断导致答案完全不在当前保留的token范围内时,直接将该样本的start、end索引设为
[CLS]对应的位置(即索引0),训练时在损失计算环节对这类样本做忽略,不参与梯度更新 - 为了减少预处理带来的偏移,直接将SQuAD提供的原始段落文本传入tokenizer,不要提前做大小写转换、空格合并、换行符替换等修改操作
- 映射结果校验
修正完索引后,将对应位置的token拼接成字符串,和原始标准答案做相似度校验,如果编辑距离超过阈值,就将该样本标记为异常,避免错误索引污染训练过程。
注意:不要在分词后直接通过原始答案的字符串匹配定位位置,因为WordPiece子词带有
##前缀标记,直接做字符串匹配会出现大量定位错误,必须依托分词时记录的字符偏移量做对齐。
内容的提问来源于stack exchange,提问作者KoalaJ
相关产品推荐
相关产品推荐

