コンテンツへスキップ

アノテーションデータでモデルを学習する

複数のアノテーターのラベルを学習の目標に統合し、ラウンドをまたいでホールドアウトのtest分割を固定し、各モデルが見たものを記録して、最初の実行の規模を見積もります。

アノテーションデータでモデルを学習するには、各項目のラベルを1つの目標か、アノテーターの票の割れ方に統合し、ラウンドをまたいで固定されるルールで項目をtrain、validation、testの各分割に割り当て、validationの分割でチェックポイントを選んだときは、testのスコアを報告します。Potatoのモデル学習は、研究自身のアノテーションでこれらの各ステップを実行し、各実行がどの項目で学習したかを記録します。

v2.14.0の新機能

アノテーションデータが、トレーナーの読む形で届くことはまれです。重複のある研究では、1つの項目に複数のラベルがあり、ラベルはしばしば食い違います。進行中の研究では、毎日ラベルが増え、再学習のラウンドごとに、前のラウンドより多くの項目が使われます。トレーナーには、項目ごとに1つの目標と、スコアを測るための固定された項目の集合が必要で、以下の判断が両方を用意します。以下の各節では、その判断を行うPotatoの設定を挙げます。Trainingページそのものについては、モデル学習の概要と、最初のモデルを学習するチュートリアルを参照してください。自分のコードで学習したい場合は、機械学習のためのアノテーションのエクスポートにエクスポート形式があり、同じ判断がエクスポートしたファイルにも当てはまります。

複数のアノテーターを1つのラベルに統合する

集約は、1つの項目に複数のアノテーターが付けたラベルを、モデルが学習する1つのラベルにします。最も単純な方法は多数決です。多数決は、各アノテーターの答えを1回ずつ数え、最も多い答えを残します。Dawid and Skene (1979)は、期待値最大化法で各アノテーターの混同行列を推定し、推定された信頼性で各票に重みをつけます。すると、不注意なアノテーターは、注意深いアノテーターよりも結果への影響が小さくなります。クラウドラベルの集約は、2つの方法と、Dawid-Skeneを土台にしたモデルを比較します。

Potatoの学習の実行は、model_training.aggregationでラベルを統合します。既定のconsensusは、プロジェクトにアノテーターが2人以上いればDawid-Skeneを実行し、推定が失敗すれば多数決に切り替えます。もう1つの値majorityは、多数決だけを実行します。どちらの方法も、スキームに対するアノテーターの答え全体を1票として扱います。そのため、2つのmultiselectの答えが同じ票と数えられるのは、両方の答えが同じラベルの集合にチェックを入れたときだけです。

実行のconsensus設定と、コンセンサスのエクスポートは別の機能です。コンセンサスのエクスポートは、各アノテーターに1票を与え、すべての項目のすべての答えの件数と割合を報告し、各項目にretiredかneeds_reviewの印を付けます。アノテーターがどこで割れているかを項目ごとに見たいときは、学習の前にエクスポートを読んでください。MACEは、同じ票から各アノテーターの能力スコアを推定します。

不一致から学ぶ

攻撃性や感情のような主観的なタスクでは、各アノテーターが項目を異なって読むため、アノテーターが食い違うことがあり、投票で決めた1つのラベルは、その割れ方を捨ててしまいます。Uma et al. (2021)は、1つの集約ラベルではなく、不一致そのものから学習する方法を概観しています。そうした方法の1つの系統は、ソフトラベルで学習します。ソフトラベルは、各ラベルを選んだアノテーターの割合から作る、ラベル上の確率分布です。

hf-text-classificationは、パラメーターsoft_targets: trueを受け取ります。このパラメーターを設定すると、2人以上のアノテーターがラベルを付けた項目は、分布に対するクロスエントロピーで、アノテーターの割れ方に向けて学習します。3人のうち2人がpositiveと答えたなら、目標はpositiveが0.67、negativeが0.33です。multiselectのスキームでは、各ラベルが、そのラベルにチェックを入れたアノテーターの割合に向けて学習します。アノテーターが1人の項目は、これまでどおり、そのアノテーターのラベルで学習します。すると、モデルは人々の意見が割れたところで迷ったままになり、各予測にはモデルのprobabilitiesが含まれます。票の割れている項目のホールドアウトでは、実行はさらに3つの指標を報告します。

指標その指標が測るもの
soft_jsdモデルの分布とアノテーターの割れ方の間のJensen-Shannonダイバージェンス。単位はビットで、0から1
soft_cross_entropyモデルの分布のもとでの、アノテーターの割れ方のクロスエントロピー
ece上位ラベルを投票で決まったラベルと比べた期待較正誤差。信頼度10区間で計算

