Sentence Transformersによる文埋め込み
「Word2Vecは単語レベルの表現だった。でも我々が必要なのは、問い合わせ文全体の意味を捉えたベクトルだ。」
田中VPoEが2つの問い合わせを並べる。
「『荷物が届きません』と『注文した商品がまだ来ていない』は同じ意味だ。Sentence Transformersならこれを正しく近いベクトルにマッピングできる。」
Sentence Transformersとは
文全体を1つの密なベクトル(通常384〜768次元)に変換するモデル。BERTをベースに、文のペアで学習することで高品質な文埋め込みを実現する。
Word2Vecの平均プーリング vs Sentence Transformers
# Word2Vecの平均プーリング: 単語ベクトルの平均
# → 「犬が猫を追う」と「猫が犬を追う」が同じベクトルに
# → 文全体の意味を適切に表現できない
# Sentence Transformers: 文全体を直接ベクトル化
# → 文の構造と意味を考慮した表現
# → 類似文は近いベクトル、異なる文は遠いベクトル
基本的な使い方
from sentence_transformers import SentenceTransformer
import numpy as np
# モデルのロード
model = SentenceTransformer('all-MiniLM-L6-v2') # 英語用
# model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2') # 多言語対応
# 文埋め込みの生成
sentences = [
"My order hasn't arrived yet",
"The package I ordered still hasn't come",
"I want to return this product",
"How do I get a refund",
]
embeddings = model.encode(sentences)
print(f"埋め込みの形状: {embeddings.shape}")
# 出力: 埋め込みの形状: (4, 384)
# コサイン類似度の計算
from sklearn.metrics.pairwise import cosine_similarity
sim_matrix = cosine_similarity(embeddings)
print("類似度行列:")
for i, s1 in enumerate(sentences):
for j, s2 in enumerate(sentences):
if i < j:
print(f" '{s1[:30]}' vs '{s2[:30]}': {sim_matrix[i][j]:.4f}")
カスタマーサポートへの応用
類似問い合わせ検索
from sentence_transformers import SentenceTransformer, util
import torch
model = SentenceTransformer('all-MiniLM-L6-v2')
# 過去の問い合わせデータベース
knowledge_base = [
{"text": "Order not delivered after 5 days", "category": "配送", "response": "配送状況を確認いたします..."},
{"text": "Product arrived damaged", "category": "クレーム", "response": "大変申し訳ございません..."},
{"text": "How to return an item", "category": "返品", "response": "返品手続きの流れをご案内します..."},
{"text": "Wrong item received", "category": "返品", "response": "誤配送のお詫びと交換手続き..."},
{"text": "Payment charged twice", "category": "決済", "response": "二重請求の確認と返金処理..."},
]
# ナレッジベースのベクトル化(事前計算)
kb_texts = [item["text"] for item in knowledge_base]
kb_embeddings = model.encode(kb_texts, convert_to_tensor=True)
def find_similar_inquiries(query, top_k=3):
"""類似する過去の問い合わせを検索"""
query_embedding = model.encode(query, convert_to_tensor=True)
scores = util.cos_sim(query_embedding, kb_embeddings)[0]
top_indices = torch.topk(scores, k=top_k).indices
results = []
for idx in top_indices:
results.append({
"text": knowledge_base[idx]["text"],
"category": knowledge_base[idx]["category"],
"response": knowledge_base[idx]["response"],
"similarity": scores[idx].item(),
})
return results
# 検索例
query = "My package hasn't been delivered"
results = find_similar_inquiries(query)
for r in results:
print(f" 類似度: {r['similarity']:.4f} | カテゴリ: {r['category']} | {r['text']}")
バッチ処理による高速化
# 大量のテキストを効率的にベクトル化
import time
texts = ["Sample inquiry " + str(i) for i in range(1000)]
start = time.time()
embeddings = model.encode(
texts,
batch_size=64, # バッチサイズ
show_progress_bar=True, # 進捗表示
normalize_embeddings=True, # L2正規化(コサイン類似度の高速化)
)
elapsed = time.time() - start
print(f"1000件のベクトル化: {elapsed:.2f}秒")
特徴抽出手法の比較
from sklearn.feature_extraction.text import TfidfVectorizer
from sentence_transformers import SentenceTransformer
import numpy as np
# テストデータ
pairs = [
("My order hasn't arrived", "The package I ordered is missing"),
("I want to return this", "How do I send this product back"),
("My order hasn't arrived", "I want to return this"),
]
# TF-IDF
tfidf = TfidfVectorizer()
all_texts = [t for pair in pairs for t in pair]
tfidf_vecs = tfidf.fit_transform(all_texts)
# Sentence Transformers
st_model = SentenceTransformer('all-MiniLM-L6-v2')
st_vecs = st_model.encode(all_texts)
print("手法別の類似度比較:")
for i, (t1, t2) in enumerate(pairs):
idx1, idx2 = i * 2, i * 2 + 1
# TF-IDF類似度
tfidf_sim = cosine_similarity(
tfidf_vecs[idx1:idx1+1], tfidf_vecs[idx2:idx2+1]
)[0][0]
# Sentence Transformers類似度
st_sim = cosine_similarity(
st_vecs[idx1:idx1+1], st_vecs[idx2:idx2+1]
)[0][0]
print(f"\n '{t1}' vs '{t2}'")
print(f" TF-IDF: {tfidf_sim:.4f}")
print(f" Sentence Transformers: {st_sim:.4f}")
# Sentence Transformersは意味的な類似性をより正確に捉える
手法選定ガイド
| 手法 | 精度 | 速度 | メモリ | 適用場面 |
|---|---|---|---|---|
| TF-IDF | 中 | 最速 | 小 | ベースライン、大規模データ |
| Word2Vec平均 | 中〜高 | 速い | 中 | 単語の意味を考慮したい場合 |
| Sentence Transformers | 最高 | 中 | 大 | 意味的類似性が重要な場合 |
まとめ
| 項目 | ポイント |
|---|---|
| Sentence Transformers | 文全体を1つのベクトルに変換 |
| 利点 | 意味的な類似性を正確に捉える |
| 応用 | 類似問い合わせ検索、自動分類 |
| 選定基準 | 精度重視ならST、速度重視ならTF-IDF |
チェックリスト
- Sentence Transformersの仕組みを説明できる
- Word2Vecの平均プーリングとの違いを理解した
- 類似検索の実装方法を理解した
- TF-IDF、Word2Vec、Sentence Transformersの使い分けができる
次のステップへ
テキストの特徴抽出手法を一通り学んだところで、次の演習でこれらの手法をKaggleデータセットに適用してみよう。
推定読了時間: 30分