Skip to content
Guides1 min read

完全な重複を超えて:大規模データセットのための適応的なアノテーターカバレッジ

すべてに二重ラベルを付けるのは高コストで、すべてに単一ラベルを付けるのは品質が見えません。Potato 2.6 では、ほとんどの項目に1人のアノテーターを、層化抽出したサンプルに3人を割り当て、適応的なブーストと自動の調停ルーティングを利用できます。

Potato Team

ある程度の規模のアノテーションプロジェクトには、決まって生じる緊張関係があります。各項目に2人や3人のアノテーターを付ければ、一致度を測ってラベルを信頼できますが、予算は2倍や3倍に膨らみます。各項目に1人だけ付ければ、同じ費用で3倍のデータにラベルが付きますが、そのどれもがどれほど信頼できるのか見当もつきません。

研究を運営したことのある人なら誰もが知っている定番の妥協策があります。コーパスの大部分は単一アノテーション、ごく一部のサンプルだけ二重または三重にアノテーションして品質を見張るというものです。問題は常に、ツール側にそれをきれいにこなさせること、そして重複が手に入った後にそれを何かに役立てることにありました。Potato 2.6 はこの設計を、2つの設定ブロック(num_annotators_per_itemper_annotator_quota)に加えて、適応的なブーストと調停ルーティングを通じて組み込んでいます。

本稿では、このカバレッジ設計を単純なケースから適応的なケースへと順を追って解説します。完全なリファレンスはヘテロジニアスカバレッジのドキュメントにあります。

デフォルトの単一カバレッジ、3人のアノテーターによる層化重複サンプル、不一致時の適応的ブースト、そして調停ルーティングPotato における適応的なアノテーターカバレッジ

重複サンプルを伴う項目ごとの上限

num_annotators_per_item は、一律の上限としての単一の整数を受け取ることも、項目ごとに異なるカバレッジを与えたいときには構造化されたマッピングを受け取ることもできます。よくある形は、デフォルトを1人とし、層化サンプルを3人に引き上げるというものです。

yaml
num_annotators_per_item:
  default: 1
  overlap_sample:
    fraction: 0.1
    count: 3
    stratify_by: domain
    seed: 42
  min: 1

overlap_sample ブロックは、決定論的に選ばれた項目の部分集合に対して上限を引き上げます。抽出は起動時に一度だけ行われ、選ばれた項目は内部的に印が付けられるため、それ以降の割り当てロジックはそれらを高カバレッジとして扱います。各フィールドの意味は明快です。fraction は抽出される割合、count は引き上げられた上限(デフォルトを上回る必要があります)、seed は再起動をまたいで選択を再現可能にします。

じっくり見るに値する細部が stratify_by です。これをデータ内のフィールド(ここでは domain)に向けると、割合はプール全体ではなく層ごとに適用されます。すべてのカテゴリが重複サンプルに比例して寄与するため、たまたま90%が単一ドメインで占められたサンプル上で一致度を測ることはありません。コーパスがニュース、ソーシャルメディア、臨床テキストを混在させているなら、それぞれが規模に比例して品質サンプルに現れます。

適応的ブースト:難しいところにより多く投じる

固定された重複サンプルは、誰もまだ何もアノテーションしていない段階で、盲目的に選ばれます。しかし2度目、3度目の確認を最も必要とする項目とは、アノテーターが実際に不一致を起こすものであり、それがどれなのかは最初のパスの後でしか分かりません。適応的ブーストはまさにそれに対処します。

yaml
num_annotators_per_item:
  default: 1
  adaptive:
    enabled: true
    disagreement_threshold: 0.5
    boost_to: 3

ある項目が少なくとも2件のアノテーションを得て、その不一致スコアが disagreement_threshold を越えると、その上限が boost_to に引き上げられ、その項目はもう一度のパスのために割り当てキューへ再投入されます。ブーストは項目ごとに一度きりなので、議論を呼ぶ項目は際限なく膨らむのではなく、一度だけエスカレーションされます。これは、データの難しさを前もって推測するのではなく、それに従うカバレッジです。

アノテーターごとの割り当て量

カバレッジ上限は、各項目が何人のアノテーターを得るかを制御します。別のブロックは、各アノテーターが何個の項目を得るかを制御するもので、通常は専門性や契約に応じて変えたいものです。

yaml
per_annotator_quota:
  default: 100
  by_user:
    alice: 30
  by_user_role:
    expert: 30
    novice: 200
 
user_roles:
  alice: expert
  carol: novice

解決は最も具体的なものから順に行われます。まず by_user[uid]、次に by_user_role[user_roles[uid]]、最後に default です。したがって、特定の専門家を30項目に制限し、他のすべての専門家を役割によって30に、初心者を200に設定でき、しかもこの2つの仕組みは上記の項目ごとの上限に干渉しません。

重複を判断へと変える

重複を集めるのは仕事の半分にすぎません。肝心なのは、その不一致に対して行動を起こすことです。調停ブロックを有効にすると、上限に達した重複サンプルの項目は自動的にスコアリングされ、一致度がしきい値を下回ったときに調停キューへ送り込まれます。

yaml
adjudication:
  enabled: true
  adjudicator_users: [admin]
  min_annotations: 2
  agreement_threshold: 0.75

その効果として、一致度の低い項目は、誰かが手作業でキューを再構築するのを思い出すのを待つのではなく、サンプルが飽和したまさにその瞬間に浮かび上がります。調停者がキューを開くと、全員が合意した大量の項目からすでに絞り込まれた、真に争点となっている項目が目に入ります。

一致度を読み解く

重複サンプルの項目が飽和すると、一致度の統計が /admin/iaa で利用できるようになります。このエンドポイントは、すべてに1つの数値を押し付けるのではなく、各スキームのタイプに適した指標を計算します。名義スキームには Cohen's と Fleiss' kappa、順序スキームには weighted kappa、span にはトークンレベルの kappa に加えて span F1 を用います。これが重要なのは、順序のある Likert 評定をあたかも順序のないカテゴリであるかのように計算した κ は、実際の一致度を過小評価してしまうからです。

試してみる

実行可能なデモがリリースに同梱されています。リポジトリのルートから:

bash
python potato/flask_server.py start examples/advanced/heterogeneous-coverage/config.yaml -p 8000

これは2つのドメインにまたがる20項目を使い、ドメインで層化して20%を3アノテーター重複用に抽出し、0.5のしきい値で適応的ブーストを有効にし、2つの専門性ティアを定義し、一致度の低い項目を調停へとルーティングします。上記の設計全体を、最初から最後まで通したものです。

良いカバレッジ計画のかたち

これらを組み合わせると、この設計によって、アノテーション予算を一律に広げるのではなく、どこに投じるかを決められるようになります。ほとんどの項目は1回だけ通ります。層化されたスライスは3回通るので、コーパスの一隅だけでなく全体にわたって信頼性を報告できます。蓋を開けてみて本当に難しかった項目は自動的にエスカレーションされ、争点となったものは調停者へとルーティングされます。最も不確かなデータに最も多くを投じることになり、しかもどのカバレッジの判断も方法のセクションで擁護できます。

ある特定のタスクに実際何人のアノテーターが必要かは、それ自体が別の問いです。何人のアノテーターが必要かの記事が経験則を順を追って説明しています。本リリースの眼目は、あなたがたどり着いたどんな答えであれ、それを表現しやすくすることにあります。ヘテロジニアスカバレッジは Potato 2.6 に同梱されています。上記の各ブロックでできることのすべてについては、ヘテロジニアスカバレッジのドキュメントタスク割り当てのリファレンスをご覧ください。