Taste of Tech Topics

Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

GiNZAの単語分散表現にchiVeを使って精度向上のお試し

こんにちは。最近シェアハウスのネットワークをIPv6に切り替えたら快適になった@Ssk1029Takashiです。

最近は学習済み単語分散表現が日本語でも充実してきており、語彙の多いもの・ドメインに特化しているものなど選択肢の幅が広がってきています。
日本語処理フレームワークであるGiNZAからもデフォルトで単語分散表現が使用可能です。
今回はワークスアプリケーションさんが作成しているchiVeという学習済み単語分散表現を使って、機械学習の精度を向上できるかを見てみます。

はじめに

単語分散表現とは単語に対して、ベクトルを埋め込む技術で、Word2Vecなどが代表的です。
すでに学習されている分散表現を使用することで、機械学習モデルを作らなくても、近しい単語の検索・文書分類などが可能になります。
例えば、単語分散表現を使用することで「令和」という単語から「平成」という単語が近しい意味であると検索出来たりします。

しかし、単語分散表現を使うときの課題としては、未知語への対応があります。
単語をベクトルに変換するとき、事前学習したモデルが知らない単語はベクトルに変換できないため、精度が落ちてしまうことがあります。
GiNZAにはデフォルトで使用できる単語分散表現モデルがあるのですが、新語への対応に弱い部分があり、例えば「令和」がベクトルに変換できないなどがあります。

しかし、ワークスアプリケーションさんが作成しているchiVeという単語分散表現であれば、新語なども学習されているので、より精度の高い結果が期待できます。
実際に学習している単語の語彙数でも、GiNZAのデフォルトのモデルが、約12万語なのに対して、chiVeは最大360万語となっているので、カバーしている単語の範囲もよりchiVeのほうが広くなっています。

f:id:acro-engineer:20200603075346p:plain

なので、今回はGiNZAの学習済み単語分散表現をchiVeに差し替えて、機械学習の精度が向上するのか試してみます。

GiNZAとは

GiNZAについての詳細な説明は過去の記事に記載しているので、参照してください。
acro-engineer.hatenablog.com

chiVeとは

chiVeとは形態素解析器のSudachiを開発しているワークスアプリケーションさんが作成した、学習済み単語分散表現です。
github.com

以下のような特徴があります。
1. Skip-gramアルゴリズムを元に、word2vec (gensim) を使用して構築した単語分散表現。
2. 約1億のウェブページ文章を含む国立国語研究所の日本語ウェブコーパス(NWJC)から、Sudachiで分かち書きして学習している。
3. Sudachiの短・中・長単位の3つの分割単位の形態素で学習している。

上でも書きましたが、豊富な語彙数が収録されており、最大で約360万語の語彙数を持ったモデルがあります。
GiNZAがデフォルトで使用しているモデルが約12万語のモデルなので、比較すると語彙数の多さがわかりますね。

GiNZAから学習済み単語分散表現を使用する

GiNZAはspacyベースのため、vector属性から学習済み分散表現を参照できます。

import spacy

nlp = spacy.load('ja_ginza')
doc = nlp("平成の次は令和です。")
for sent in doc.sents:
    for token in sent:
        print(token.vector) #単語のベクトルを参照

また、文書や文章単位でもvector属性を参照することが可能で、その場合は、各単語のベクトルを加算平均した値になります。

nlp = spacy.load('ja_ginza')
doc = nlp("平成の次は令和です。")
print(doc.vector) #文書のベクトルを参照

文書のベクトルを簡易的に扱いたいときでも、vector属性から簡単に参照できるので便利ですね。

GiNZAからchiVeの分散表現を使用する

GiNZAからWord2Vecの形式で保存されているchiVeの分散表現モデルを読み込むことで、chiVeを使用できるようにします。
今回は、約310万語収録されている、v1.1 mc5版のモデルを使用しています。

from gensim.models import KeyedVectors

chive_vectors = KeyedVectors.load_word2vec_format('./chive-1.1-mc5-20200318.txt', binary=False) #モデル読み込み
#ベクトル入れ替え
nlp.vocab.reset_vectors(width=chive_vectors.vectors.shape[1])
for word in chive_vectors.vocab.keys():
    nlp.vocab[word]
    nlp.vocab.set_vector(word, chive_vectors[word])

