[技術日誌]モデル別で文章の類似度を判定する
8/9分の技術日誌
モデル別で文章の類似度を判定する
環境構築
Google Colabratryを使用してるので、環境構築は不要です。
SentenceTransformers
下記のコマンドでライブラリをインストールします。
!pip install sentence-transformers
データセットの準備
モデルによっては、全く違う文章でも類似度の最大値が1として0.8を超える数値を算出するものもあります。
全く違う文章の類似度は低く、似た文章の類似度は高く判定するように、数値を差をつけて推定してくれるモデルを選定する必要があります。
よって、文章の類似度算出を検証するにあたって、類似度が異なる文章を用意する必要があります。
本記事では、Yahoo! JAPAN研究所の日本語言語理解ベンチマークJGLUEを用います。
2つの文章の類似度を5段階評価した、ラベル付きのデータです。
下記のサイトを参考に、0.0~1.0で0.1刻みで文章のサンプル抽出します。
import pandas as pd
# データセットの準備
# https://qiita.com/masa_yam/items/4cb31ccb0be6e86af404
# https://github.com/yahoojapan/JGLUE/blob/main/datasets/jsts-v1.1/valid-v1.1.json
df_json = pd.read_json('https://raw.githubusercontent.com/yahoojapan/JGLUE/main/datasets/jsts-v1.1/valid-v1.1.json', lines=True)
df_json.head()
import numpy as np
"""
サンプルを抽出
今回は、label を 1.0 刻みで分割してその中から1件ずつデータを取ります。
後で比較しやすいように label は 0.0 ~ 1.0 の範囲に変換します。
"""
seed = 42
offset = 1.0
df_sample = df_json[df_json['label']==0.0].sample(random_state=seed)
for i in np.arange(0.0, 5.0, offset):
if i==0.0:
df_sample = pd.concat([df_sample, df_json.query(f'{i} < label < {i+offset}').sample(random_state=seed)])
else:
df_sample = pd.concat([df_sample, df_json.query(f'{i} <= label < {i+offset}').sample(random_state=seed)])
df_sample = pd.concat([df_sample, df_json[df_json['label']==5.0].sample(random_state=seed)])
# まったく同じ文章のペアのものも入れておく
df_sample = pd.concat([df_sample, df_json[(df_json['sentence1']==df_json['sentence2']) & (df_json['label']==5.0)].sample(random_state=seed)])
df_sample.drop(['sentence_pair_id', 'yjcaptions_id'], axis=1, inplace=True)
df_sample.reset_index(drop=True, inplace=True)
# 比較しやすいように label を [0, 1] の区間に変換する
df_sample['label'] = df_sample['label'].apply(lambda x: x/5.0)
df_sample = df_sample[1:-1].reset_index(drop=True)
df_sample
類似度の算出
import math
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
from sentence_transformers import SentenceTransformer, util
# 文章類似度モデル
# 下記のリンクからいくつかピックアップ
# https://www.sbert.net/docs/sentence_transformer/pretrained_models.html
# https://huggingface.co/pkshatech/GLuCoSE-base-ja
model_name_list = ['all-MiniLM-L12-v2',
'all-MiniLM-L6-v2',
'all-distilroberta-v1',
'all-mpnet-base-v2',
'distiluse-base-multilingual-cased-v1',
'distiluse-base-multilingual-cased-v2',
'intfloat/multilingual-e5-large',
'multi-qa-MiniLM-L6-cos-v1',
'multi-qa-distilbert-cos-v1',
'multi-qa-mpnet-base-dot-v1',
'paraphrase-MiniLM-L12-v2',
'paraphrase-MiniLM-L3-v2',
'paraphrase-MiniLM-L6-v2',
'paraphrase-albert-small-v2',
'paraphrase-mpnet-base-v2',
'paraphrase-multilingual-MiniLM-L12-v2',
'paraphrase-multilingual-mpnet-base-v2',
'paraphrase-xlm-r-multilingual-v1',
'pkshatech/GLuCoSE-base-ja',
'stsb-xlm-r-multilingual']
for model_name in model_name_list:
# 文章類似度モデル
model_sentence = SentenceTransformer(model_name)
# 相関・コサイン類似度を格納するリスト
cosine_score_list = []
# コサイン類似度を計算
for i in range(len(df_sample)):
# 行のデータを取得
sentence1 = df_sample["sentence1"][i]
sentence2 = df_sample["sentence2"][i]
# 文章をベクトルに変換
embeddings1 = model_sentence.encode(sentence1, convert_to_tensor=True)
embeddings2 = model_sentence.encode(sentence2, convert_to_tensor=True)
# コサイン類似度の計算
cosine_score = util.pytorch_cos_sim(embeddings1, embeddings2)[0][0]
cosine_score = round(float(cosine_score), 4)
cosine_score_list.append(cosine_score)
# データフレームに整形
df_sample[model_name] = cosine_score_list
# 類似度が高いほど青色が濃ゆくなる
display(df_sample.style.background_gradient(axis=None))
ざっとまとめ
下記のモデルがマシそう。
・multi-qa-mpnet-base-dot-v1
・pkshatech/GLuCoSE-base-ja
この記事が気に入ったらサポートをしてみませんか?