Skip to content
チュートリアル7分で読めます

初めてのNERアノテーションタスクの構築

Potatoで固有表現認識タスクを構築するステップバイステップガイド。スパンアノテーションの設定、ラベルの色、重なり合うスパン、キーボードショートカット、CoNLLエクスポートを扱います。

Potato Team

このチュートリアルでは、5つのエンティティタイプ、数字キーのショートカット、アノテーター向けの指示、モデル学習用のCoNLL-2003エクスポートを備えた固有表現認識(NER)タスクをPotatoで構築します。その土台となるスパン設定のオプションについては、スパンアノテーションのドキュメントを参照してください。

アノテーターが使う画面

完成したタスクでは、アノテーターに1つの文と、その上に並ぶラベル付きボタンの列が表示されます。アノテーターはフレーズをドラッグして選択し、数字キーを押すかボタンをクリックしてラベルを付け、ラベル付きのスパンをもう一度クリックすると変更や削除ができます。各スパンは文字オフセットとともに保存されるため、同じアノテーションファイルからCoNLL-2003エクスポートとスパン単位の一致度計算の両方を行えます。

前提条件

Potatoのインストール、テキストのデータファイル、設定ファイルを編集できる程度のYAMLの知識が必要です。

bash
pip install potato-annotation

ステップ1:スパンスキーム

スパンアノテーションはPotatoのspanタイプです。各ラベルには名前が必要です。有用なオプションフィールドは3つあります。colorは密なテキストの中でエンティティタイプを視覚的に区別し、key_valueはラベルにキーボードショートカットを割り当て、tooltipはホバー時にラベルの定義を表示するので、アノテーターはコードブックを確認するためにページを離れる必要がありません。

タイプが5つなら、1回のセッションでタスクを習得できます。8つ程度を超えると、アノテーターはアイテムごとにガイドラインを確認するようになり、そこで作業速度が落ちます。sequential_key_bindingで数字キーが有効になり、key_valueでどの数字がどのラベルに対応するかをリストの順序に任せずに固定します。config.yamlを作成します。

yaml
annotation_task_name: "Named Entity Recognition"
task_dir: "."
 
data_files:
  - data/sentences.json
 
item_properties:
  id_key: id
  text_key: text
 
output_annotation_dir: "annotation_output/"
export_annotation_format: "jsonl"
 
annotation_schemes:
  - annotation_type: span
    name: entities
    description: "Highlight and label named entities in the text"
    sequential_key_binding: true
    labels:
      - name: PER
        tooltip: "Person names, including fictional characters"
        color: "#FF6B6B"
        key_value: "1"
      - name: ORG
        tooltip: "Companies, institutions, agencies"
        color: "#4ECDC4"
        key_value: "2"
      - name: LOC
        tooltip: "Places, including countries, cities, landmarks"
        color: "#45B7D1"
        key_value: "3"
      - name: DATE
        tooltip: "Dates, times, and temporal expressions"
        color: "#96CEB4"
        key_value: "4"
      - name: MISC
        tooltip: "Named entities that fit none of the above"
        color: "#FFEAA7"
        key_value: "5"
 
user_config:
  allow_all_users: true

ステップ2:データファイル

Potatoは1行に1つのJSONオブジェクトを読み込み、item_propertiesで指定したフィールドを取り出します。data/sentences.jsonを作成します。

json
{"id": "1", "text": "Apple Inc. announced that CEO Tim Cook will visit Paris next Tuesday."}
{"id": "2", "text": "The United Nations headquarters in New York hosted delegates from Japan."}
{"id": "3", "text": "Dr. Sarah Johnson published her research at Stanford University in March 2024."}

インターフェースが動作するかを確認するには3文で足ります。実際のコーパスは、ラベルセットがパイロットを通過してから読み込んでください。

ステップ3:アノテーターがすぐに参照できる指示

