news 2026/9/13 2:45:36

unilm/EdgeLM 无监督机器翻译质量估计:基于 MC-Dropout 的翻译不确定性估计完整复现指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
unilm/EdgeLM 无监督机器翻译质量估计:基于 MC-Dropout 的翻译不确定性估计完整复现指南

unilm/EdgeLM 无监督机器翻译质量估计:基于 MC-Dropout 的翻译不确定性估计完整复现指南

【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm

本篇指南基于 unilm 仓库edgelm(EdgeLM)分支下的 无监督质量估计示例文档,讲解如何在神经机器翻译(NMT)场景中复现 Fomicheva 等人 2020 年论文Unsupervised Quality Estimation for Neural Machine Translation的核心方法:通过在推理时保留 dropout(MC-Dropout 思想)进行多次随机前向/解码,利用「评分方差」与「多假设译文相似度」两类不确定性信号,在无参考、无标注的条件下估计每条机器翻译的质量。读完本文,你将掌握从数据预处理、fairseq 二值化、GPU 批量翻译,到 dropout 评分聚合与 Meteor 相似度计算的完整命令流程,并能从 FairseqDropout 等源码理解--retain-dropout的底层生效机制。

1. 方法背景:为什么推理时的随机性能反映翻译质量

该示例对应 Fomicheva 等人 2020 年发表的无监督质量估计方法。其基本假设是:当源句对模型而言「容易」时,推理中保留的随机扰动(dropout)不会显著改变模型行为——无论是对给定译文的打分还是重新生成译文;而当源句困难、模型不确定时,多次随机前向会给出差异较大的分数或互不相同的译文。

仓库中该示例提供了两条可互相印证的估计路径:

  • Scoring 路径:把同一条源句和同一句机器译文重复 N 次输入模型打分,--retain-dropout使每次前向的 dropout 掩码不同,N 个分数的聚合统计(默认均值,可换标准差等)即不确定性估计;
  • Generation 路径:对每条源句在 dropout 开启下解码出 N 个候选译文,用 Meteor 计算这些候选两两之间的平均相似度,相似度越低说明翻译越不确定。

两条路径都不需要参考译文,因此可以部署在生产环境中对 NMT 输出做逐句质量打分、筛选可疑译文。

2. 环境依赖与准备工作

2.1 外部依赖

根据 README 的 Requirements 一节,复现需要安装以下外部工具:

  • mosesdecoder:提供分词脚本tokenizer.perldetokenizer.perl
  • subword-nmt:提供apply_bpe.py用于应用 BPE 子词切分;
  • flores:评测语言对数据;
  • MLQE dataset repository:翻译模型(.ptcheckpoint)与测试数据的官方下载地址,FLORES-101 上的训练/测试模型与数据均从该仓库获取。

另外 Generation 路径的 Meteor 计算需要本机安装 Java(脚本内部通过java -Xmx2G -jar调用 Meteor jar,见第 5.3 节)。

2.2 关键变量约定

原文档为整个流程定义了一组环境变量,复现前需先设置好:

变量含义
SRC_LANG/TGT_LANG源语言 / 目标语言
INPUT输入前缀:$INPUT.$SRC_LANG是源句文件,$INPUT.$TGT_LANG是参考译文文件
OUTPUT_DIR存放最终结果的路径
MOSES_DECODERmosesdecoder 安装路径
BPE_ROOTsubword-nmt 安装路径
BPEBPE 模型(bpe.codes之类)路径
MODEL_DIR包含 NMT.pt模型及源/目标词典dict.$LANG.txt的目录
TMP中间临时文件目录
GPUGPU 推理时使用的 GPU id
DROPOUT_N随机前向(或重复解码)次数 N

关于 N 的取值,原文档给出明确经验:论文实验使用DROPOUT_N=30,但作者观察到超过 10 次之后提升已不显著——因此实际部署时可根据算力预算把 N 降到 10 左右,性价比更高。

3. 第一步:标准解码产出机器译文

质量估计的对象是「模型自己产出的译文」,因此先按标准流程翻译一次测试集。

