最优-最差量表(Best-Worst Scaling)
在 Potato 中运行最优-最差量表:标注者在每个元组里选出最好和最差的项目,再由计数法、Bradley-Terry 或 Plackett-Luce 换算成分数。
v2.3.0 新增
Best-Worst Scaling(BWS),也叫 MaxDiff,把一组项目(通常是四个)摆在标注者面前,请他按某个标准选出最好的和最差的。每个元组点两下,得到的信息比打一次分更多;而且因为判断是比较式的,它绕开了"一个标注者的 7 分相当于另一个标注者的 5 分"这个麻烦。
以下情况值得为 BWS 做这套配置:
- 直接打数值分会受到标注者之间量表使用习惯差异的影响
- 你需要在成百上千个项目上得到一份可靠的排名
- 质量维度本身就是相对的,比如哪个译文读起来最流畅
Best-worst scaling interface for comparative annotation in Potato
配置
一个 BWS 任务分成两部分。方案规定问标注者什么,顶层的 bws_config 块规定元组怎么生成、怎么评分。
bws_config:
tuple_size: 4 # items shown at once
min_item_appearances: 8 # how often each item must appear across tuples
seed: 42
scoring:
method: counting # counting | bradley_terry | plackett_luce
annotation_schemes:
- annotation_type: bws
name: fluency
description: "Select the BEST and WORST translation by fluency"
tuple_size: 4
best_description: "Most Fluent"
worst_description: "Least Fluent"
sequential_key_binding: true
label_requirement:
required: true方案只接受 tuple_size、best_description、worst_description、sequential_key_binding 和 label_requirement,此外没有别的。凡是和生成元组或给元组评分有关的,都写在 bws_config 里。
缺了 bws_config 块的 bws 方案,会在一个空的项目列表上渲染问题——BWS 任务打开是一片空白,通常就是这个原因。
bws_config 选项
| 选项 | 说明 |
|---|---|
tuple_size | 一个元组里同时显示多少个项目 |
num_tuples | 总共生成多少个元组 |
min_item_appearances | 每个项目至少要出现在多少个元组里 |
seed | 固定采样,使一次运行可以复现 |
scoring.method | counting、bradley_terry 或 plackett_luce |
调高 min_item_appearances 会收紧每个项目的分数,代价是更多的比较次数。分数出来噪声大的时候,拧的就是这个旋钮。
数据格式
数据文件的每一行是一个项目,Potato 从这个池子里采样出元组。
{"id": "sys_a", "text": "Le chat s'est assis sur le tapis."}
{"id": "sys_b", "text": "Le chat a assis sur le tapis."}
{"id": "sys_c", "text": "Le chat etait assis sur le mat."}
{"id": "sys_d", "text": "Le chat se tenait sur le tapis."}元组生成会让整个设计保持平衡:每个项目出现的次数大致相同,需要相互比较的配对共同出现得足够频繁,分数才有可比性。设了 seed,这套分配就可以复现。
评分
评分在收集完成之后进行,从命令行运行:
python -m potato.bws_scoring --config config.yaml --method counting结果写到输出目录下的 bws_scores.tsv,除非 --output 指定了别的路径。参数一共三个:--config、--method 和 --output。
计数法
默认方法,也是最透明的一个。一个项目的分数,是它被选为最好的比例减去被选为最差的比例,所以分数落在 -1.0 到 +1.0 之间。它不需要额外依赖;如果你希望读者能自己手算一遍来核对,报这个方法。
python -m potato.bws_scoring --config config.yaml --method counting --output scores.tsvBradley-Terry
在每个元组隐含的成对比较上拟合一个模型:最好的项目胜过元组里其余所有项目,其余所有项目又都胜过最差的那个。数据稀疏时,它比计数法处理得更好。
python -m potato.bws_scoring --config config.yaml --method bradley_terryPlackett-Luce
把每次判断看作两次选择:先从整个元组中选出最好的,再从剩下的项目中选出最差的,这正是 MaxDiff 对最优-最差判断如何做出的建模。它用最大似然为每个项目拟合一个效用值。2.10.2 之前,它拟合的是与 Bradley-Terry 相同的成对比较,返回的分数完全相同;如果你报告过它的结果,请用 2.10.2 或更高版本重新计算分数。
python -m potato.bws_scoring --config config.yaml --method plackett_luce选择方法
| 方法 | 速度 | 使用的信息 | 适用场景 |
|---|---|---|---|
counting | 快 | 最好和最差的计数 | 探索性分析,以及希望别人容易核对的结果 |
bradley_terry | 中等 | 隐含的成对比较 | 通常的默认选择 |
plackett_luce | 较慢 | 每一次最好和最差的选择,按做出的先后顺序 | 对判断本身的似然模型 |
bradley_terry 需要 pip install choix。plackett_luce 用的是 scipy,Potato 已经自带安装。
一次评多个维度
在同一批项目上放两个 BWS 方案,每个元组就收集两次判断,代价是多点一对按钮,而不是把语料再跑一遍:
annotation_schemes:
- annotation_type: bws
name: fluency
description: "Select the BEST and WORST by fluency"
tuple_size: 4
best_description: "Most Fluent"
worst_description: "Least Fluent"
- annotation_type: bws
name: adequacy
description: "Select the BEST and WORST by meaning preservation"
tuple_size: 4
best_description: "Most Accurate"
worst_description: "Least Accurate"输出里有什么
每个方案记录下被选为最好的项目和被选为最差的项目:
{
"fluency": {"best": "sys_d", "worst": "sys_c"},
"adequacy": {"best": "sys_a", "worst": "sys_c"}
}分数不在这个文件里。它们是事后由 potato.bws_scoring 算出来的——正因为如此,你可以换一种方法给一项已经做完的研究重新评分,而不必重新收集任何数据。
监控
管理面板有一个 BWS 标签页,显示标注进度和当前的项目分数,这样你可以在决定停止收集之前,先看看排名有没有稳定下来。
完整示例
annotation_task_name: "MT System Ranking (BWS)"
task_dir: "."
data_files:
- "data/mt_systems.jsonl"
item_properties:
id_key: id
text_key: text
bws_config:
tuple_size: 4
min_item_appearances: 8
seed: 42
scoring:
method: bradley_terry
annotation_schemes:
- annotation_type: bws
name: overall_quality
description: "Select the BEST and the WORST translation"
tuple_size: 4
best_description: "Best Translation"
worst_description: "Worst Translation"
sequential_key_binding: true
label_requirement:
required: true
output_annotation_dir: "annotation_output/"
export_annotation_format: jsonl
user_config:
allow_all_users: true先收集标注,再给它们评分:
potato start config.yaml -p 8000
python -m potato.bws_scoring --config config.yaml --method bradley_terry延伸阅读
有关实现细节,请参阅源文档。