🔎

機械学習の知識不要。SentenceTransformer で検索システムを作成してみる

に公開

以下の条件を満たす検索機能を SentenceTransformer[1] で作成しました。

  • 機械学習モデルの構築は行わない
  • コード量を最小限にしたい
  • コストをかけずに運用したい
  • CPU のみで処理したい
  • データソースに新しいデータが追加されても対応できる

SentenceTransformer

SentenceTransformer[1] は embedding を計算できます。

[1] sentence-transformers - https://github.com/UKPLab/sentence-transformers

Embeddingとは

Embedding とは、言葉や画像などのデータを数値のベクトル(数字の並び)に変換したものになります。例えば「犬」という単語を、[0.2, 0.8, 0.3, ...]のような数百次元の数値リストで表現します。この数値表現によって、コンピュータが言葉を計算できるようになります。

検索機能の実装では、データソース(captions) での embding と、検索キーワードの embding とのコサイン類似度(cosine similarity)が近いものが類似度が高い順に検索の結果として出力します。

実装

今回は、["今日は和食","簡単パスタ","スイーツ作り"]の3つのデータを、検索キーワードである"簡単和食レシピ"に類似度が高い順で検索結果を常時します。

利用するモデルは、all-MiniLM-L6-v2[2] です。
このモデルでは文章や段落を384次元のベクトル空間にマッピングします。
イメージとしては、X軸・Y軸のような軸が384本ある空間上に文章を配置する感じです。

[2]sentence-transformers/all-MiniLM-L6-v2 - https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2

from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

# モデルロード
model = SentenceTransformer('all-MiniLM-L6-v2')

# Instagramキャプション
captions = [
    "今日は和食",
    "簡単パスタ",
    "スイーツ作り"
]

# キャプションベクトル化
caption_embeddings = model.encode(captions, show_progress_bar=True)

# 検索キーワード
query = "簡単和食レシピ"
query_embedding = model.encode([query])

# 類似度計算
similarity = cosine_similarity(query_embedding, caption_embeddings)

# 上位5件
top_indices = np.argsort(similarity[0])[::-1][:5]
for i in top_indices:
    print(f"{captions[i]} - 類似度: {similarity[0][i]:.3f}")

結果

今日は和食 - 類似度: 0.716
スイーツ作り - 類似度: 0.501
簡単パスタ - 類似度: 0.432

「簡単パスタ」はキーワード「簡単和食レシピ」と語彙的に似ていますが、all-MiniLM-L6-v2 モデルでは「スイーツ作り」が2番目に来ました。
同じ単語が含まれていることは必ずしもスコアに強く影響しないようです。
モデルの説明[2]にもあるようにが「単語の一致」よりも「文全体の意味的な近さ」を重視しているためだと考えられます。

Discussion