3.1 预处理(分词 + 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 done

注意-a参数表示按空格对齐分词,后续detokenizer.perl依赖这种对齐来还原原文空格;preprocessed.tok.bpe.$SRC_LANG这份 BPE 源句文件在第 4 节还会被重复使用,不要清理。

3.2 二值化加速

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.3 fairseq-generate 翻译并整理输出

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 -d- -f2- | sort -n | cut -f3- > $TMP/mt.out

fairseq-generate的标准输出格式为Hypo N <译文>(N 为句子序号),这里用grep ^H+sort -n保证多 worker 并行时句子顺序不乱,cut -f3-取出译文。

3.4 后处理(合并 BPE 标记 + 反分词)

sed -r 's/(@@ )| (@@ ?$)//g' < $TMP/mt.out | perl $MOSES_DECODER/scripts/tokenizer/detokenizer.perl \ -l $TGT_LANG > $OUTPUT_DIR/mt.out

sed去掉 subword-nmt 的@@子词连接符,detokenizer.perl依据 3.1 中的空格对齐恢复标点与空格,最终得到可读的机器译文mt.out,作为 Scoring 路径的打分对象。

4. 第二步:产生不确定性估计

4.1 Scoring 路径:MC-Dropout 打分

(1) 将源句与译文各重复 N 次

python ${SCRIPTS}/scripts/uncertainty/repeat_lines.py -i $TMP/preprocessed.tok.bpe.$SRC_LANG -n $DROPOUT_N \ -o $TMP/repeated.$SRC_LANG python ${SCRIPTS}/scripts/uncertainty/repeat_lines.py -i $TMP/mt.out -n $DROPOUT_N -o $TMP/repeated.$TGT_LANG

其中repeat_lines.py即仓库中的 repeat_lines.py,它把输入文件逐行重复 N 次写出(重复前会先做空格归一化)。

(2) 对重复后的「源句-译文」对重新二值化

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

复现提示:原文档该行写的是$TGT_DIC,是变量名笔误,执行时应统一为--tgtdict ${MODEL_DIR}/dict.${TGT_LANG}.txt;打分模型路径原文档写作${LP}.pt(语言对缩写),与前面${SRC_LANG}-${TGT_LANG}.pt指向同一 checkpoint,请保持命名一致。

(3) 带 dropout 的推理打分

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 --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 -d- -f2- | sort -n | cut -f2 > $TMP/dropout.scores

这条命令的三个要点:

  • --score-reference:不再生成新译文,而是计算模型对「源句 + 参考译文(此处即机器译文)」的对数似然分;
  • --retain-dropout:推理阶段保留 dropout,使 N 次前向的分数呈现随机波动;
  • --retain-dropout-modules:指定哪些模块启用推理期 dropout。原文档说明:若不指定,dropout 会在与训练时相同的位置生效;示例中显式列出了TransformerModelTransformerEncoderTransformerDecoderTransformerEncoderLayerTransformerDecoderLayer五类模块(命令行里写成 JSON 数组字符串)。--seed 46固定随机种子,保证实验可复现。

最后cut -f2取出每条记录的分数(Hypo N score格式的第二字段),得到 N×句数的分数流dropout.scores——同一句子的 N 个分数在文件中是连续排列的。

(4) 聚合分数

python $SCRIPTS/scripts/uncertainty/aggregate_scores.py -i $TMP/dropout.scores -o $OUTPUT_DIR/dropout.scores.mean \ -n $DROPOUT_N

aggregate_scores.py 按每 N 行一组做聚合。源码内置了六种可选聚合函数(-f参数):stdvarmedianmeanminmax,默认mean。需要强调的是:作为不确定性指标,通常应选std(分数波动越大越不确定);mean更像是对单次打分的去噪平滑。这正是该脚本支持多种聚合函数的价值所在。

4.2 Generation 路径:多假设解码 + Meteor 相似度

(1) 带 dropout 解码出 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 -d- -f2- | sort -n | 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=5 解码,得到 N 个受 dropout 扰动的译文假设;--retain-dropout-modules以空格分隔的形式传入五个模块名(而非 JSON 字符串)。

(2) 计算 N 个假设之间的 Meteor 平均相似度

python meteor.py -i $TMP/dropout.hypotheses -m <path_to_meteor_installation> -n $DROPOUT_N \ -o $OUTPUT_DIR/dropout.gen.sim.meteor

meteor.py 的输出dropup.gen.sim.meteor即每个源句对应的生成一致性得分:同一句子的 N 个假设互相越像,分数越高,翻译越确定

5. 源码纵深:--retain-dropout在 EdgeLM 中的实现

5.1 配置项定义:GenerationConfig

retain_dropoutretain_dropout_modules是 fairseq 生成配置的正式字段,定义在 GenerationConfig:

retain_dropout: bool = field( default=False, metadata={"help": "Use dropout at inference time"}, ) # temporarily set to Any until https://github.com/facebookresearch/hydra/issues/1117 is fixed retain_dropout_modules: Any = field( default=None, metadata={ "help": "if set, only retain dropout for the specified modules; " "if not set, then dropout will be retained for all modules" }, )

两点实现细节值得注意:

  • retain_dropout_modules被临时声明为Any类型(注释说明是等待 hydra 的一个 issue 修复),因此命令行既可以传 JSON 数组字符串'["TransformerModel",...]',也可以像 Generation 命令那样传空格分隔的裸模块名,两种写法在本仓库都能被接受;
  • 字段帮助文本明确:设置为 None 时,所有模块都保留 dropout,这正对应原文档「By default, dropout is applied in the same places as for training」的说法。

5.2 生效链路:从模型到 Dropout 模块

在 fairseq_model.py 中,生成流程构建解码器参数时会读取上述配置:

if getattr(cfg.generation, "retain_dropout", False): kwargs["retain_dropout"] = cfg.generation.retain_dropout kwargs["retain_dropout_modules"] = cfg.generation.retain_dropout_modules

这些参数最终经make_generation_fast_(retain_dropout=..., retain_dropout_modules=...)分发到每个 dropout 模块。核心实现在 FairseqDropout:

class FairseqDropout(nn.Module): def __init__(self, p, module_name=None): super().__init__() self.p = p self.module_name = module_name self.apply_during_inference = False def forward(self, x, inplace: bool = False): if self.p > 0 and (self.training or self.apply_during_inference): return F.dropout(x, p=self.p, training=True, inplace=inplace) else: return x

从源码结构看,其工作机制是:

  1. 每个FairseqDropout实例携带module_name(所属模块名,如TransformerEncoderLayer);
  2. make_generation_fast_被调用时,若retain_dropout=True且(未指定模块白名单,或自身module_name命中白名单),则把apply_during_inference置为 True;
  3. 之后forwardself.training or self.apply_during_inference为真,即使模型处于eval()模式也会以training=True的方式执行 dropout——这正是「推理时保留随机性」的实现关键:N 次前向共享同一 eval 模型,但 dropout 掩码逐次重新采样。

如果某个 dropout 实例的module_name为 None 而又指定了白名单,源码会打印 warning 提示「无法为该模块启用推理期 dropout」。

仓库中的测试 tests/test_inference_dropout.py 专门验证了这一机制:对同一输入重复前向,开启retain_dropout后输出分数应发生变化,可用于回归验证你本地版本的--retain-dropout是否生效。

5.3 三个辅助脚本的实现细节

  • repeat_lines.py:逐行读入、每行重复 N 次写出,写入前用" ".join(line.split())归一化空格;-o缺省时输出到 stdout。它保证 Scoring 阶段「源句与译文第 i 份严格对齐」,是后续按连续 N 行聚合的前提。
  • aggregate_scores.py:滑动窗口式聚合——累计repeat_times个分数后立即输出聚合值并清窗,因此要求输入文件中同一句子的 N 个分数必须连续(由 4.1 的sort -n步骤保证)。std/var等聚合基于 numpy,一行一个输出值。
  • meteor.py:这是三个脚本中最复杂的一个,值得细看:
    • read_translations:按连续 N 行切分,把 N 个假设归到同一个句段 id 下;
    • generate_input:对每个句段取combinations(range(N), 2)生成C(N,2)个两两配对(第 i 份做系统输出、第 j 份做参考),写入临时文件——因此 Meteor 比较的不是「假设 vs 参考译文」,而是「假设 vs 假设」;
    • run_meteor:以java -Xmx2G -jar <meteor_jar>调用,参数为-p "0.5 0.2 0.6 0.75" -norm -l <lang>。注释特别指出:这是 Meteor 默认参数,仅把 alpha 从默认值改为 0.75,使精确率与召回率在评分中获得等权重
    • read_output:只解析以Segment开头的行,每攒满 C(N,2) 个原始分段得分,就取平均输出一个句段级相似度。也就是说,对 N 个假设共有 C(N,2) 次配对比较,最终每个源句得到一个均值。

6. 结果解读与适用边界

两条路径的输出文件对应关系:

输出文件含义不确定性方向
$OUTPUT_DIR/dropout.scores.meanN 次 dropout 打分的聚合值(默认均值,可换std-f std时:越大越不确定
$OUTPUT_DIR/dropout.gen.sim.meteorN 个 dropout 假设两两 Meteor 相似度的均值越小越不确定

实践注意事项(均来自原文档与源码事实):

  1. N 的取值:论文用 30,作者实测超过 10 无显著提升,资源受限时 N=10 即可;
  2. 随机种子:示例固定--seed 46,更换种子会改变结果,跨实验对比时务必保持一致;
  3. 模块白名单:Scoring 与 Generation 两条命令的--retain-dropout-modules传参格式不同(JSON 数组 vs 空格分隔),两者在 GenerationConfig 的Any类型下均可解析;
  4. 适用前提:模型 checkpoint、词典、BPE 与 moses 分词流程必须来自同一 MLQE 训练配置,且fairseq-generate使用--beam 5 --unkpen 5与示例保持一致,才能对齐论文中的复现口径;
  5. 语言相关meteor.py默认-l en,评测非英语目标语时应显式指定目标语言。

综上,该示例目录(README + 三个脚本)构成了一套自包含的 NMT 无监督质量估计流水线:标准解码产出译文,MC-Dropout 打分与多假设 Meteor 相似度分别从「置信度」和「一致性」两个角度给出逐句质量信号,配合 FairseqDropout 的推理期 dropout 机制,即可在完全无参考、无标注的数据上部署翻译质量监控。

【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 2:43:24

Wi-Fi Mesh排障不再靠猜:R-Mesh Gravitation拓扑与信号可视化实战

小区里一户别墅客户装了三套 Mesh&#xff0c;调试了整整一个周末&#xff0c;最后发现只是子节点摆放位置的墙体里有新风管道。这种经历多了之后&#xff0c;我越来越确信一件事&#xff1a;Wi-Fi Mesh 的安装调试&#xff0c;真正难的从来不是硬件本身&#xff0c;而是排障。…

作者头像 李华
网站建设 2026/9/13 2:42:55

Python脚本化数据库备份、导出与迁移的完整实践

做系统运维和数据开发的朋友&#xff0c;应该都遇到过这种尴尬&#xff1a;半夜收到磁盘告警&#xff0c;登上去一看&#xff0c;备份文件把空间塞满了&#xff1b;或者业务方要一份上个月的订单明细&#xff0c;你下意识写了一条select * from orders扔给 pandas&#xff0c;结…

作者头像 李华
网站建设 2026/9/13 2:42:46

Linux课程设计实战:从zip解压到源码阅读与实验报告对齐

简介&#xff1a;一套Linux课程设计资料包&#xff0c;面向计算机专业学生及需要完成Shell脚本数据库备份作业的开发者&#xff0c;重点展示如何用Shell与mysqldump实现MySQL数据库的即时备份、cron定时备份、增量备份及旧备份自动清理。资源共3个文件&#xff0c;包含两个Shel…

作者头像 李华
网站建设 2026/9/13 2:42:41

AD7745电容传感器驱动开发:从I2C寄存器到Linux IIO全攻略

简介&#xff1a;AD7745官方驱动程序压缩包面向需要快速上手高精度24位Σ-Δ ADC的嵌入式开发者&#xff0c;以及工业与医疗领域的数据采集、传感器接口和精密测量场景工程师&#xff0c;用于解决芯片初始化配置、转换结果读取和主机通信对接等问题。包内共5个文件&#xff0c;…

作者头像 李华