実際に語彙数が増えたのか確認すると、310万x100次元のベクトルが読み込まれています。

nlp.vocab.vectors.shape

(3572384, 300)

クラス分類の精度が向上するか試してみる

単語分散表現の有効性を示すためには、文書分類でどれくらい結果が向上するかがわかりやすいです。
livedoorニュースコーパスというデータセット、ニュース記事とその記事のジャンルがそろっているので、そちらを使って文書分類を学習してみます。

データセット・手法は以下のようになります。

データセット livedoorニュースコーパス
手法 単語ベクトルの加算平均+ランダムフォレスト

まずは学習用にデータを作成します。

import pandas as pd
from sklearn.model_selection import train_test_split
import numpy as np

def parse_doc(sentence):
  sentence = re.sub(r'https?\S+\n', " ", sentence)
  # 解析のノイズになる特殊文字を削除する
  sentence = re.sub(r'[\._-―─!@#$%^&\-‐|\\*\“()_■×+α※÷⇒—●★☆〇◎◆▼◇△□(:〜~+==)/*&^%$#@!~`){}[]…\[\]\"\'\”\’:;<>?<>〔〕〈〉?、。・,\./『』【】「」→←○《》≪≫\n\u3000]+', "", sentence)
  return sentence


df = pd.read_csv("./text/livedoor.tsv", delimiter="\t")
df["article"] = df["article"].apply(parse_doc)

X = []
y = df["category"]

with nlp.disable_pipes(["ner", "parser"]):
  for article in df["article"].tolist():
    doc = nlp(article)
    X.append(doc.vector)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

次に、学習して、精度を確かめてみます。

from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.metrics import classification_report

rfc = RandomForestClassifier()
rfc.fit(X_train, y_train)
y_pred = rfc.predict(X_test)
print(classification_report(y_test, y_pred))

GiNZAのデフォルトの分散表現で学習した結果は以下になります。

                precision    recall  f1-score   support

dokujo-tsushin       0.83      0.84      0.83       185
  it-life-hack       0.81      0.70      0.75       200
 kaden-channel       0.71      0.73      0.72       177
livedoor-homme       0.77      0.62      0.69        90
   movie-enter       0.81      0.95      0.87       163
        peachy       0.75      0.70      0.72       170
          smax       0.85      0.86      0.86       154
  sports-watch       0.90      0.95      0.92       180
    topic-news       0.75      0.77      0.76       155

      accuracy                           0.80      1474
     macro avg       0.80      0.79      0.79      1474
  weighted avg       0.80      0.80      0.80      1474

これが、chiVeを使用すると、以下の結果になります。

                precision    recall  f1-score   support

dokujo-tsushin       0.77      0.83      0.80       180
  it-life-hack       0.82      0.75      0.78       161
 kaden-channel       0.81      0.79      0.80       187
livedoor-homme       0.87      0.54      0.67        96
   movie-enter       0.81      0.95      0.88       177
        peachy       0.76      0.76      0.76       181
          smax       0.92      0.88      0.90       168
  sports-watch       0.90      0.94      0.92       171
    topic-news       0.78      0.82      0.80       153

      accuracy                           0.82      1474
     macro avg       0.83      0.81      0.81      1474
  weighted avg       0.82      0.82      0.82      1474

結果としてはF1値が0.80から0.82と0.02ポイントの精度向上ができました。
語彙数が増えた分、精度は向上できました。

まとめ

今回は、ワークスアプリケーションさんが公開している学習済み単語分散表現のchiVeを紹介して、GiNZAから使用する方法を紹介しました。
学習済み単語分散表現はクラス分類や検索など、多数の使い道があるだけに、モデル自体の語彙数が重要になってきます。
chiVeは語彙数が豊富で、使いたい場面も多そうです。
それではまた。

Acroquest Technologyでは、キャリア採用を行っています。


  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
Kaggle Masterと働きたい尖ったエンジニアWanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com