概要
OpenAI の text-embedding-3-small,text-embedding-3-large を使い、同じテキストでも 正規化を行うかどうかでベクトルがどの程度変化(ズレるかを)調査しました。
文字列の正規化は当たり前にやっていることですが、結構見逃してしまう(やり忘れ)を防ぐための自分へのメモでもあります。
また、内部でうまくやってくれているのでは?と思ったりする淡い期待も込めての検証です。
検証コード
import re
import numpy as np
import unicodedata
from openai import OpenAI
client = OpenAI()
def normalize_text(s: str):
s = unicodedata.normalize("NFKC", s)
# 0幅<SP>,全角SP
s = re.sub(r"[\u200b\u200c\u200d\ufeff]", "", s)
s = s.replace("\u3000", " ")
s = s.casefold()
s = re.sub(r"\s+", " ", s).strip()
return s
MODEL = "text-embedding-3-small"
# MODEL = "text-embedding-3-large"
def embed(text):
r = client.embeddings.create(model=MODEL, input=text)
v = np.array(r.data[0].embedding)
return v / np.linalg.norm(v)
text1 = "AppleのiPhone17"
text2 = normalize_text(text1)
v1 = embed(text1)
v2 = embed(text2)
# ベクトルがどれだけズレているかをチェックする
sim = np.dot(v1, v2)
print(f"text1: {text1}")
print(f"text2: {text2}")
print(f"cosine similarity: {sim:.6f}")
結果
- text-embedding-3-small
text1: AppleのiPhone17
text2: appleのiphone17
cosine similarity: 0.921472
- text-embedding-3-large
text1: AppleのiPhone17
text2: appleのiphone17
cosine similarity: 0.952069
サンプルとして正規化の有無の差が結構ある(文字列で2箇所)あるんですが、それぞれsmallで7%, largeで4% ほどズレてしまっているので、必要に応じて正規化は実施したほうがよいと思います。
OpenAIとしては、そこまで踏み込んだ正規化は実施してないですね。(当たり前といえば、当たり前か)
まとめ
- OpenAIのembeddingsはある程度表記ゆれに頑健だが、大文字・小文字/全角・半角の違いで最大5〜7%程度ズレることがある。
- 再現性・安定性を重視する場合は、正規化したほうがよい。