ソフトラベルのスキームでは、各アノテーターがスライダーで分布を答えます。hf-text-classificationは、soft_labelスキームを常にアノテーターの平均の分布に向けて学習し、事前ラベルは、スライダーを予測した分布に設定します。ソフトな目標には、項目に2つ以上のラベルが必要です。そのため、不一致から学習するつもりの研究は、最初から重複したラベルを集めることになり、重複の設定はアノテーターは何人必要かで扱います。割れ方をデータに残す理由は、不一致はノイズではなくシグナルで述べています。

train、validation、testの分割

学習、検証、テストの分割は、3つの異なる役割を担います。train分割は、モデルの重みを当てはめます。validation分割は、候補のモデルの中から、例えば学習を止めるエポックを選びます。test分割は、未見のデータでの性能を推定し、そのどちらの選択にも関与しません。validationでチェックポイントを選ぶことは、validationへの当てはめの一種です。validationのスコアが最良だったチェックポイントは、そのvalidationのスコアが上に偏っており、選択が一度も参照していない項目から出るのは、testのスコアだけです。

Potatoの実行は、既定でラベル付きの項目を70/15/15に分けます(splits)。各項目の分割は、項目IDのシード付きハッシュで決まります(split_seed)。そのため、ある実行でホールドアウトされた項目は、split_seedとsplitsが変わらない限り、次の実行でもホールドアウトされたままです。どちらかの設定を変えると、ホールドアウトした項目が学習に移ることがあり、その後のすべてのスコアは、一部が暗記を測ることになります。どちらも、研究の始めに1度だけ設定してください。

hf-text-classificationのようなファインチューニングのトレーナーは、validationで最良のスコアを出したエポックのチェックポイントを残します。そうした実行の主要なスコアは、testから取られます。sklearn-text、setfit、rdkit-property、判断モデルのトレーナー、推論ブリッジは、validationで何も選ばず、これらのトレーナーの実行は、validationに項目があれば、主要なスコアをvalidationから取ります。RunsテーブルのHeld-out score列のツールチップには、各数値の元となる分割と指標が書かれています。ラベルがあって予測のない項目は、誤りと数えられます。トレーナーが難しい項目を飛ばしてスコアを上げることはできず、<split>_coverageは、予測を得た項目の割合を報告します。

修正された項目と固定された項目

2種類の項目が、ハッシュがどの分割に割り当てたかにかかわらず、以降のすべての実行のtrain分割に入ります。1つは、モデルレビューでレビュー担当者が修正した項目で、もう1つは、Catalogページのスライスの横のTrain on theseで誰かが固定した項目です。修正は、モデルが最も苦手だった項目から出るため、validationやtestに入れると、モデル自身の間違いの標本でモデルのスコアを測ることになります。ホールドアウトした項目を学習に移した実行は、その件数の警告をログに出し、その実行のホールドアウトスコアは、以前の実行のスコアとは直接比較できなくなります。以前の実行がホールドアウトした修正済みの項目で学習する実行も警告をログに出します。以前の実行のvalidationまたはtestの項目、あるいはそれらの項目から保存したデータセットでのスコアには、新しいモデルが学習に使った項目が含まれることになるからです。修正と固定された項目は常に学習されるに、そのルールがあります。

各モデルが何で学習したかを記録する

2つの実行を比べるには、各実行がどの項目で学習し、どの項目でスコアを測ったかを知る必要があります。Potatoの実行はどれも、<output_annotation_dir>/training/runs/<run_id>/bundle/の下に、train.jsonl、val.jsonl、test.jsonl、labels.json、manifest.jsonを持つバンドルを書き出します。マニフェストには、分割のシード、集約の方法、各分割の項目数、学習に強制的に入れた項目の数、分割ファイルのSHA-256ダイジェストが記録されます。バンドルの中にPotatoを参照するものはなく、Potatoの外のスクリプトは、バンドルを、統合したラベルと分割の自己完結したコピーとして読めます。

プロジェクトのデータベースproject.sqliteには、実行ごとに1行の台帳があります。各行には、トレーナー、パラメーター、分割のサイズ、分割のシード、ホールドアウトの指標、バンドルのダイジェストが記録されます。2つ目のテーブルには、各実行で各項目がどの分割に入っていたかが記録されます。書き戻しはこのテーブルを読み、台帳に残っているどの実行かが学習に使った項目には、事前ラベルを決して付けません(retain_runsは、既定で完了した実行を5つ残します)。モデルは、新しいデータについて何も語らない理由で、学習に使った項目に自信を持つからです。

