unilm/IAD fairseq 无监督质量估计(UQE)实战:基于蒙特卡洛 Dropout 的 NMT 译文置信度评估

发布时间:2026/9/13 19:10:55
unilm/IAD fairseq 无监督质量估计(UQE)实战:基于蒙特卡洛 Dropout 的 NMT 译文置信度评估 unilm/IAD fairseq 无监督质量估计UQE实战基于蒙特卡洛 Dropout 的 NMT 译文置信度评估【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm本文是一份围绕decoding/IAD/fairseq/examples/unsupervised_quality_estimation/README.md展开的实战指南完整复现 Fomicheva et al. (2020) 提出的**无监督质量估计Unsupervised Quality Estimation, UQE**方案在不依赖任何人工标注质量分数的情况下仅利用 NMT 模型自身的输出log 概率与多次采样假设评估译文可信度。读者将掌握在 unilm 仓库内嵌的 IAD/fairseq 框架中如何完成数据预处理、标准解码、基于--retain-dropout的随机前向采样、以及基于 Meteor 相似度的两种不确定性估计流水线并理解其底层实现原理。方法背景为什么无监督也能估计译文质量传统 QE 任务需要额外的质量标注数据如 HTER、DA 分数训练回归模型。Fomicheva et al. (2020) 提出的无监督方案则利用**蒙特卡洛 DropoutMC Dropout**的核心思想训练好的 NMT 模型在推理时开启 dropout等价于从模型的近似后验分布中采样。对同一条源句执行N次带 dropout 的解码可以得到N个不同的翻译假设若模型对译文不确定例如出现未见过的命名实体、专有名词多次采样的假设之间差异大、分布方差高反之若模型确信则假设高度一致。由此不依赖任何外部标注仅凭模型内部行为即可给出逐句置信度信号。该方法来自论文Unsupervised Quality Estimation for Neural Machine Translation (Fomicheva et al., 2020)本仓库的 README 给出了完整复现步骤配套脚本repeat_lines.py、aggregate_scores.py、meteor.py位于同一目录下。环境与依赖准备开始前需要准备以下外部工具依赖用途mosesdecoder分词tokenizer.perl与去分词detokenizer.perlsubword-nmtBPE 切分apply_bpe.pyflores测试集数据若使用该基准MLQE 数据集仓库下载翻译模型与测试数据另外需要 Java 运行时用于运行 Meteor 评估 jar 包。配置环境变量本流程围绕一组 shell 变量组织所有后续命令都依赖它们变量含义SRC_LANG/TGT_LANG源语言 / 目标语言代码INPUT输入前缀要求存在$INPUT.$SRC_LANG源句与$INPUT.$TGT_LANG参考译文两个文件OUTPUT_DIR结果输出目录MOSES_DECODERmosesdecoder 安装路径BPE_ROOTsubword-nmt 安装路径BPEBPE 模型文件路径MODEL_DIR存放 NMT 模型.pt文件以及源/目标词表dict.$LANG.txt的目录TMP中间临时文件目录GPU使用 GPU 推理时的 GPU 编号DROPOUT_N随机前向传播MC 采样的次数LP语言对标识如en-de用于定位模型文件$MODEL_DIR/$LP.pt关于DROPOUT_N的取值论文实验中使用DROPOUT_N30但原文档明确说明当取值超过 10 后收益不再显著——在资源受限时可先用 10追求更稳定信号可提升到 30。第一步使用标准解码翻译数据UQE 需要一个基线翻译作为后续评分与假设对比的对象其流程为分词 → BPE → 二值化 → 解码 → 后处理。1. 预处理输入数据对源语言和目标语言参考译文分别执行 Moses 分词与 BPE 切分for LANG in $SRC_LANG $TGT_LANG; do perl $MOSES_DECODER/scripts/tokenizer/tokenizer.perl -threads 80 -a -l $LANG $INPUT.$LANG $TMP/preprocessed.tok.$LANG python $BPE_ROOT/apply_bpe.py -c ${BPE} $TMP/preprocessed.tok.$LANG $TMP/preprocessed.tok.bpe.$LANG done2. 二值化数据使用fairseq-preprocess将文本转为 fairseq 二进制格式以加速推理。注意这里显式指定了模型自带的词表保证分词与模型训练时一致fairseq-preprocess --srcdict $MODEL_DIR/dict.$SRC_LANG.txt --tgtdict $MODEL_DIR/dict.$TGT_LANG.txt \ --source-lang ${SRC_LANG} --target-lang ${TGT_LANG} --testpref $TMP/preprocessed.tok.bpe \ --destdir $TMP/bin --workers 4原文档该命令为单行书写此处为便于阅读换行参数完全一致。3. 执行翻译CUDA_VISIBLE_DEVICES$GPU fairseq-generate $TMP/bin --path ${MODEL_DIR}/${SRC_LANG}-${TGT_LANG}.pt \ --beam 5 --source-lang $SRC_LANG --target-lang $TGT_LANG --no-progress-bar --unkpen 5 \ $TMP/fairseq.out grep ^H $TMP/fairseq.out | cut -f3- $TMP/mt.out其中--beam 5使用 5 路 beam search--unkpen 5对未登录词施加惩罚grep ^H | cut -f3-从 fairseq 输出中抽取假设译文H 行的文本部分得到每条源句的最终翻译$TMP/mt.out。4. 后处理去除 BPE 标记并执行 Moses 去分词得到可读的目标语言译文sed -r s/( )| ( ?$)//g $TMP/mt.out \ | perl $MOSES_DECODER/scripts/tokenizer/detokenizer.perl -l $TGT_LANG $OUTPUT_DIR/mt.out第二步产生不确定性估计这是 UQE 的核心包含两种互补的信号模型对译文的输出分布稳定性Scoring以及多次采样假设之间的相互一致性Generation。两者都依赖--retain-dropout让模型在推理时保持 dropout 开启。准备重复输入行并二值化先利用仓库提供的 repeat_lines.py 把源句和基线译文各重复DROPOUT_N次。该脚本逐行读取输入文件对每一行原样写入-n次并顺手把连续空白归一化为单空格_normalize_spaces保证重复后的行与原始内容完全一致python repeat_lines.py -i $TMP/preprocessed.tok.bpe.$SRC_LANG -n $DROPOUT_N -o $TMP/repeated.$SRC_LANG python repeat_lines.py -i $TMP/mt.out -n $DROPOUT_N -o $TMP/repeated.$TGT_LANG fairseq-preprocess --srcdict ${MODEL_DIR}/dict.${SRC_LANG}.txt --tgtdict ${MODEL_DIR}/dict.${TGT_LANG}.txt \ --source-lang ${SRC_LANG} --target-lang ${TGT_LANG} --testpref ${TMP}/repeated --destdir ${TMP}/bin-repeated说明原文档中第二行--tgtdict后写的变量名为$TGT_DIC未在变量表中定义按上下文应为$MODEL_DIR/dict.$TGT_LANG.txt此处已按其本意补全repeat_lines.py在仓库中的实际位置即 examples/unsupervised_quality_estimation/可直接调用。路径 AScoring——评分分布的均值A1. 用--score-reference给重复后的参考译文打分同时开启 dropoutCUDA_VISIBLE_DEVICES${GPU} fairseq-generate ${TMP}/bin-repeated --path ${MODEL_DIR}/${LP}.pt --beam 5 \ --source-lang $SRC_LANG --target-lang $TGT_LANG --no-progress-bar --unkpen 5 --score-reference \ --retain-dropout \ --retain-dropout-modules [TransformerModel,TransformerEncoder,TransformerDecoder,TransformerEncoderLayer,TransformerDecoderLayer] \ --seed 46 $TMP/dropout.scoring.out grep ^H $TMP/dropout.scoring.out | cut -f2- $TMP/dropout.scores关键点--score-reference让模型对给定的参考/目标句计算 log 概率而不是做 beam search 解码--retain-dropout在推理时保留 dropout默认推理时关闭见下文源码分析--retain-dropout-modules指定哪些模块保留 dropout。不传该参数时所有模块默认启用 dropout即与训练时相同的丢弃位置传入后仅列出的模块开启每条源句对应DROPOUT_N个重复行因此产出N个独立采样的 log 概率分数这里grep ^H | cut -f2-抽取的是分数而非译文文本。A2. 聚合多次采样分数使用 aggregate_scores.py 按-n $DROPOUT_N个一组计算聚合统计量python aggregate_scores.py -i $TMP/dropout.scores -o $OUTPUT_DIR/dropout.scores.mean -n $DROPOUT_N该脚本不仅支持默认的mean还内置了std标准差、var方差、median、min、max五种聚合函数通过-f/--func切换见aggregate_funcs字典。方差/标准差本身就是不确定性的直接度量均值则是期望 log 概率。多次采样分数的低均值 高方差组合即可作为低质量译文的判据。路径 BGeneration——多次假设的相互相似度B1. 对重复源句执行带 dropout 的 beam search生成N个翻译假设CUDA_VISIBLE_DEVICES${GPU} fairseq-generate ${TMP}/bin-repeated --path ${MODEL_DIR}/${LP}.pt \ --beam 5 --source-lang $SRC_LANG --target-lang $TGT_LANG --no-progress-bar --retain-dropout \ --unkpen 5 --retain-dropout-modules TransformerModel TransformerEncoder TransformerDecoder TransformerEncoderLayer TransformerDecoderLayer \ --seed 46 $TMP/dropout.generation.out grep ^H $TMP/dropout.generation.out | cut -f3- $TMP/dropout.hypotheses_ sed -r s/( )| ( ?$)//g $TMP/dropout.hypotheses_ \ | perl $MOSES_DECODER/scripts/tokenizer/detokenizer.perl -l $TGT_LANG $TMP/dropout.hypotheses与 Scoring 路径的区别在于这里省略--score-reference走正常的 beam search 解码因此每条源句得到N个通常彼此略异的完整译文假设。--seed 46固定随机种子以保证可复现--retain-dropout-modules在此处以空格分隔的模块名列表书写与路径 A 的 JSON 列表写法等价两种语法均被 fairseq 支持。后处理同样需要去 BPE 去分词。B2. 用 Meteor 计算同源假设间的相似度python meteor.py -i $TMP/dropout.hypotheses -m path_to_meteor_installation -n $DROPOUT_N -o \ $OUTPUT_DIR/dropout.gen.sim.meteormeteor.py 的内部逻辑清晰地展示了相似度估计的构造方式read_translations按每n_repeats行把文件切分成每个源句的N个假设generate_input对每个源句的N个假设两两配对combinations(range(N), 2)生成C(N, 2)对 (mt, ref) 组合分别写入临时文件run_meteor调用java -jar meteor.jar参数为-p 0.5 0.2 0.6 0.75仅将 alpha 调整为 P 与 R 等权其余用默认参数与-norm逐对计算 Meteor 分数最后按源句聚合这些成对分数输出每句一个相似度值。直觉若同一源句的多次采样假设相互之间 Meteor 相似度很高说明模型输出稳定、该句翻译可信反之假设漂移大说明模型不确定该句质量存疑。这条信号不依赖参考译文天然属于无监督。源码级原理--retain-dropout是如何工作的要理解以上流程需要看懂 fairseq 推理时 dropout 的开关机制涉及三个关键文件。1. 参数定义fairseq/dataclass/configs.py 中定义了生成generation配置retain_dropout: bool field( defaultFalse, metadata{help: Use dropout at inference time}, ) retain_dropout_modules: Any field( defaultNone, metadata{ help: if set, only retain dropout for the specified modules; if not set, then dropout will be retained for all modules }, )默认retain_dropoutFalse即标准推理下 dropout 完全关闭——这也是为什么 UQE 必须显式打开该开关。2. 开关如何传递到模型在 fairseq/models/fairseq_model.py 的prepare_for_inference_中生成配置被透传给make_generation_fast_if getattr(cfg.generation, retain_dropout, False): kwargs[retain_dropout] cfg.generation.retain_dropout kwargs[retain_dropout_modules] cfg.generation.retain_dropout_modules self.make_generation_fast_(**kwargs)3. 模块级 dropout 门控fairseq 的自定义 dropout 层 FairseqDropout 维护一个apply_during_inference标志def forward(self, x, inplace: bool False): if self.training or self.apply_during_inference: return F.dropout(x, pself.p, trainingTrue, inplaceinplace) else: return x def make_generation_fast_(self, name, retain_dropoutFalse, retain_dropout_modulesNone, **kwargs): if retain_dropout: if retain_dropout_modules is not None and self.module_name is None: logger.warning(Cannot enable dropout during inference ...) elif (retain_dropout_modules is None or self.module_name in retain_dropout_modules): self.apply_during_inference True逻辑一目了然retain_dropout_modulesNone→ 对所有模块开启推理期 dropout即与训练完全一致传入模块名列表 → 仅匹配module_name的模块开启其余保持关闭便于实验只对 Encoder/Decoder 的哪些子层加噪模块未设置module_name时无法按名匹配会打印 warning。4. 测试验证仓库的 tests/test_inference_dropout.py 用单元测试锁定了这一行为test_sets_inference_dropout_to_true设置retain_dropoutTrue后encoder/decoder 及其各层的dropout_module.apply_during_inference均变为Truetest_inference_dropout_false_by_default默认情况下所有层均为False推理期 dropout 关闭test_retain_modules仅指定[TransformerEncoder, TransformerEncoderLayer]时只有 encoder 侧开启、decoder 侧保持关闭验证了模块级选择性开关。完整流程串联与实操建议将两条路径组合起来一次完整的 UQE 评估共生成三个产物产物含义产生方式$OUTPUT_DIR/mt.out标准解码基线译文第一步流程$OUTPUT_DIR/dropout.scores.mean逐句期望 log 概率可选叠加方差路径 A$OUTPUT_DIR/dropout.gen.sim.meteor逐句假设间 Meteor 相似度路径 B实操建议DROPOUT_N从 10 起步文档明确 10 以上收益递减若追求论文级复现再使用 30固定--seed 46保证多次实验可复现两条信号可以互补Scoring 衡量模型对某一条译文给分的稳定性Generation 衡量模型自己会怎样翻译的一致程度两者联合可过滤单条信号的噪声--retain-dropout-modules按需收窄若想验证不确定性主要来自 Decoder 自回归步可仅对TransformerDecoderLayer开启 dropout 做消融适配当前仓库路径所有配套脚本repeat_lines.py、aggregate_scores.py、meteor.py均在 examples/unsupervised_quality_estimation/ 目录下调用时使用仓库根相对路径如python decoding/IAD/fairseq/examples/unsupervised_quality_estimation/repeat_lines.py ...即可。整个流水线不需要任何人工质量标注仅依赖模型自身行为即可为每条译文产出置信度信号这也正是它被称为无监督质量估计的原因。【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考