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)の課題