chiVeの活用方法シリーズ
- Part 1 「分散表現とは?chiVeとは?」
- Part 2 「chiVeでできること(単語ベクトルの性質)」
- Part 3 「chiVeでできること(単語ベクトルで文書分類)」
- Part 4 「chiVeの追加学習」(本記事)
はじめに
2022年4月末に、WAP NLP Tech Talk#5 にて、「単語分散表現 chiVeの活用方法」というタイトルでお話しをしました。
そのQiita版として、スライド の内容を補足しながら4回に分けて紹介しています。
chiVe とは、日本語単語分散表現です。分散表現の基本事項や、chiVe の特長については、Part 1 で触れています。
さて、前回は公開済みの chiVe を使って文書分類をしました。今回は chiVe を追加学習し、前回と同じ分類タスクで結果を比較します。
追加学習
公開されている chiVe は汎用的なデータセットで学習済み1ですので、そのままでも利用できますが、手持ちのデータで追加学習させることによって、自分専用のドメイン(分野)に特化させることができます。
例えば、ニュースの分類タスクに専用で使う場合は、ニュースドメインのコーパスで追加学習させることで、より性能が高くなる可能性があります。
実験
今回も Livedoor ニュースコーパス でテキスト分類をします。
前回のコードの続きで進めます。
本記事から進めるには
前回の「データセットの準備 」節を適用してから次のコードを実行してください。import gensim
import numpy as np
import sudachipy
import sudachidict_core
from sklearn.metrics import accuracy_score
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import make_pipeline, Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
tokenizer = sudachipy.Dictionary().create()
def tokenize(sent: str) -> list[str]:
morphs = tokenizer.tokenize(sent.strip())
norms = [m.normalized_form() for m in morphs]
return norms
def text2vec(text: str, vectorizer):
norms = tokenize(text)
word_vecs = np.array([vectorizer[n] for n in norms if n in vectorizer])
text_vec = np.average(vecs, axis=0)
return vec
def classify(train_x, train_y, test_x, test_y):
param_grid = {
'svc__C': [1, 10, 100, 1000],
'svc__gamma': [1e-4, 5e-4, 1e-3],
}
clf = make_pipeline(StandardScaler(), SVC(random_state=0))
search = GridSearchCV(clf, param_grid, verbose=3)
search.fit(train_x, train_y)
best_model = search.best_estimator_
predicted = best_model.predict(test_x)
accuracy = accuracy_score(test_y, predicted)
print('accuracy = {:.4f}'.format(accuracy))
フルモデルのダウンロード
chiVe の追加学習を行うには、フルモデルを使う必要があります。
$ wget https://sudachi.s3-ap-northeast-1.amazonaws.com/chive/chive-1.2-mc90_gensim-full.tar.gz
$ tar xzf chive-1.2-mc90_gensim-full.tar.gz
chiVe の追加学習
from gensim.models import Word2Vec
# chiVe を追加学習するメソッド
def finetuning(output_chive_path: str, train_texts):
chive_finetuned = Word2Vec.load("data/chive-1.2-mc90_gensim-full/chive-1.2-mc90.bin")
# 実験の再現性のため(並列処理すると実験が再現できない)
chive_finetuned.workers = 1
# 語彙の再構築
chive_finetuned.build_vocab(train_texts, update=True)
# 追加学習で使用するデータセットは小規模なので、min_count を小さくしておく
chive_finetuned.vocabulary.min_count = 0
# 学習、保存
chive_finetuned.train(train_texts, total_examples=chive_finetuned.corpus_count,
epochs=chive_finetuned.epochs)
chive_finetuned.save(output_chive_path)
Livedoor ニュースコーパスの学習用データでchiVeを学習します。
# 学習用データを単語分割
train_toked = [tokenize(line) for article in train_df['article']
for line in article.split('\n')]
# 追加学習した chiVe の保存先
output_chive_path='data/chive-1.2-mc90.livedoor.finetuned.bin'
# 追加学習
finetuning(output_chive_path, train_toked)
学習が終わると、次の3つのファイルが生成されているはずです。
$ ls
# >>> chive-1.2-mc90.livedoor.finetuned.bin
# chive-1.2-mc90.livedoor.finetuned.bin.trainables.syn1neg.npy
# chive-1.2-mc90.livedoor.finetuned.bin.wv.vectors.npy
これで、Livedoor ニュースコーパスに特化した chiVe が得られました。
追加学習した chiVe を使って分類
前回と同じデータセットで分類タスクの性能を確認します。
# 追加学習した chiVe の読み込み
chive_finetuned = Word2Vec.load('data/chive-1.2-mc90.livedoor.finetuned.bin')
# vectorizer=chive_finetuned.wv を指定して、ベクトル化
train_x = np.array([text2vec(article, vectorizer=chive_finetuned.wv)
for article in train_df["article"]])
train_y = np.array(train_df["label_id"])
test_x = np.array([text2vec(article, vectorizer=chive_finetuned.wv)
for article in test_df["article"]])
test_y = np.array(test_df["label_id"])
# 学習、評価
classify(train_x, train_y, test_x, test_y)
# >>> accuracy = 0.9227
前回の正解率 91.32% に比べて、改善できたようです。
他のデータセットで追加学習
chiVe の性能改善にはデータセットの選択が大切です。ニュース記事とは別のデータで chiVe を追加学習し、同じ分類タスク(ニュース分類)の性能が改善するか調べます。
別のデータセットとして、Twitter のツイート文を使ってみましょう。ツイート文は、ニュース記事に比べてカジュアルな表現が多く、同じ日本語ですが性質が全く異なります。
Twitterのデータセットとして、WRIMEを使います。
$ wget https://raw.githubusercontent.com/ids-cv/wrime/master/wrime-ver1.tsv
import pandas as pd
# データを読み込んで、単語分割
wrime_df = pd.read_csv('data/wrime/wrime-ver1.tsv', delimiter='\t')
train_toked = [tokenize(line) for tweet in wrime_df['Sentence'] for line in tweet.split('\n')]
# chiVe の追加学習
finetuning('data/chive-1.2-mc90.wrime.finetuned.bin', train_toked)
chive_finetuned_wrime = Word2Vec.load('data/chive-1.2-mc90.wrime.finetuned.bin')
# ベクトル化
train_x = np.array([text2vec(article, vectorizer=chive_finetuned_wrime.wv)
for article in train_df["article"]])
train_y = np.array(train_df["label_id"])
test_x = np.array([text2vec(article, vectorizer=chive_finetuned_wrime.wv)
for article in test_df["article"]])
test_y = np.array(test_df["label_id"])
# 分類
classify(train_x, train_y, test_x, test_y)
# >>> accuracy = 0.9091
追加学習をしなかった場合の正解率 91.32% に比べて、性能が下がってしまったようです。
このように、追加学習を行う時には、適切なデータセットの選択が必要です。
まとめ
今回は chiVe の追加学習について触れました。
Livedoor ニュースコーパスの分類実験の結果は次の通りでした。
分類手法 | 正解率 |
---|---|
chiVe(追加学習なし) + SVM | 0.9132 |
chiVe(Livedoorで追加学習) + SVM | 0.9227 |
chiVe(ツイート文で追加学習) + SVM | 0.9091 |
同じドメインのデータセットで追加学習する手法(Livedoorで追加学習)が最も良い結果になりましたが、別のドメインのデータセットを使う手法(ツイート文で追加学習)は、改善が見られませんでした。
chiVe を追加学習する際には、応用先に合わせたデータセットをご検討ください。
さて、「単語分散表現 chiVe の活用方法」シリーズは今回が最後です。
ぜひ紹介した内容を応用して chiVe を使ってみてください。