spaCyでフィンランド語のNERをしたので記録しておく。使用しているのはspaCy ver. 3.1である。
フィンランド語NLPの状況
spaCyにフィンランド語のモデルはない(モデル一覧)。Antti Ajanki氏が非公式にフィンランド語のspaCy用のモデルを公開している。しかし,このモデルには固有表現抽出(NER)が含まれていない。精度が悪いため入れていないと書かれている。
他方,フィンランド語のNER用のデータセットがTurku大学によって公開されている(LREC 2020)。従って,spaCyをこのデータセットで訓練すればspaCyのパイプラインでNERができるはずである。
spaCyに学習させる
データ形式
spaCyは,訓練時には.spacy形式しか入力として受け付けない。この形式に変換する機能も同時に提供されているので,それを用いる。spaCyのドキュメントによれば,以下のコマンドで変換できる。
$ python -m spacy convert <input_file> <output_dir> --converter <入力ファイルの形式>
入力ファイルの形式は,以下に対応している。
引数 | 形式 | 説明 |
---|---|---|
json |
spaCy2.xで使われていた形式 | |
conllu |
UDで使われる.connlu形式 | CoNLL-U形式である。 |
ner |
NERで使われるCoNLL形式 |
-DOCSTART- で始まるCoNLLのデータがそのまま入力できる。 |
iob |
自分で作るならこれが楽。1文1行で,各単語はスペース区切り。各単語は,「word|pos|BIO」または「word|BIO」の形式で記述される。 |
今回使うデータセットはCoNLL形式だったので,ner
を指定すれば何ら前処理の必要はなかった。また,上述のコマンドを使うと,-n 10
を指定するように推奨される(どうなるのかよくわからない)。
設定ファイルの作成
spaCyの訓練では,コマンドに設定を書くのではなく,設定ファイルに設定を書くことになっている(その方が後から分かりやすいから)。設定ファイルは,ここで簡単に作れる。これに入出力を若干書き足す。今回はNERのみなので,以下のようになった(GPUありにしている(GPUだから速いということは無いが,BERTを使っているようなので精度は良いかも))。
# 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 = "turku-ner-corpus/data/conll/converted/train.spacy" # ←ここを追加
dev = "turku-ner-corpus/data/conll/converted/dev.spacy" # ←ここを追加
vectors = "spacy_fi_experimental_web_md" # ←なければ空欄でも動くっぽい。今回は先述のフィンランド語のspaCyモデルを指定
[system]
gpu_allocator = "pytorch"
[nlp]
lang = "fi"
pipeline = ["transformer","ner"]
batch_size = 128
[components]
[components.transformer]
factory = "transformer"
[components.transformer.model]
@architectures = "spacy-transformers.TransformerModel.v1"
name = "TurkuNLP/bert-base-finnish-cased-v1"
tokenizer_config = {"use_fast": true}
[components.transformer.model.get_spans]
@span_getters = "spacy-transformers.strided_spans.v1"
window = 128
stride = 96
[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 = false
nO = null
[components.ner.model.tok2vec]
@architectures = "spacy-transformers.TransformerListener.v1"
grad_factor = 1.0
[components.ner.model.tok2vec.pooling]
@layers = "reduce_mean.v1"
[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]
accumulate_gradient = 3
dev_corpus = "corpora.dev"
train_corpus = "corpora.train"
[training.optimizer]
@optimizers = "Adam.v1"
[training.optimizer.learn_rate]
@schedules = "warmup_linear.v1"
warmup_steps = 250
total_steps = 20000
initial_rate = 5e-5
[training.batcher]
@batchers = "spacy.batch_by_padded.v1"
discard_oversize = true
size = 2000
buffer = 256
[initialize]
vectors = ${paths.vectors}
この設定ファイルは,いくつか項目を省略している(デフォルト値があるため)。しかし,spaCyの訓練用設定ファイルでは,デフォルト値が決まっていても省略が許されない(その方が後から分かりやすいので)。そこで,省略された部分を補う機能が提供されている。
$ python -m spacy init fill-config <上述の設定ファイル> <出力する設定ファイル>
学習させる
以下のコマンドで学習が開始される。
GPUを使用
python -m spacy train <設定ファイル> --output <出力先ディレクトリ> --gpu-id 0
※GPUのIDは必要に応じて変更する
GPUを使う場合はGPU対応版のspaCyを入れておく必要がある(pip install spacy[cuda]
などとする)。また,内部ではtransformersを使うので,pytorch
とtransformers
は必須である。
CPUを使用
python -m spacy train <設定ファイル> --output <出力先ディレクトリ>
できあがったモデルを読み込む
--output
で指定したディレクトリの内部に,model-best
とmodel-last
という2つのディレクトリが作られる。このいずれもがspaCyのモデルである。これを使用するためには,以下のようにする。
import spacy
nlp=spacy.load('foobar/model-last')
できあがったモデルはNERの訓練しかしていないのでNERしかできない。これはこれで不便で,なんとかならないものか・・・