nikkie-ftnextの日記

イベントレポートや読書メモを発信

OpenAIのembedding新モデルのAPIで、英語や日本語テキストからembeddingsやその類似度を計算する

はじめに

スケルツォ見てスッキリ。nikkieです。

OpenAIから2024年1月のアップデートが来ましたね。
その中の目玉と思われるembedding新モデルのAPIで少しだけ手を動かしました

目次

OpenAI embedding新モデルのAPI

「New embedding models with lower pricing」参照。
embeddingの新しいモデル2つが登場しています。

  • text-embedding-3-small
  • text-embedding-3-large

embeddingの既存APIにtext-embedding-ada-002がありましたが、新モデルのどちらも精度向上しています。
多言語における検索のベンチマークMIRACLと英語タスクのベンチマークMTEB1でembeddingを評価した表を引用。

Eval benchmark ada v2 text-embedding-3-small text-embedding-3-large
MIRACL average 31.4 44.0 54.9
MTEB average 61.0 62.3 64.6

なおOpenAIとしては、text-embedding-ada-002のdeprecation(廃止)は今は考えていないようです。
ですが、新モデルのほうが精度が高く低コストなので、乗り換える方向に進みそうです。

embeddingはテキストの意味を表すベクトルですが、精度向上しただけでなく、ベクトルの長さ(dimensions)を指定できるようになったとのこと!

For example, on the MTEB benchmark, a text-embedding-3-large embedding can be shortened to a size of 256 while still outperforming an unshortened text-embedding-ada-002 embedding with a size of 1536.

なんでも、text-embedding-3-largeのembeddingは、デフォルトの3072次元でtext-embedding-ada-002をMTEBのスコアで上回る(64.6 > 61.0)のは先に見たとおりですが、256次元に短縮してもtext-embedding-ada-002を上回る(62.0 > 61.0)そうです

既存のAPIと比べて安くうまくなったわけで、これは素振りしたくなりますね。

APIでembeddingを得て、テキストの類似度計算

以前sentence-transformersで手を動かしたのをなぞって、APIでembedidngを得てから類似度を求めます。

今回はAPI呼び出しだけで済んじゃうんですね!
なおお金は少額ですがかかります(ただし1ドルもいきません)

ライブラリのバージョン

annotated-types==0.6.0
anyio==4.2.0
certifi==2023.11.17
distro==1.9.0
h11==0.14.0
httpcore==1.0.2
httpx==0.26.0
idna==3.6
numpy==1.26.3
openai==1.10.0
pydantic==2.5.3
pydantic_core==2.14.6
sniffio==1.3.0
tqdm==4.66.1
typing_extensions==4.9.0

英語の例(text-embedding-3-small)

以下を参考にして、APIを介してembeddingを得るスクリプトを書きました。

OpenAIのAPIから返るembedding(ベクトル)は、長さが1になるように正規化されている2ので、embeddingどうしの内積(dot product)がコサイン類似度となります

>>> np.dot(embeddings[0], embeddings[0])  # 1文目自身は1文目と類似度1
1.0000001104418899
>>> np.dot(embeddings[0], embeddings[1])
0.363144529288284
>>> np.dot(embeddings[0], embeddings[2])  # 1文目と3文目は類似度が小さいです(最小は-1ですが)
0.029553639372359004

日本語の例(text-embedding-3-small)

文: 今日は雨降らなくてよかった
類似文: 今日は良いお天気ですね
類似度: [0.15914484 0.16386892 0.24410782 0.65602571 0.30940887]
文: ハンバーガーは好きですか?
類似文: 好きな食べ物は何ですか?
類似度: [0.42248486 0.16168734 0.05642641 0.15871578 0.08902706]

sentence-transformersの素振り記事で試したモデルと比べると、どちらの例も1つだけスコアが高くなっていてすごいなと思います。
誤回答の余地がないので、embeddingがよくできていると感じました。

text-embedding-3-large(日本語)

モデルの指定を変更します。

- model_name = "text-embedding-3-small"
+ model_name = "text-embedding-3-large"
文: 今日は雨降らなくてよかった
類似文: 今日は良いお天気ですね
類似度: [0.11441737 0.13935541 0.21728123 0.62243932 0.26052769]
文: ハンバーガーは好きですか?
類似文: 好きな食べ物は何ですか?
類似度: [0.55978838 0.23029284 0.13640034 0.19007486 0.17140786]

text-embedding-3-large(日本語)でdimensionsを指定する

API呼び出しにdimensions引数の指定を追加します。

def get_embedding(text, model):
-     response = client.embeddings.create(input=text, model=model)
+     response = client.embeddings.create(input=text, model=model, dimensions=256)
文: 今日は雨降らなくてよかった
類似文: 今日は良いお天気ですね
類似度: [0.05933593 0.15390326 0.31828702 0.63382458 0.26526732]
文: ハンバーガーは好きですか?
類似文: 好きな食べ物は何ですか?
類似度: [0.65567454 0.25886909 0.12645944 0.21691509 0.17720161]

3072次元から256次元までベクトルを小さくした(表現できる情報を絞った)のに、全然変わらないように映ります。すごい!

積ん読資料たち

(1) Embeddings Guide
https://platform.openai.com/docs/guides/embeddings
Cookbookへのリンクもあり、コード込みでユースケースが掴めそうです。
気になるところ

  • Classification using the embedding features
  • Zero-shot classification

(2) 日本語のベンチマークで評価した例

終わりに

OpenAIからembeddingの新モデルのAPIがリリースされました。
過去にsentence-transformersで素振りしたときと同じトイデータで触った範囲では、たしかに性能が良さそうなembeddingです。

たくさんのテキストをembeddingにするときは、openaiライブラリがサポートしている並行処理によるリクエストが有効だと思います(今後の素振り材料)


  1. StudyCoさんの勉強会で聞いたやつだ〜!
  2. OpenAI embeddings are normalized to length 1」ref: https://platform.openai.com/docs/guides/embeddings/which-distance-function-should-i-use