はじめに
今回はEmbeddings(埋め込み化)をAzure OpenAIで行ってみます。
まずは、OpenAIのEmbeddingサンプルにある『fine-food reviews』を試しに使ってみます。
最後にこのサンプルを参考に、けんさむさんの熊本紹介記事を埋め込み化して熊本の行きたいお店を探してみようと思います。
環境
- OS Windows 10(NVIDIA GTX 1650Ti,16GB RAM, i5-10300H CPU)
- Visual Studio Code 1.73.1
- Python 3.9
埋め込み化とは
テキストを埋め込み化すると、そのテキストの関連性を測定するというものです。
埋め込みAPIを使うことで、関連性の高い文字列の検索ができるほか、類似したテキストをグループ化するクラスタリングや、逆に関連性の低いものを検知する異常検知などもできます。
レビューを埋め込み化してみる
まずはレビューを埋め込み化して、欲しい内容を検索して取得してみます。
データセット
使っていくレビューはこちらのfine-food reviewsです。
このデータセットはAmazonの高級食材をレビューしたもので、約50万件まとめられています。
内容には、Score
(5段階評価)やText
(実際のレビューテキスト)、HelpfulnessNumerator
(このレビューが役に立ったというユーザの数)などの項目があります。
text-embedding-ada-002を使ってみる
それではさっそく埋め込み化をします!
使うモデルはtext-embedding-ada-002です。
Azure OpenAIにtext-embedding-ada-002のモデルをデプロイしているのを前提に進めていくので、まだの人はこちらの公式サイトをご参照ください。
まずは必要なライブラリをインストール。
下記のものが必要なのでpipインストールしましょう。
1 2 |
pip install openai num2words matplotlib plotly scipy scikit-learn pandas tiktoken |
そして、importやAPIの設定を行います。
1 2 3 4 5 6 7 8 9 10 11 12 |
import openai import os import pandas as pd import numpy as np from openai.embeddings_utils import get_embedding, cosine_similarity import tiktoken openai.api_type = "azure" openai.api_base = "https://XXX.openai.azure.com/" #OPENAI_API_BASE openai.api_version = "2023-05-15" openai.api_key = "OPENAI_API_KEY" |
APIキーやバージョンなどを入力します。
次に埋め込み化の設定をします。使用するモデル・エンコーディング・最大トークン数を次のようにしました。
1 2 3 4 |
embedding_model = "text-embedding-ada-002" embedding_encoding = "cl100k_base" max_tokens = 8000 |
続いてデータの前処理をします。
csvファイルを読み込み、columnsの選択・追加を行います。
1 2 3 4 5 6 7 8 |
input_datapath = "data/fine_food_reviews_1k.csv" df = pd.read_csv(input_datapath, index_col=0) df = df[["Time", "ProductId", "UserId", "Score", "Summary", "Text"]] df = df.dropna() df["combined"] = ( "Title: " + df.Summary.str.strip() + "; Content: " + df.Text.str.strip() ) |
そしてエンコーディング・埋め込み化を行います。
最大トークン数を超えるような、長いレビューはフィルタリングし、最終的に最新レビューのうち1000件を選んで埋め込みします。
1 2 3 4 5 6 7 8 9 10 |
top_n = 1000 df = df.sort_values("Time").tail(top_n * 2) less than half will be filtered out df.drop("Time", axis=1, inplace=True) encoding = tiktoken.get_encoding(embedding_encoding) df["n_tokens"] = df.combined.apply(lambda x: len(encoding.encode(x))) df = df[df.n_tokens <= max_tokens].tail(top_n) |
生成された埋め込みは新しくembedding
列に追加します。
1 2 3 |
<df["embedding"] = df.combined.apply(lambda x: get_embedding(x, engine=embedding_model)) df.to_csv("data/fine_food_reviews_with_embeddings_1k_2.csv") |
出力された「fine_food_reviews_with_embeddings_1k_2.csv」の中身はコチラ
検索・結果
それでは検索してみます。user_query
で取得したい情報について書きます。今回は抽象的ですが、良いレビューを3つ取ってくるように設定しました。
埋め込み計算は「コサイン類似度」というものを使って埋め込みしたドキュメントとクエリの類似度を計算します。
1 2 3 4 5 6 7 8 9 10 11 12 |
user_query = "Can I get good reviews" top_n = 3 embedding = get_embedding( user_query, engine=embedding_model, ) df["similarities"] = df.embedding.apply(lambda x: cosine_similarity(x, embedding)) res = (df.sort_values("similarities", ascending=False).head(top_n)) res.to_csv("data/response.csv") |
返ってきた内容がコチラ
選ばれた3つのText
を見てみるとどれも高評価なレビューなので、きちんと求めていた結果が返ってきました。
今度はこの埋め込み化を使って、熊本のおいしいお店を検索してみます!!
けんさむさんの食レポ記事を埋め込み化してみる
熊本のおいしいお店を紹介しているけんさむさんの記事を埋め込み化し、自分の希望にマッチするお店を検索してみます。
まずは記事のURLと文章を取ってきて、csvファイルにまとめます。
そして、このcsvファイルを読み込んで、埋め込み化をします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import openai import os import pandas as pd import numpy as np from openai.embeddings_utils import get_embedding, cosine_similarity import tiktoken openai.api_type = "azure" openai.api_base = "https://XXX.openai.azure.com/" #OPENAI_API_BASE openai.api_version = "2023-05-15" openai.api_key = "OPENAI_API_KEY" embedding_model = "text-embedding-ada-002" embedding_encoding = "cl100k_base" max_tokens = 8000 input_datapath = "data/kensam/sentences.csv" df = pd.read_csv(input_datapath, index_col=0, encoding="utf-8") encoding = tiktoken.get_encoding(embedding_encoding) df["n_tokens"] = df.Sentences.apply(lambda x: len(encoding.encode(x))) df = df[df.n_tokens <= max_tokens] print(len(df)) df["embedding"] = df.Sentences.apply(lambda x: get_embedding(x, engine=embedding_model)) df.to_csv("data/kensam/sentences_with_embeddings.csv") |
input_datapath
に埋め込み化をするcsvファイルのパスを入力します。
これを実行したら、「sentences_with_embeddings.csv」というembedding列を加えたファイルが出力されます。
埋め込み化したら次は検索!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import openai import pandas as pd import numpy as np from openai.embeddings_utils import get_embedding, cosine_similarity import ast openai.api_type = "azure" openai.api_base = "https://XXX.openai.azure.com/" #OPENAI_API_BASE openai.api_version = "2023-05-15" openai.api_key = "OPENAI_API_KEY" embedding_model = "text-embedding-ada-002" embedding_encoding = "cl100k_base" max_tokens = 8000 df = pd.read_csv("data/kensam/sentences_with_embeddings.csv", index_col=0, encoding="utf-8") user_query = "山鹿のおいしいラーメン屋さんは?" top_n = 3 df['embedding'] = df['embedding'].apply(lambda x: np.array(ast.literal_eval(x))) embedding = get_embedding( user_query, engine=embedding_model, ) df["similarities"] = df.embedding.apply(lambda x: cosine_similarity(x, embedding)) res = (df.sort_values("similarities", ascending=False).head(top_n)) print(res) res.to_csv("data/kensam/result/response.csv") |
df
には先ほどの埋め込み化で出力された「sentences_with_embeddings.csv」のパスを入力します。また、user_query
には検索したい情報を書き込みます。
検索結果
まずは試しに「山鹿でおいしいラーメン屋はどこ?」と聞いてみました。
すると…
- 【麺屋仁大 におう】熊本・山鹿でおいしい豚骨ラーメンを発見!
- 熊本の山奥、山都町で謎に支持されている「おちかラーメン」に潜入してきた
- 熊本・山鹿『どさん子ラーメン』のチーズカツ定食が絶品&ボリュームMAXだ
上位3つこちらが選ばれました。
1と3についてはきちんと山鹿のラーメン屋が選ばれましたが、2番目だけは山都町の記事がヒット!!「山」だけで判断された感じですかね…?よくわかりません><
ちなみにけんさむさんの検索窓に「山鹿 ラーメン」と入力したら、『仁大』と『どさん子ラーメン』の記事がヒットしたので、今のところ埋め込み化のメリットはなんだろう?状態になってます汗。ただ、文章で聞けるのは普通の検索とは違う良いところですかね。
↓がちもとさんにも使ってもらいました!↓
けんさむさんのグルメ記事をEmbeddingしました。
「ひとりで気軽に行ける居酒屋」トップ3
1.https://t.co/NG0koAaSjH
2.https://t.co/Y9EMINu607
3.https://t.co/VJrdv0uhzF#OpenAI #Embedding— がちもとさん (@sotongshi) June 5, 2023
今回使った検索については他にどんなものに使えるのか、用途を検討してみます…!
参考サイト