)
在 Fairseq 中使用带动态 beam 分配的词法约束解码Lexically Constrained Decoding【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm导读本文以 Fairseq 仓库位于kosmos-2/fairseq中examples/constrained_decoding示例为线索系统讲解词法约束解码Lexically Constrained Decoding的原理、命令行用法与源码实现。词法约束解码允许你在解码时强制目标输出中出现指定的词或短语如人名、术语、多词短语常用于机器翻译中的术语翻译控制与单语改写场景。读完本文你将掌握--constraints参数的完整用法、输入输出格式、有序/无序两种约束模式的差异并能从源码层面理解LexicallyConstrainedBeamSearch的动态 beam 分配机制。一、词法约束解码是什么词法约束解码的核心思想是解码器在生成每个目标词时除了依据语言模型打分还必须保证最终输出包含用户预先指定的词或短语序列。在 Fairseq 中这一功能由fairseq/search.py中的LexicallyConstrainedBeamSearch实现它基于以下两篇论文Fast Lexically Constrained Decoding With Dynamic Beam AllocationPost Vilar, NAACL 2018提出了带动态 beam 分配的快速词法约束解码算法Improved Lexically Constrained Decoding for Translation and Monolingual RewritingHu et al., NAACL 2019在向量化层面改进约束处理使其同时适用于翻译与单语改写。约束可以是单个 token 或多个 token 组成的短语如 hard 或 to influence同一个约束短语还可以在输出中多次出现例如 Berlin 出现两次则输出中必须包含两处 Berlin。这种能力让机器翻译系统在遇到专有名词、产品名、法律条款等场景时能够按用户给定的术语表强制生成指定译法从而显著提升术语一致性。二、快速开始用--constraints跑通第一个例子2.1 启用方式与输入格式在 Fairseq 中约束解码无需修改任何模型代码只需在fairseq-interactive命令后追加--constraints参数即可开启。输入行中源句与每个约束之间用Tab 分隔每个约束是一个独立字段可含多个 token源句\t约束1\t约束2\t...下面的命令使用 Fairseq 的 WMT19 德英模型将德语句子Die maschinelle Übersetzung ist schwer zu kontrollieren.翻译成英文并强制输出中必须包含约束hard与to influenceecho -e Die maschinelle Übersetzung ist schwer zu kontrollieren.\thard\ttoinfluence \ | normalize.py | tok.py \ | fairseq-interactive /path/to/model \ --path /path/to/model/model1.pt \ --bpe fastbpe \ --bpe-codes /path/to/model/bpecodes \ --constraints \ -s de -t en \ --beam 10命令中的normalize.py与tok.py位于本 README 同目录下即kosmos-2/fairseq/examples/constrained_decoding/它们只是 Fairseq WMT19 预处理流程的快捷封装。注意这里约束to influence写成了toinfluence——因为 BPE 切分后influence本身就是一个词片无需空格同理约束中的多词短语也应以模型 BPE 切分后的形式给出这是约束能否命中的关键细节。2.2 输出格式解读上述命令会产生如下输出[snip] S-0 Die masch in elle Über setzung ist schwer zu kontrollieren . W-0 1.844 seconds C-0 hard C-0 influence H-0 -1.5333266258239746 Mach ine trans lation is hard to influence . D-0 -1.5333266258239746 Machine translation is hard to influence . P-0 -0.5434 -0.1423 -0.1930 -0.1415 -0.2346 -1.8031 -0.1701 -11.7727 -0.1815 -0.1511各字段含义S-0源句及其 BPE 切分结果W-0解码耗时C-0约束回显行每一行对应一个约束此处为hard与influence注意输出中是 BPE 后的形式用于确认约束已正确送入解码器H-0假设hypothesis及其累计得分BPE 形式D-0去 BPE 后的最终译文可见hard与influence均被强制出现在译文中P-0每个生成 token 的位置得分positional scores。对比可知未加约束时模型很可能输出 difficult to control 之类的译法而加了约束后译文的措辞被精确锁定为 hard to influence。三、约束的输入与预处理链路从 interactive.py 的make_batches可以看到约束从文本到张量的完整转换流程对应 interactive.py切分字段当cfg.generation.constraints开启时对每一行按\t切分第一个字段是源句其余字段是约束编码约束每个约束字符串经task.target_dictionary.encode_line(...)编码为 token id 序列append_eosFalse, add_if_not_existFalse即不允许约束中出现 OOV 词打包成张量调用pack_constraints将「句子 × 约束」的嵌套列表打成 batch 级张量随 batch 一起进入推理流程。pack_constraints的打包格式非常巧妙见 token_generation_constraints.py每一行是一个句子所有约束的拼接序列行首第一个元素是「该句的约束数量」每个约束之后补一个0作为分隔符。例如 batch 中有 3 个句子、约束数分别为 3/0/1 时打包结果形如[ [ 3 3 1 2 0 3 0 4 5 6 7 0], [ 0 0 0 0 0 0 0 0 0 0 0 0], [ 1 1 8 9 10 1 4 11 12 0 0 0] ]行首的3、0、1即各句约束个数。整行宽度maxlen取所有句子中「约束数 各约束长度之和 1」的最大值。对应的unpack_constraints则负责在解码后把单行张量还原成约束列表。在fairseq-cli generate批量生成场景下约束则通过sample[constraints]从数据集读取并传给 generator见 generate.py。四、有序约束与无序约束--constraintsvs--constraints unordered约束解码支持两种模式对应LexicallyConstrainedBeamSearch初始化的representation参数ordered / unordered见 search.py模式命令行写法行为数据结构有序--constraints约束按输入顺序依次出现约束之间允许出现任意数量0 个或多个的其他 tokenOrderedConstraintState无序--constraints unordered解码器自行决定约束的出现顺序尝试全部C!种顺序UnorderedConstraintState默认的有序模式对大多数场景如术语表按原文语序排列已经足够无序模式会探索更多顺序输出更灵活但搜索空间更大。两种模式的共同点在于约束之间永远允许插入任意内容约束内部则必须连续生成多 token 短语不可拆散。4.1 OrderedConstraintState线性状态机有序模式把 C 个约束拼接成一条线性序列用单个整数状态指针state记录进度见 token_generation_constraints.py。advance(token)的转移规则直观若下一个待生成 token 恰好匹配sequence[state 1]则指针前进一步若当前正处于某个约束的终点endpoint则可以接受任意 token约束之间的「间隔」若 token 等于整个序列的第一个 token则回到状态 0重新开始否则回到根状态 -1从头再来。finished属性即state 1 len(sequence)表示所有约束都已生成完毕next_tokens()只返回「下一个约束 token 序列首 token」两个候选搜索空间极小。4.2 UnorderedConstraintStateTrie 驱动的自动机无序模式将全部约束含重复约束建成一棵Trie前缀树节点类ConstraintNode记录terminal此节点结束了几条约束与num_constraints子树内约束总数见 token_generation_constraints.py。每个 beam 假设持有一个UnorderedConstraintState通过advance(token)游走在 Trie 节点之间若当前节点存在匹配子节点且该路径未被「饱和」generated[child] child.num_constraints则深入子节点若无法深入则「回退rewind」到根节点回退沿途检查是否有已满足的前缀约束并标记为completed状态用generated已生成节点计数、completed已完成约束计数、needed_tokens剩余必需 token 集合共同刻画finished当且仅当所有约束均已完成。五、实现细节动态 beam 分配的核心算法约束解码的心脏是 search.py 中的LexicallyConstrainedBeamSearch。它继承自Search基类并设置self.supports_constraints True若用户传入约束而当前搜索器不支持sequence_generator.py会直接报错见 sequence_generator.py确保约束不会被静默忽略。与传统 Beam Search 不同它需要同时维护 beam 中每个假设的约束进度并在每个时间步做 8 步处理step与step_sentence方法STEP 0防提前结束对尚未完成约束的假设把eos的 log 概率置为-inf防止模型在约束未满足时就收尾STEP 1候选构建候选池由三部分组成——全 beam 上top 2×beam_size、每个假设的top-1each_k1、以及每个假设的「下一个约束 token」集合STEP 2注入约束遍历每个 beam 假设把state.next_tokens()中所有合法约束 token 加入候选并以对应位置的 log 概率作为得分见 search.pySTEP 3计算 bank对每个候选执行advance(token)得到新状态bank即该候选「已生成的约束数量」这是后续动态分配的排序依据STEP 4按 (bank, score) 排序通过巧妙的排序键(num_constraint_tokens - bank) * MAX_SCORE score实现先按 bank、再按得分排序STEP 5去重把(beam, token_id)映射到一维用 roll 移位比较法去除重复候选STEP 6round-robin 分配这是「动态 beam 分配」的精髓——对排序后的候选按 bank 分桶跨 bank 做轮转分配stripe依次取 bank C 的最佳、bank C-1 的最佳、…… 再取 bank C 的次佳、bank C-1 的次佳……保证进展快bank 高的假设优先占位又不至于垄断整个 beamSTEP 7/8排序与截断按 stripe 值排序后截取前num_cands 2 × beam_size个候选作为下一时间步的 beam。因为有了「按 bank 轮转」的精细分配约束搜索不再需要像传统做法那样剪枝prunebeambeam 宽度只需 10 甚至 5 就往往足够。这正是论文标题中 Dynamic Beam Allocation 的含义。六、与 Sockeye 实现的差异Fairseq 的实现在设计上与 Sockeye 的约束解码存在若干差异详见原文档这些差异也是选择 Fairseq 实现时的理由有序生成默认的「按输入顺序生成约束」模式在 Sockeye 中不可用无需剪枝得益于改进的 beam 分配方法Fairseq 无需对 beam 进行剪枝beam 更小同样因为分配更优beam 宽度 10 甚至 5 通常就已足够向量化扩展Hu et al.NAACL 2019描述的向量化扩展trie 约束版本从未被合并进 Sockeye 主分支而 Fairseq 的LexicallyConstrainedBeamSearch原生支持。七、引用文献词法约束解码的第一篇论文Grid Beam Search为inproceedings{hokamp-liu-2017-lexically, title Lexically Constrained Decoding for Sequence Generation Using Grid Beam Search, author Hokamp, Chris and Liu, Qun, booktitle Proceedings of the 55th Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers), month jul, year 2017, address Vancouver, Canada, publisher Association for Computational Linguistics, url https://www.aclweb.org/anthology/P17-1141, doi 10.18653/v1/P17-1141, pages 1535--1546, }Fairseq 实现所依赖的两篇扩展工作分别为inproceedings{post-vilar-2018-fast, title Fast Lexically Constrained Decoding with Dynamic Beam Allocation for Neural Machine Translation, author Post, Matt and Vilar, David, booktitle Proceedings of the 2018 Conference of the North {A}merican Chapter of the Association for Computational Linguistics: Human Language Technologies, Volume 1 (Long Papers), month jun, year 2018, address New Orleans, Louisiana, publisher Association for Computational Linguistics, url https://www.aclweb.org/anthology/N18-1119, doi 10.18653/v1/N18-1119, pages 1314--1324, }inproceedings{hu-etal-2019-improved, title Improved Lexically Constrained Decoding for Translation and Monolingual Rewriting, author Hu, J. Edward and Khayrallah, Huda and Culkin, Ryan and Xia, Patrick and Chen, Tongfei and Post, Matt and Van Durme, Benjamin, booktitle Proceedings of the 2019 Conference of the North {A}merican Chapter of the Association for Computational Linguistics: Human Language Technologies, Volume 1 (Long and Short Papers), month jun, year 2019, address Minneapolis, Minnesota, publisher Association for Computational Linguistics, url https://www.aclweb.org/anthology/N19-1090, doi 10.18653/v1/N19-1090, pages 839--850, }八、深入阅读指引如需进一步钻研可在本仓库内查阅以下关键文件示例与预处理脚本kosmos-2/fairseq/examples/constrained_decoding/本 README、normalize.py、tok.py核心搜索算法search.pyLexicallyConstrainedBeamSearch及其 8 步动态分配流程约束状态机与 Trietoken_generation_constraints.pypack_constraints、OrderedConstraintState、UnorderedConstraintState命令行入口interactive.py约束解析与打包、generate.py批量推理解码主循环sequence_generator.py约束初始化与每步更新值得留意的是fairseq/search.py中还存在LengthConstrainedBeamSearch等变体它们与词法约束解码同属「解码期控制」家族但机制完全不同读者在阅读源码时应加以区分。【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考