この記事はMYJLabアドベントカレンダー23日目です。
はじめに
こんにちは。MYJLab m1のmarutakuです。今回は、固有表現抽出と呼ばれる技術を使う機会があったので、その時に使ったライブラリの紹介をしようと思います。
固有表現抽出(NER)について
固有表現抽出(Named Entity Recognition)とは、企業名や地名などの固有名詞を企業・地名などのラベル付きで取得してくる技術です。
例として、
米航空機大手ボーイングは23日、ミュイレンバーグ最高経営責任者(CEO)の即時辞任を発表した。
2度の墜落事故を起こして運航停止中の最新鋭機「737MAX」の問題の責任を取ったとみられる。
カルフーン会長が来年1月13日付でCEO職に就くという。
https://news.yahoo.co.jp/pickup/6346205
この時、人名はミュイレンバーグ, カルフーン
であり、組織名はボーイング
ということがわかります。このように、文章の中に存在する固有名詞を取得するのが固有表現抽出のタスクです。
データセット
このリポジトリにまとまってます。よく使われるのはCoNLL2003とOntonotes v5だと思っています。他にも、医療系のデータやwikipedhiaのアノテーション済みデータなどがあります。
日本語のデータセットはあまり公開されていませんが、売ってはいるようです。
固有表現抽出の難しいところ
最近の固有表現抽出の論文は、実装するのが大変難しいです。Paper With Codeをみてもらえればわかると思いますが、大量のモデルをスタックさせて使用したり、複数の事前学習済みモデルの単語表現を使用したいりしているので大変面倒です。LSTM-CRF+ELMo+BERT+Flair
とかモウナニイッテルノカワカラナイ。
そんな時に、NERのState of the artを達成したモデルを簡単に実装できるFlairというライブラリに出会いました。
Flairとは
Flairは、簡単にState of the artのモデルを実装できるようにと作られた自然言語処理用のライブラリです。学習済みのモデルが豊富に用意されており、過去のSoTAモデルをすぐに自分のシステムに組み込むことができます。
チュートリアルにも書いてありますが、Flairで学習済みの固有表現抽出モデルを試す時は以下のコードだけで実現できます
from flair.data import Sentence
from flair.models import SequenceTagger
# make a sentence
sentence = Sentence('I love Berlin .')
# load the NER tagger
tagger = SequenceTagger.load('ner')
# run NER over sentence
tagger.predict(sentence)
ここで用いられているner
というモデルの他にも、CPUでも高速に動作するner-fast
というモデルなど多様なモデルが存在しています。
Flairを用いた自作モデル
Flairは学習済みモデルの実行だけではなく、自作のモデルを作成することも可能です。
Flairは学習済みモデルだけでなく、有名なモデルの埋め込み表現も簡単に扱えるようにしています。(https://github.com/flairNLP/flair/blob/master/resources/docs/TUTORIAL_4_ELMO_BERT_FLAIR_EMBEDDING.md)
自作のモデルの例を以下に示します。
from flair.data import Corpus
from flair.datasets import WNUT_17
from flair.embeddings import TokenEmbeddings, WordEmbeddings, StackedEmbeddings
from typing import List
# 1. get the corpus
corpus: Corpus = WNUT_17().downsample(0.1)
print(corpus)
# 2. what tag do we want to predict?
tag_type = 'ner'
# 3. make the tag dictionary from the corpus
tag_dictionary = corpus.make_tag_dictionary(tag_type=tag_type)
print(tag_dictionary.idx2item)
# 4. initialize embeddings
embedding_types: List[TokenEmbeddings] = [
WordEmbeddings('glove'),
# comment in this line to use character embeddings
# CharacterEmbeddings(),
# comment in these lines to use flair embeddings
# FlairEmbeddings('news-forward'),
# FlairEmbeddings('news-backward'),
]
embeddings: StackedEmbeddings = StackedEmbeddings(embeddings=embedding_types)
# 5. initialize sequence tagger
from flair.models import SequenceTagger
tagger: SequenceTagger = SequenceTagger(hidden_size=256,
embeddings=embeddings,
tag_dictionary=tag_dictionary,
tag_type=tag_type,
use_crf=True)
# 6. initialize trainer
from flair.trainers import ModelTrainer
trainer: ModelTrainer = ModelTrainer(tagger, corpus)
# 7. start training
trainer.train('resources/taggers/example-ner',
learning_rate=0.1,
mini_batch_size=32,
max_epochs=150)
# 8. plot weight traces (optional)
from flair.visual.training_curves import Plotter
plotter = Plotter()
plotter.plot_weights('resources/taggers/example-ner/weights.txt')
上のモデルはglove
というモデルの埋め込み表現をモデル内部で使用していますが、これを増やすことで複数の単語埋め込み表現を利用することができます。
まだ試してはいないですが、埋め込み表現のファインチューニングもできるみたいです。
終わりに
今回は、NERの話とFlairの話をしました。FlairはNERの他にもネガポジ判定やテキスト分類などのタスクに応用が可能です。自然言語処理使いたいけど難しそう…と思っている方はぜひ使ってみてください。