Universal Sentence Encoderは、文をベクトル化する手法です。
Googleの研究者達が開発したもので、2018年にTensorflow Hubで公開されました。
多言語に対応しているところが特徴で、日本語と英語で同じ意味なら、ほぼ同じベクトルに変換してくれます。
また、文中の単語の意味や語順を考慮した文章ベクトルを、ニューラルネットワークによるend-to-endな学習で獲得できるので、意味を解釈したベクトルに変換可能です。
関連記事:Python(gensim)と日本語Word2Vecで単語ベクトル可視化
また、文中の単語の意味や語順を考慮した文章ベクトルを、ニューラルネットワークによるend-to-endな学習で獲得できるので、意味を解釈したベクトルに変換可能です。
関連記事:Python(gensim)と日本語Word2Vecで単語ベクトル可視化
Universal Sentence Encoderの使い方
tensorflow_hubにある学習済みモデルを使うと、とても簡単にテキストデータを512次元の文章ベクトルに変換できます。text = ["今日はいい天気だな"]
import tensorflow_hub as hub import numpy as np import tensorflow_text #テキストを文章ベクトルに変換 embed = hub.load("https://tfhub.dev/google/universal-sentence-encoder-multilingual/3") embeddings = embed(text) print(embeddings)
日本語を文章ベクトルに変換できました。非常に簡単です。
Universal Sentence Encoderの文書分類モデル
Universal Sentence Encoderで分類モデルを作成します。テキストデータの準備
株式会社ロンウイット様のライブドアニュースのデータセットを利用します。前処理は、以下の記事を参考にさせて頂きました。
参考記事:【実装解説】日本語版BERTでlivedoorニュース分類:Google Colaboratoryで(PyTorch)
Universal Sentence Encoderで文書ベクトル化
TensorFlow HubにあるUSEの学習済みモデルの中で、universal-sentence-encoder-multilingualを利用しました。large版より軽くて、少量データでもうまくいきやすいので便利です。
なお、データ件数が多いとUSEは少し時間がかかるので、データセットを200件に絞り込みました。
なお、データ件数が多いとUSEは少し時間がかかるので、データセットを200件に絞り込みました。
import tensorflow as tf import tensorflow_hub as hub import tensorflow_text import numpy as np import pandas as pd df = pd.read_csv('livedoor_data_all.csv', encoding='utf-8') df = df.iloc[850:1150,:] text_df = df.iloc[:,1].values y = df.iloc[:,2] text_list = text_df.tolist() # 学習済みモデルの読み込み #embed = hub.load("https://tfhub.dev/google/universal-sentence-encoder-multilingual-large/3") embed = hub.load("https://tfhub.dev/google/universal-sentence-encoder-multilingual/3") embeddings = embed(text_list) # numpy配列に変換 embeddings =embeddings.numpy()
なお、tensorflow_textのimportでエラーが起きたときは、tensorflowとのバージョンがずれているケースが多いです。バージョン合わせるとエラーが解消されます。
ランダムフォレストで分類モデル作成
ランダムフォレストで分類モデルを作成します。from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import cross_validate # ランダムフォレストのパラメータ clf = RandomForestClassifier(n_estimators=10) ## Cross-Validation scoring = {"a": "accuracy", "p": "precision_macro", "r": "recall_macro", "f":"f1_macro"} ## Cross-Validation score = cross_validate(clf, embeddings, y, scoring=scoring,cv=2) print('accuracy:', score['test_a'].mean()) print('precision:', score['test_p'].mean()) print('recall:', score['test_r'].mean()) print('f1:', score['test_f'].mean())
精度は以下になりました。なかなか良いですね。
accuracy: 0.9633333333333334
precision: 0.9810344827586207
recall: 0.7386363636363636
f1: 0.8132490116135409
実験:Bag-of-Wordsとの分類精度比較
USEの性能を確認するため、Bag-of-Wordsと分類精度を比較してみます。形態素解析
MeCabで形態素解析します。文を単語に分割し、「名詞、形容詞、動詞」のみを抽出します。import numpy as np import pandas as pd import MeCab from gensim import corpora, matutils df = pd.read_csv('livedoor_data_all.csv', encoding='utf-8') df = df.iloc[850:1150,:] text_df = df.iloc[:,1].values y = df.iloc[:,2] # ChaSen 互換形式 mecab = MeCab.Tagger("-Ochasen") #形態素解析 def ChaSen(text): word_l = [] res = mecab.parse(text) #構文解析 words = res.split('\n')[:-2] # 最後にEOSが入るためそれ以外を取得 for word in words: pos = word.split('\t') # タブで各行を切り分け if '名詞'or'形容詞'or'動詞' in pos[3]: #品詞がある4番目にアクセス word_l.append(pos[2]) # 原型を取得 return word_l # 単語に分割したリスト作成 word_list = [] for text in text_df: b = ChaSen(text) word_list.append(b) print(word_list)
Bag-of-Wordsの文書ベクトル作成
gensimでBag-of-Words形式に変換します。#gensimでbowに変換 dictionary = corpora.Dictionary(word_list) n_word = len(dictionary) x = [] for i in word_list: bow_id = dictionary.doc2bow(i) bow = matutils.corpus2dense([bow_id], n_word).T[0] x.append(bow) x = np.array(x, 'f') print(x.shape) x_pd = pd.DataFrame(x)
TF-IDF変換
TF-IDFに変換します。# TF-IDF
from sklearn.feature_extraction import text tfidf = text.TfidfTransformer(norm=None) #帰ってくるのはスパースマトリックス res = tfidf.fit_transform(x_pd) x_pd_TFIDF = pd.DataFrame(res.toarray(), columns=x_pd.columns)
主成分分析
主成分分析で2次元に次元削減します。# PCA from sklearn import decomposition pca = decomposition.PCA(n_components=100) x_2 = pca.fit_transform(x_pd_TFIDF) x_2 = pd.DataFrame(x_2)
ランダムフォレストで分類モデル作成
ランダムフォレストで分類モデルを作成します。from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_validate
# ランダムフォレストのパラメータ
clf = RandomForestClassifier(n_estimators=10)
scoring = {"a": "accuracy",
"p": "precision_macro",
"r": "recall_macro",
"f":"f1_macro"}
## Cross-Validation
score = cross_validate(clf, x_2, y, scoring=scoring,cv=3)
print('accuracy:', score['test_a'].mean())
print('precision:', score['test_p'].mean())
print('recall:', score['test_r'].mean())
print('f1:', score['test_f'].mean())
精度は以下になりました。
accuracy: 0.9533333333333333
accuracy: 0.9533333333333333
precision: 0.8626577604726101
recall: 0.7107014848950333
f1: 0.7570604649807056
やはりbag-of-wordsは、USEよりやや下回る精度でした。
やはりbag-of-wordsは、USEよりやや下回る精度でした。
関連記事:自然言語処理の分散表現(Word2Vec,fastText)の課題