後のモデルをまったく同じ項目で比較するには、実行ページのKeep this split as a datasetが、実行のvalidation、test、またはtrainの項目を、合意された人手のラベルとともに、データセットのバージョンとして保存します。保存されたバージョンは、その後変わりません。保存された各バージョンは1つの分割を含み、前のバージョンに追加するのではなく、ゼロから始まります。実行2のvalidationの項目を実行1のものの上に保存すると、実行2が学習に使った項目が含まれてしまうからです。保存された入力には事前ラベルのフィールドが含まれないため、保存されたバージョンでの評価がモデルの答えを読むことはできません。保存には、datasets.enabled: trueが必要です。モデルやデータセットがプロジェクトの外に出るときの、データシートとモデルカードについては、データセットとモデルの文書化で扱います。

最初のモデルに必要なデータ量

Potatoの各トレーナーは、train分割の項目がmin_instances件に満たないと、学習を拒否します。次の既定値は、実行が始まる件数です。

トレーナーmin_instancesの既定値備考
setfit8プロジェクトの最初の数日向けで、ラベルあたり約8件から
sklearn-text10信頼度の較正は、学習項目が50件以上のときだけ
hf-audio-tagger10
hf-text-classification、hf-token-classification、hf-image-classification20
llm-sft、llm-dpo20

下限が数えるのは、train分割だけです。既定の70/15/15の分割では、sklearn-textの実行は、約15件の項目にラベルがつくと始まります。Potatoのリポジトリにあるモデル学習のサンプルが、実測値を1つ示しています。サンプルの160件の合成の商品レビューのうち120件に1回ずつラベルを付けたところ、1回のsklearn-textの実行は、validationでマクロF1が0.84となり、80件の事前ラベルを公開しました。この数値は、1つの合成の2ラベルのタスクから得たもので、自分のタスクについて読むべき数値は、自分の実行のホールドアウトスコアです。

まずsklearn-textから始めてください。このトレーナーは、通常のインストール以外に何も必要とせず、GPUも要りません。ラベルが届くたびに再学習し、split_seedを変えないまま、実行ごとにホールドアウトスコアを見ます。事前ラベルはアノテーターを引き寄せます。ホールドアウトスコアがモデルの答えを見せることを支えるようになるまでは、writeback.schemasを空のままにしてください。アノテーターが事前ラベルを見るようになると何が変わるかはモデル支援ラベリングで、アノテーターがまだ項目を読んでいるかを確認する方法はレビューとゴム印の見分け方で扱います。

各判断を設定する設定ファイル

次の設定は、2ラベルの感情スキームで学習します。model_trainingの下の各キーが、上の判断の1つを設定します。

yaml
annotation_task_name: "Review sentiment"
task_dir: "."
data_files:
  - "data/reviews.json"
item_properties:
  id_key: "id"
  text_key: "text"
output_annotation_dir: "annotation_output"
 
annotation_schemes:
  - annotation_type: "radio"
    name: "sentiment"
    description: "Is this review positive or negative?"
    labels: ["positive", "negative"]
 
model_training:
  enabled: true
  aggregation: consensus
  split_seed: 0
  splits: {train: 0.7, val: 0.15, test: 0.15}
  trainer_params:
    hf-text-classification:
      soft_targets: true

aggregation: consensusは、重複したラベルをDawid-Skeneで統合します。split_seedとsplitsは、どちらの設定も研究の間は変えるべきではないため、既定値のまま明示的に書いてあります。soft_targets: trueは、プロジェクトでのhf-text-classificationの実行すべてを、票の割れ方で学習させます。そのトレーナーにはpip install "potato-annotation[train-text]"が必要で、sklearn-textは、同じ設定で追加のインストールなしに動きます。writebackブロックがないと、アノテーターに事前ラベルは表示されません。設定でサーバーを再起動し、/admin/trainingを開き、トレーナーとsentimentスキームを選んで、Train nowをクリックします。すべてのキーはモデル学習の設定のリファレンスに挙げてあり、モデル・イン・ザ・ループのチュートリアルは、書き戻しと自動の再学習を加えます。

関連資料

参考文献

  • Dawid, A. P., and Skene, A. M. (1979). Maximum Likelihood Estimation of Observer Error-Rates Using the EM Algorithm. Applied Statistics, 28(1), 20. doi.org/10.2307/2346806
  • Uma, A. N., Fornaciari, T., Hovy, D., Paun, S., Plank, B., and Poesio, M. (2021). Learning from Disagreement: A Survey. Journal of Artificial Intelligence Research, 72, 1385–1470. doi.org/10.1613/jair.1.12752