NERの不一致の大半はエンティティタイプそのものではなく境界のルールから生じます。そのため、最も多くのアイテムを左右するルールはアノテーション画面に置くべきです。annotation_instructionsは各アイテムの上部に折りたたみ可能なパネルとして表示されます。初期状態では開いていて、アノテーターはタスクに慣れたら折りたたみます。上の設定に次のブロックを追加します。

yaml
annotation_instructions: |
  ## Entity types
 
  - **PER** covers people, including fictional characters ("John Smith", "Dr. Johnson", "Batman")
  - **ORG** covers companies, institutions, and agencies ("Apple Inc.", "United Nations", "Stanford University")
  - **LOC** covers places, including countries, cities, and landmarks ("Paris", "New York", "Mount Everest")
  - **DATE** covers dates, times, and temporal expressions ("Tuesday", "March 2024", "next week")
  - **MISC** covers named entities that fit none of the above ("Nobel Prize", "iPhone", "COVID-19")
 
  ## Boundary rules
 
  1. Include titles (Dr., Mr.) with person names.
  2. For nested entities, annotate the largest meaningful span.
  3. Leave articles (the, a) outside the span.

ここではMarkdownがレンダリングされるので、コードブックの文章をHTMLに書き直さずにそのまま流用できます。このパネルには大半のアイテムを決めるルールだけを載せ、コードブック全体は別タブで開くannotation_codebook_urlの先に置いてください。

これで、スパンインターフェースはテキストの上にラベルをボタンとして表示します。

色分けされたエンティティタイプを持つ固有表現スパンアノテーションインターフェースアノテーターはテキストスパンをハイライトし、PER、ORG、LOC、DATEなどのエンティティラベルを割り当てます

ステップ4:タスクの実行

ステップ1の設定でサーバーを起動します。

bash
potato start config.yaml

表示されたアドレスを開いてログインします。アノテーターはエンティティごとに次の4つの操作を行います。

  1. テキストを選択する。 フレーズをクリックしてドラッグします。
  2. タイプを割り当てる。 数字キーを押すか、ラベルボタンをクリックします。
  3. 誤りを直す。 既存のスパンをクリックして、ラベルを変更するか削除します。
  4. 送信する。 文が終わったら次のアイテムに進みます。

ステップ5:出力ファイルの内容

アノテーション済みの各アイテムはannotation_output/に1つのJSONオブジェクトとして書き出されます。スキーム名がキーになり、スパンごとに1つのエントリが入ります。

json
{
  "id": "1",
  "text": "Apple Inc. announced that CEO Tim Cook will visit Paris next Tuesday.",
  "entities": [
    {"start": 0, "end": 10, "label": "ORG", "text": "Apple Inc."},
    {"start": 30, "end": 38, "label": "PER", "text": "Tim Cook"},
    {"start": 50, "end": 55, "label": "LOC", "text": "Paris"},
    {"start": 61, "end": 73, "label": "DATE", "text": "next Tuesday"}
  ]
}

このファイルを後工程で役立つものにしているのは文字オフセットです。文字オフセットはトークン化の変更に影響されないため、同じアノテーションをモデルが使うどのトークナイザーにも再アラインできます。

ステップ6:CoNLL-2003へのエクスポート

系列ラベリングモデルは文字オフセットではなくタグ付きトークンを読み込むため、Potatoはエクスポート時にスパンを変換します。

bash
python -m potato.export -c config.yaml -f conll_2003 -o ./conll_export/

出力は1行に1トークンとそのタグで、文と文の間は空行になります。tag_schemeオプションはBIO、BIOES、IOBのいずれかで書き出し、既定値はBIOです。エクスポートを実行する前に、学習コードが想定する形式に合わせてください。

ガイドラインを引き締める

曖昧なルールは同じスパンに対する判断を割れさせるので、パイロットが小規模なうちにルールを見直す価値があります。難しいケースはアノテーターが作業を始めた後ではなく前に説明し、決着したエッジケースは出てくるたびに共有リストに記録してください。アノテーター間の一致度の低下はルールを引き締める必要があるという合図であり、5,000アイテムよりも50アイテムの段階で気づくほうがコストは小さく済みます。

次のステップ