Label Studioによる固有表現抽出のデータアノテーション ~ spacy のファインチューニング
この記事では、Label Studioを使用して固有表現抽出(NER)のデータ作成を行う方法、作成したデータを用いてspacyのモデルをfine-tuningする方法についてまとめます。
Label Studioについて
Label StudioはLLMのfine-tuningや訓練に用いるデータを作成できるツールの1つです。
特徴として、
- インストール・立ち上げがとても簡単
- 物体検出やNER、話者分離など、多様なタスクに対応している
などがあげられます。また、この記事では触れませんが、
- 機械学習モデルを用いたpre-annotationやactive-learning
- 外部データベースとの連携
なども行えるようです。
インストール
pip
だけでインストールできます。
pip install label-studio
ほかにもHomebrewやDockerなどでインストールすることもできます。詳細は公式ドキュメントをご参照ください。
インストールできた場合は、次のコマンドでLabel Studioを立ち上げられます。
label-studio
localhost:8080 に接続して以下のような画面が表示されたら成功です。
HumanSignal. Label Studioのログイン画面のスクショ
アノテーション
ユーザー作成
「SIGN UP」を選択し、適当なメールアドレス、パスワードを入力してアカウントを作成してください。(メールアドレスは実際に使用しているものでも、user@example.com のようなものでもよいと思います。)
無事にユーザー作成ができた場合は以下のような画面に移ります。
HumanSignal. Label Studioのプロジェクト一覧画面のスクショ
プロジェクト作成
-
「Create Project」からプロジェクト作成画面を開く。
-
必要な場合は「Project Name」、「Description」を設定する。
-
「Data Import」からデータをインポートする。
ファイルの例
マシンラーニング・ソリューションズは機械学習ベンチャー企業へ様々な支援を行う株式会社である。 マシンラーニング・ソリューションズは2017年に設立された。 世界レベルの機械学習研究者をマシンラーニング・ソリューションズは技術顧問として招聘している。
.txt
ファイルをインポートすると「Treat CSV/TSV as ...」と選択肢が出てきますが、「List of tasks」を選ぶようにしてください。また
.txt
ファイルの場合、1つの行が1つのデータに分割されます。改行を含むデータを扱いたい場合などは他の形式を用いる必要があります -
「Labeling Setup」から「Named Entity Recognition」を選択する。
HumanSignal. Label Studioのテンプレート選択画面のスクショ新たなラベルを追加するなどの細かな設定はここで行うことができます。詳細は公式ドキュメントをご参照ください。
-
「Save」を押す。以下のようにデータが追加されていれば成功。
HumanSignal. Label Studioのプロジェクト画面のスクショ
アノテーションの作成
「Label All Tasks」をクリックするとアノテーション画面に移ります。1つのデータにだけラベル付けしたい場合は、そのデータをクリックすればよいです。
つけたいラベルを選択し、文章の該当部分を範囲選択することでラベル付けできます。
以下は、“マシンラーニング・ソリューションズ”にラベルORGをつける際の画面です。
HumanSignal. Label Studioのアノテーション画面のスクショ
すべてのラベルを付け終えたら「Submit」で保存できます。「Label All Tasks」を押して始めた場合は次のデータのアノテーション画面に移り、そうでない場合はアノテーションが終了します。
fine-tuning
spacyのインストール
pip install -U pip setuptools
pip install -U spacy
python -m spacy download ja_core_news_sm
動作確認
spacyを用いてNERを行うコードの例です。
import spacy
nlp = spacy.load("ja_core_news_sm")
txt = "マシンラーニング・ソリューションズのオフィスは東京都にある。"
doc = nlp(txt)
for ent in doc.ents:
print(ent.text, ent.label_)
以下のような出力が得られます。
東京都 GPE
作成したデータのダウンロード・変換
まず、アノテーションの作成 を参考に、データのラベル付けを行ってください。
プロジェクト画面右上の「Export」を押し、「JSON-MIN」を選択してから右下の「Export」を押すとデータをJSON形式でダウンロードできます。
HumanSignal. Label Studioのエクスポート画面のスクショ
出力されるファイルの例
[
{
"text": "マシンラーニング・ソリューションズは機械学習ベンチャー企業へ様々な支援を行う株式会社である。",
"id": 1,
"label": [
{
"start": 0,
"end": 17,
"text": "マシンラーニング・ソリューションズ",
"labels": [
"ORG"
]
}
],
"annotator": 2,
"annotation_id": 159,
"created_at": "2024-04-02T00:36:58.236828Z",
"updated_at": "2024-04-02T00:36:58.236870Z",
"lead_time": 126.952
},
{
"text": "マシンラーニング・ソリューションズは2017年に設立された。",
"id": 2,
"label": [
{
"start": 0,
"end": 17,
"text": "マシンラーニング・ソリューションズ",
"labels": [
"ORG"
]
}
],
"annotator": 2,
"annotation_id": 160,
"created_at": "2024-04-02T00:37:06.698209Z",
"updated_at": "2024-04-02T00:37:06.698239Z",
"lead_time": 7.445
},
{
"text": "世界レベルの機械学習研究者をマシンラーニング・ソリューションズは技術顧問として招聘している。",
"id": 3,
"label": [
{
"start": 14,
"end": 31,
"text": "マシンラーニング・ソリューションズ",
"labels": [
"ORG"
]
}
],
"annotator": 2,
"annotation_id": 161,
"created_at": "2024-04-02T00:37:42.870619Z",
"updated_at": "2024-04-02T00:37:42.870645Z",
"lead_time": 33.072
}
]
そのままではfine-tuningに使用できないため、以下のようなコードによって.spacy
ファイルに変換する必要があります。
コード例
import spacy
from spacy.tokens import DocBin
import json
nlp = spacy.blank("ja")
with open("/path/to/annotation_data.json", encoding="utf-8") as f:
training_data = json.loads(f.read())
db = DocBin()
for annotation in training_data:
doc = nlp(annotation["text"])
ents = []
for label in annotation["label"]:
span = doc.char_span(label["start"], label["end"], label["labels"][0])
if span is not None:
ents.append(span)
doc.ents = ents
db.add(doc)
db.to_disk("./train.spacy")
db.to_disk("./dev.spacy")
train.spacy
とdev.spacy
は異なるべきですが、今回は簡単のためにどちらも同じにしました。
fine-tuning
-
base_config.cfg
ファイルを作成し、以下の内容を入力する。base_config.cfg の中身
base_config.cfg# This is an auto-generated partial config. To use it with 'spacy train' # you can run spacy init fill-config to auto-fill all default settings: # python -m spacy init fill-config ./base_config.cfg ./config.cfg [paths] train = null dev = null vectors = null [system] gpu_allocator = null [nlp] lang = "ja" pipeline = ["tok2vec","ner"] batch_size = 1000 [components] [components.tok2vec] factory = "tok2vec" [components.tok2vec.model] @architectures = "spacy.Tok2Vec.v2" [components.tok2vec.model.embed] @architectures = "spacy.MultiHashEmbed.v2" width = ${components.tok2vec.model.encode.width} attrs = ["NORM", "PREFIX", "SUFFIX", "SHAPE"] rows = [5000, 1000, 2500, 2500] include_static_vectors = false [components.tok2vec.model.encode] @architectures = "spacy.MaxoutWindowEncoder.v2" width = 96 depth = 4 window_size = 1 maxout_pieces = 3 [components.ner] factory = "ner" [components.ner.model] @architectures = "spacy.TransitionBasedParser.v2" state_type = "ner" extra_state_tokens = false hidden_width = 64 maxout_pieces = 2 use_upper = true nO = null [components.ner.model.tok2vec] @architectures = "spacy.Tok2VecListener.v1" width = ${components.tok2vec.model.encode.width} [corpora] [corpora.train] @readers = "spacy.Corpus.v1" path = ${paths.train} max_length = 0 [corpora.dev] @readers = "spacy.Corpus.v1" path = ${paths.dev} max_length = 0 [training] dev_corpus = "corpora.dev" train_corpus = "corpora.train" [training.optimizer] @optimizers = "Adam.v1" [training.batcher] @batchers = "spacy.batch_by_words.v1" discard_oversize = false tolerance = 0.2 [training.batcher.size] @schedules = "compounding.v1" start = 100 stop = 1000 compound = 1.001 [initialize] vectors = ${paths.vectors}
-
python -m spacy init fill-config base_config.cfg config.cfg
を実行する。 -
作成された
config.cfg
の一部を以下のように書き替える。base_config.cfg[components.ner] - factory = "ner" + source = "ja_core_news_sm" incorrect_spans_key = null
base_config.cfg[components.tok2vec] - factory = "tok2vec" + source = "ja_core_news_sm"
-
python -m spacy train config.cfg --output ./output --paths.train ./train.spacy --paths.dev ./dev.spacy
を実行する。モデルがoutput/model-last
に出力される。
モデルの使用
作成したモデルは以下のように使用することができます。
このコードは使用するモデルを除き、spacyのインストールの動作確認で用いたものと同じです。
import spacy
# nlp = spacy.load("ja_core_news_sm")
nlp = spacy.load("./output/model-last")
txt = "マシンラーニング・ソリューションズのオフィスは東京都にある。"
doc = nlp(txt)
for ent in doc.ents:
print(ent.text, ent.label_)
以下のような出力が得られます。
マシンラーニング・ソリューションズ ORG
東京都 GPE
モデルとしてja_core_news_sm
を使用した際は“マシンラーニング・ソリューションズ”は検出されませんでしたが、fine-tuningしたことによりORGとして検出されていることがわかります。
おわりに
本記事ではLabel Studioによってデータアノテーションを行う方法、および作成したデータでspacyモデルのfine-tuningを行う方法についてまとめました。
本文中でも少しだけ言及しましたが、Label StudioにはNER以外のテンプレートが多数あり、幅広いタスクに対応しています。また、便利な機能もたくさんありますので、アノテーションを行う際にはぜひLabel Studioを試してみてください。
参考文献
-
HumanSignal,Label Studio Documentation
-
HumanSignal,HumanSignal/label-studio
-
朝日新聞社 メディア研究開発センター,アノテーションツール「Label Studio」のご紹介【無料でどこまでできる?】
-
Explosion,spaCy Usage Documentation - Training Pipelines & Models
-
Jim Zieleman,Training and Fine Tuning NER transformer models using spaCy3 and spacy-annotator
Discussion