OpenAI platform 1.x : 機能 : 埋め込み (ユースケース) (翻訳/解説)
翻訳 : クラスキャット セールスインフォメーション
作成日時 : 11/21/2023 (v1.2.4)
* 本ページは、以下のドキュメントを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
OpenAI platform 1.x : 機能 : 埋め込み (ユースケース)
ここではいくつかの代表的なユースケースを示します。以下のサンプルに対して Amazon fine-food レビュー・データセット を使用します。
埋め込みの取得
データセットは Amazon ユーザが 2012年10月までに残した合計 568,454 の食品レビューを含みます。例示目的で 1,000 件の最も最近のレビューのサブセットを使用します。レビューは英語で肯定的または否定的である傾向があります。各レビューは ProductId, UserId, スコア, レビュータイトル (Summary) とレビュー本体 (Text) を含みます。例えば :
製品 ID | ユーザ ID | スコア | 要約 | テキスト |
---|---|---|---|---|
B001E4KFG0 | A3SGXH7AUHU8GW | 5 | Good Quality Dog Food | I have bought several of the Vitality canned… |
B00813GRG4 | A1D87F6ZCVE5NK | 1 | Not as Advertised | Product arrived labeled as Jumbo Salted Peanut… |
レビュー要約とレビューテキストを単一の連結テキストに結合します。モデルはこの連結テキストをエンコードして単一のベクトル埋め込みを出力します。
from openai import OpenAI
client = OpenAI()
def get_embedding(text, model="text-embedding-ada-002"):
text = text.replace("\n", " ")
return client.embeddings.create(input = [text], model=model)['data'][0]['embedding']
df['ada_embedding'] = df.combined.apply(lambda x: get_embedding(x, model='text-embedding-ada-002'))
df.to_csv('output/embedded_1k_reviews.csv', index=False)
データをセーブされたファイルからロードするには、以下を実行できます :
import pandas as pd
df = pd.read_csv('output/embedded_1k_reviews.csv')
df['ada_embedding'] = df.ada_embedding.apply(eval).apply(np.array)
2D でのデータ視覚化
埋め込みのサイズは基礎モデルの複雑さにより様々です。この高次元データを視覚化するために、 t-SNE アルゴリズムを使用してデータを 2 次元に変換します。
レビュアーが与えたスター評価に基づいて個々のレビューを色分けします :
- 1-star: 赤
- 2-star: ダークオレンジ
- 3-star: ゴールド
- 4-star: ターコイズ
- 5-star: ダークグリーン
この視覚化はおおよそ 3 つのクラスタを生成したようです、その一つは殆ど否定的なレビューです。
import pandas as pd
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
import matplotlib
df = pd.read_csv('output/embedded_1k_reviews.csv')
matrix = df.ada_embedding.apply(eval).to_list()
# Create a t-SNE model and transform the data
tsne = TSNE(n_components=2, perplexity=15, random_state=42, init='random', learning_rate=200)
vis_dims = tsne.fit_transform(matrix)
colors = ["red", "darkorange", "gold", "turquiose", "darkgreen"]
x = [x for x,y in vis_dims]
y = [y for x,y in vis_dims]
color_indices = df.Score.values - 1
colormap = matplotlib.colors.ListedColormap(colors)
plt.scatter(x, y, c=color_indices, cmap=colormap, alpha=0.3)
plt.title("Amazon ratings visualized in language using t-SNE")
ML アルゴリズム用テキスト特徴エンコーダとしての埋め込み
埋め込みは機械学習モデル内で汎用のフリーテキスト特徴エンコーダとして使用できます。関連する入力の幾つかがフリーテキストである場合、埋め込みを組み込むと任意の機械学習モデルのパフォーマンスを改良します。埋め込みはまた ML モデル内のカテゴリカル特徴エンコーダとして使用することもできます。これは役職のようなカテゴリカル変数の名前が意味があり数多くあれば、価値を高めます。このタスクに対しては類似性埋め込みは一般に検索埋め込みよりもパフォーマンスが高いです。
一般に埋め込み表現は非常にリッチで情報密であることに気づきました。例えば、SVD や PCA を使用して入力の次元性を削減すると、10% でさえ、一般に特定のタスクの下流パフォーマンスが低下するという結果になります。
このコードはデータを訓練セットとテストセットに分割します、これは以下の 2 つのユースケースで使用されます、つまり回帰と分類です。
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
list(df.ada_embedding.values),
df.Score,
test_size = 0.2,
random_state=42
)
埋め込み機能を使用した回帰
埋め込みは数値を予測するエレガントな方法を提供します。この例ではレビュアーのスター評価を、レビューのテキストに基づいて予測します。埋め込み内に含まれる意味的情報が高い (high) ので、予測は非常に少ないレビューでも十分です。
スコアは 1 から 5 の連続変数であると仮定し、アルゴリズムは任意の浮動小数点値を予測することを可能にします。ML アルゴリズムは真のスコアへの予測値の距離を最小化して、0.39 の平均絶対誤差を達成します、これは平均して予測はスターの半分未満 (真のスコアから) 離れていることを意味します。
from sklearn.ensemble import RandomForestRegressor
rfr = RandomForestRegressor(n_estimators=100)
rfr.fit(X_train, y_train)
preds = rfr.predict(X_test)
埋め込み機能を使用した分類
今回は、アルゴリズムに 1 から 5 のどこかの値を予測させるのではなく、レビューに対するスターの正確な数値を 1 から 5 スターの範囲の 5 つのバケットに分類することを試みます。
訓練後、おそらくはより極端なセンチメント表現ゆえに、モデルは微妙なレビュー (2 から 4 スター) よりも 1 と 5-スターのレビューを遥かに上手く予測することを学習します。
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, accuracy_score
clf = RandomForestClassifier(n_estimators=100)
clf.fit(X_train, y_train)
preds = clf.predict(X_test)
ゼロショット分類
ラベル付き訓練データなしにゼロショット分類のために埋め込みを使用することができます。各クラスについて、クラス名またはクラスの短い説明を埋め込みます。ゼロショット手法で新しいテキストを分類するため、その埋め込みをすべてのクラスの埋め込みと比較して最も高い類似性を持つクラスを予測します。
from openai.embeddings_utils import cosine_similarity, get_embedding
df= df[df.Score!=3]
df['sentiment'] = df.Score.replace({1:'negative', 2:'negative', 4:'positive', 5:'positive'})
labels = ['negative', 'positive']
label_embeddings = [get_embedding(label, model=model) for label in labels]
def label_score(review_embedding, label_embeddings):
return cosine_similarity(review_embedding, label_embeddings[1]) - cosine_similarity(review_embedding, label_embeddings[0])
prediction = 'positive' if label_score('Sample Review', label_embeddings) > 0 else 'negative'
コールドスタートのリコメンデーション用にユーザと製品の埋め込みの取得
ユーザのレビューのすべてに渡り平均化することでユーザの埋め込みを取得することができます。同様に製品についてのすべてのレビューに渡り平均化することで製品の埋め込みを取得できます。このアプローチの有用性を示すために、50k レビューのサブセットを使用してユーザ毎と製品毎のより多くのレビューをカバーします。
これらの埋め込みの有用性を分離したテストセットで評価します、そこではユーザと製品埋め込みの類似性を評価の関数としてプロットします。興味深いことに、このアプローチに基づいて、ユーザが製品を受け取る前でさえ、ユーザが製品を好きになるかランダムよりも良い予測をすることができます。
user_embeddings = df.groupby('UserId').ada_embedding.apply(np.mean)
prod_embeddings = df.groupby('ProductId').ada_embedding.apply(np.mean)
クラスタリング
クラスタリングは大量のテキストデータの意味を理解する一つの方法です。埋め込みはこのタスクのために有用です、それらは各テキストの意味論的に意味のあるベクトル表現を提供するからです。そのため、教師なしの手法で、クラスタリングはデータセットの隠れたグループ分けを明らかにします。
この例では、4 つの異なるクラスタを発見します : 1 つはドッグフードにフォーカスし、一つは否定的なレビュー、そして 2 つは肯定的なレビューです。
import numpy as np
from sklearn.cluster import KMeans
matrix = np.vstack(df.ada_embedding.values)
n_clusters = 4
kmeans = KMeans(n_clusters = n_clusters, init='k-means++', random_state=42)
kmeans.fit(matrix)
df['Cluster'] = kmeans.labels_
埋め込みを使用したテキスト検索
最も関連性の高いドキュメントを取得するため、クエリーと各ドキュメント間の埋め込みベクトルのコサイン類似度を使用し、最高スコアのドキュメントを返します。
from openai.embeddings_utils import get_embedding, cosine_similarity
def search_reviews(df, product_description, n=3, pprint=True):
embedding = get_embedding(product_description, model='text-embedding-ada-002')
df['similarities'] = df.ada_embedding.apply(lambda x: cosine_similarity(x, embedding))
res = df.sort_values('similarities', ascending=False).head(n)
return res
res = search_reviews(df, 'delicious beans', n=3)
埋め込みを使用したコード検索
コード検索は埋め込みベースのテキスト検索と同様に機能します。与えられたレポジトリのすべての Python ファイルから Python 関数を抽出するメソッドを提供します。そして各関数は text-embedding-ada-002 モデルによりインデックスが作成されます。
コード検索を実行するため、同じモデルを使用して自然言語でクエリーを埋め込みます。それから結果としてのクエリー埋め込みと各関数埋め込みの間のコサイン類似度を計算します。最高のコサイン類似度の結果が最も関連性が高いです。
from openai.embeddings_utils import get_embedding, cosine_similarity
df['code_embedding'] = df['code'].apply(lambda x: get_embedding(x, model='text-embedding-ada-002'))
def search_functions(df, code_query, n=3, pprint=True, n_lines=7):
embedding = get_embedding(code_query, model='text-embedding-ada-002')
df['similarities'] = df.code_embedding.apply(lambda x: cosine_similarity(x, embedding))
res = df.sort_values('similarities', ascending=False).head(n)
return res
res = search_functions(df, 'Completions API tests', n=3)
埋め込みを使用したレコメンデーション
埋め込みベクトルの間のより短い距離はより類似度が高いことを表しますので、埋め込みはレコメンデーションのためにも役立ちます。
以下で基本的なレコメンダー (recommender) を例示します。それは文字列のリストと 1 つの「ソース」文字列を受け取り、それらの埋め込みを計算してから、最も類似したものからそうでないものへとランク付けされた、文字列のランキングを返します。具体的な例として、以下のリンクされたノートブックはこの関数のバージョンを (2,000 のニュース記事の説明にサンプリングダウンされた) AG ニュースデータセット に適用し、任意の与えられたソース記事に最も類似した 5 つの記事を返します。
def recommendations_from_strings(
strings: List[str],
index_of_source_string: int,
model="text-embedding-ada-002",
) -> List[int]:
"""Return nearest neighbors of a given string."""
# get embeddings for all strings
embeddings = [embedding_from_string(string, model=model) for string in strings]
# get the embedding of the source string
query_embedding = embeddings[index_of_source_string]
# get distances between the source embedding and other embeddings (function from embeddings_utils.py)
distances = distances_from_embeddings(query_embedding, embeddings, distance_metric="cosine")
# get indices of nearest neighbors (function from embeddings_utils.py)
indices_of_nearest_neighbors = indices_of_nearest_neighbors_from_distances(distances)
return indices_of_nearest_neighbors
制限とリスク
(訳注: 原文 参照)
よくある質問と回答 (FAQ)
文字列を埋め込む前に幾つのトークンを含むか分かる方法は?
Python で、文字列を OpenAI のトークナイザー tiktoken でトークンに分割できます。
サンプルコード :
import tiktoken
def num_tokens_from_string(string: str, encoding_name: str) -> int:
"""Returns the number of tokens in a text string."""
encoding = tiktoken.get_encoding(encoding_name)
num_tokens = len(encoding.encode(string))
return num_tokens
num_tokens_from_string("tiktoken is great!", "cl100k_base")
text-embedding-ada-002 のような第2世代の埋め込みモデルについては、cl100k_base エンコーディングを使用します。
詳細とサンプルコードは OpenAI クックブック・ガイド how to count tokens with tiktoken にあります。
K 個の最も近い埋め込みベクトルをどのように素早く取得できますか?
多くのベクトルを素早く検索するために、ベクトルデータベースの使用を勧めます。ベクトルデータベースと OpenAI API を使用する例は GitHub の クックブック で見つけられます。
ベクトルデータベースの選択肢は以下を含みます :
- Chroma, オープンソースの埋め込みストア
- Elasticsearch, ポピュラーな検索/分析エンジンとベクトルデータベース
- Milvus, スケーラブルな類似検索のために構築されたベクトルデータベース
- Pinecone, フルマネージドなベクトルデータベース
- Qdrant, ベクトル検索エンジン
- Redis, ベクトルデータベースとして
- Typesense, 高速なオープンソースのベクトル検索
- Weaviate, オープンソースのベクトル検索エンジン
- Zilliz, Milvus による強化
どの距離関数を使用するべきでしょう?
コサイン類似度 を勧めます。距離関数の選択は通常は重要ではありません。
OpenAI の埋め込みは長さ 1 に正規化されます、これは以下を意味します :
- コサイン類似度はドット積だけを使用して僅かに高速に計算できます。
- コサイン類似度とユークリッド距離は同一の順位付け (ranking) という結果になります。
埋め込みをオンラインで共有できますか?
顧客は入力とモデルからの出力を、埋め込みの場合も含めて所有します。You are responsible for ensuring that the content you input to our API does not violate any applicable law or our Terms of Use.
以上