多くの場合、最新のアプリケーションには検索ソリューションが組み込まれており、ユーザーは必要に応じて既存のコンテンツにすばやくアクセスできます。この情報を効率的に取得できる他の機能を想像することは困難であり、検索はほとんどのアプリケーションで不可欠な機能となっています。
同時に、クエリと検索の必要性が非常に一般的であっても、アプリケーションが異なれば、アプローチも大幅に異なります。
ほとんどの場合、企業は OLTP データベースに直接クエリを実行するだけで、非常に基本的な検索レベルのままです。リクエストは次のようになります: SELECT id, title FROM, entities WHERE, description LIKE '%bow%
.
ただし、多くの場合、それらは複雑で複数レベルのテーブル結合構造で表され、読み取りが不可能で、遅く、原始的です。コンテキストを理解できず、多数のカスタマイズが必要であり、適切に実装するのは非常に困難です。
マテリアライズド ビュー、クエリ キャッシング、およびその他の技術によってクエリの実行時間を改善することは可能ですが、複雑さが増すと、プライマリ更新と一貫した検索結果の間にかなりの遅延が生じます。
原始的な DB ベースの検索ソリューションのより効率的な代替手段として、Apache Lucene、Apache Solr、Elasticsearch、Sphinx、MeiliSearch、Typesense などのオープンソース検索エンジンを構成することができます。
これらは比較的高速で、複雑なクエリの処理やフィルターの操作がはるかに優れている傾向があります。しかし、これらの検索エンジンをGoogle検索や DuckDuckGo などの対応するものと比較すると、オープンソース ソリューションが適切な検索コンテキストとクエリ モダリティを構築できないことが明らかになります。
酸味のある黄色い柑橘系の果物が何と呼ばれているのか思い出せないと想像してみてください。しかし、この不思議な果物を育てる方法に関する記事をアプリで検索したいと考えています。その検索をどのように行いますか?
あなたの質問は、「屋内で黄色の酸っぱい柑橘類を育てる方法」かもしれません.データベースに「レモン」の栽培に関する記事が含まれている場合でも、前述のオープンソース検索エンジンのいずれも、このクエリに関連する結果を返すのに非常に苦労する可能性があります。
これは、クエリからの意味の抽出は自然言語タスクであり、AI コンポーネントなしでは解決できない可能性が高いためです。 GPT-3はこのタスクに適しています。
OpenAI オファー
ドキュメント テキストのベクトル表現への変換はバックグラウンドで実行できますが、検索クエリのベクトル化は実行時に実行する必要があります。 OpenAI が提供するいくつかの GPT-3 モデル ファミリーがあります。
text-search-ada-doc-001: 1024 text-search-babbage-doc-001: 2048 text-search-curie-doc-001: 4096 text-search-davinci-doc-001: 12288
ベクトルの次元が高いほど、埋め込まれた情報が多くなるため、コストが高くなり、検索が遅くなります。
ドキュメントは通常長く、クエリは通常短く不完全です。したがって、ドキュメントのベクトル化は、コンテンツの密度とサイズを考慮すると、クエリのベクトル化とは大きく異なります。 OpenAI はそれを知っているため、2 つのペアのモデル、 -doc
と-query
を提供します。
text-search-ada-query-001: 1024 text-search-babbage-query-001: 2048 text-search-curie-queryc-001: 4096 text-search-davinci-query-001: 12288
クエリとドキュメントの両方が同じモデル ファミリを使用し、出力ベクトルの長さが同じでなければならないことに注意することが重要です。
例を通して、この検索ソリューションの威力を見て理解するのが最も簡単かもしれません。この例では、
データセットには多数の列が含まれていますが、ベクトル化プロセスはタイトルと概要の列のみを中心に構築されます。
Title: Harry Potter and the Half-Blood Prince Overview: As Harry begins his sixth year at Hogwarts, he discovers an old book marked as 'Property of the Half-Blood Prince', and begins to learn more about Lord Voldemort's dark past.
データセットをすぐにインデックス付けできるテキストにマップしましょう。
datafile_path = "./tmdb_5000_movies.csv" df = pd.read_csv(datafile_path) def combined_info(row): columns = ['title', 'overview'] columns_to_join = [f"{column.capitalize()}: {row[column]}" for column in columns] return '\n'.join(columns_to_join) df['combined_info'] = df.apply(lambda row: combined_info(row), axis=1)
埋め込みプロセスは簡単です。
def get_embedding(text, model="text-search-babbage-doc-001"): text = text.replace("\n", " ") return openai.Embedding.create(input = [text], model=model)['data'][0]['embedding'] get_embedding(df['combined_info'][0])
このコード ブロックは、モデルが操作しているパラメーターtext-search-babbage-doc-001
の場合は 2048) と同じサイズのリストを出力します。
同様の埋め込みプロセスを、検索するすべてのドキュメントに適用する必要があります。
df['combined_info_search'] = df['combined_info'].apply(lambda x: get_embedding(x, model='text-search-babbage-doc-001')) df.to_csv('./tmdb_5000_movies_search.csv', index=False)
列combined_info_search
結合テキストのベクトル表現を保持します。
そして、驚くべきことに、それはすでにそれです!最後に、サンプルの検索クエリを実行する準備が整いました。
from openai.embeddings_utils import get_embedding, cosine_similarity def search_movies(df, query, n=3, pprint=True): embedding = get_embedding( query, engine="text-search-babbage-query-001" ) df["similarities"] = df.combined_info_search.apply(lambda x: cosine_similarity(x, embedding)) res = ( df.sort_values("similarities", ascending=False) .head(n) .combined_info ) if pprint: for r in res: print(r[:200]) print() return res res = search_movies(df, "movie about the wizardry school", n=3)
Title: Harry Potter and the Philosopher's StoneOverview: Harry Potter has lived under the stairs at his aunt and uncle's house his whole life. But on his 11th birthday, he learns he's a powerful wizard — with a place waiting for him at the Hogwarts School of Witchcraft and Wizardry. As he learns to harness his newfound powers with the help of the school's kindly headmaster, Harry uncovers the truth about his parents' deaths — and about the villain who's to blame. Title: Harry Potter and the Goblet of FireOverview: Harry starts his fourth year at Hogwarts, competes in the treacherous Triwizard Tournament and faces the evil Lord Voldemort. Ron and Hermione help Harry manage the pressure — but Voldemort lurks, awaiting his chance to destroy Harry and all that he stands for. Title: Harry Potter and the Prisoner of AzkabanOverview: Harry, Ron and Hermione return to Hogwarts for another magic-filled year. Harry comes face to face with danger yet again, this time in the form of an escaped convict, Sirius Black — and turns to sympathetic Professor Lupin for help.
「ハリー・ポッターと賢者の石」の概要には、「魔法使い」と「学校」という単語が含まれており、検索結果の最初に表示されます。 2 番目の結果には、「学校」という単語が含まれなくなりましたが、「魔法使い」、「トリウィザード」に近い単語がまだ残っています。 3 番目の結果には、「魔法使い」の同義語である魔法のみが含まれています。
もちろん、このデータベースには、学校や魔法使い (またはその両方) をフィーチャーした他の映画が多数ありますが、返されたのは上記の映画だけでした。これは、検索ソリューションが機能し、クエリのコンテキストを実際に理解したという明確な証拠です。
2048 個のパラメーターのみを持つ Babbage モデルを使用しました。 Davinci には 6 倍 (12,288) のパラメーターがあるため、非常に複雑なクエリに関して大幅に優れたパフォーマンスを発揮できます。
検索ソリューションは、一部のクエリに関連する出力を生成できない場合があります。たとえば、「学校の魔法使いに関する映画」というクエリでは、次の結果が生成されます。
Title: Harry Potter and the Philosopher's StoneOverview: Harry Potter has lived under the stairs at his aunt and uncle's house his whole life. But on his 11th birthday, he learns he's a powerful wizard — with a place waiting for him at the Hogwarts School of Witchcraft and Wizardry. As he learns to harness his newfound powers with the help of the school's kindly headmaster, Harry uncovers the truth about his parents' deaths — and about the villain who's to blame. Title: Dumb and Dumberer: When Harry Met LloydOverview: This wacky prequel to the 1994 blockbuster goes back to the lame-brained Harry and Lloyd's days as classmates at a Rhode Island high school, where the unprincipled principal puts the pair in remedial courses as part of a scheme to fleece the school. Title: Harry Potter and the Prisoner of AzkabanOverview: Harry, Ron and Hermione return to Hogwarts for another magic-filled year. Harry comes face to face with danger yet again, this time in the form of an escaped convict, Sirius Black — and turns to sympathetic Professor Lupin for help.
「Dumb and Dumberer: When Harry Met Lloyd」がここで何をしているのか疑問に思うかもしれません。ありがたいことに、この問題は、より多くのパラメーターを持つパラメーターでは再現されませんでした。
検索出力は、関連性の降順でソートされたドキュメントで構成されている必要があります。これを実現するには、現在のクエリと各ドキュメントの間の距離を認識する必要があります。長さが短いほど、出力の関連性が高くなります。次に、定義された最大リーチの後、残りのドキュメントの関連性の考慮を停止する必要があります。
前述の例では、
距離計算アルゴリズムは、クエリとドキュメント間のこの類似性 (相違点) を単一の数値で表す傾向があります。ただし、信頼することはできません。
必要に応じて、ここで結果のリポジトリをチェックアウトできます。
または、こちらのGoogle Colab で試すこともできます。
ドキュメントを並べ替えるには、ブルート フォース アプローチを使用しました。決定しましょう:
● n: トレーニング データセットのポイント数
● d: データの次元
ブルート フォース ソリューションの検索時間の複雑さはO(n * d * n * log(n))です。パラメータdはモデルによって異なります (Babbage の場合は 2048 です) が、並べ替えステップのためにO(nlog(n))ブロックがあります。
この段階で、モデルが小さいほど高速で安価であることを認識しておくことが重要です。たとえば、検索ケースの類似度計算ステップでは、Ada モデルは 2 倍速く、Davinci モデルは 6 倍遅くなります。
私の M1 Pro では、クエリと 2048 次元の 4803 ドキュメント間のコサイン類似度の計算に 1260 ミリ秒かかりました。現在の実装では、計算に必要な時間はドキュメントの総数に比例して増加します。同時に、このアプローチは計算の並列化をサポートします。
検索ソリューションでは、クエリはできるだけ早く完了する必要があります。そして、この価格は通常、トレーニングと事前キャッシュ時間の側面で支払われます. kd ツリー、r ツリー、ボール ツリーなどのデータ構造を使用できます。の記事を検討してください。
Kd ツリー、ボール ツリー、および r ツリーは、意味ベクトルなどの N 次元空間内のポイントを格納して効率的に検索するために使用されるデータ構造を構成します。
Kd ツリーとボール ツリーは、ツリー ベースのデータ構造であり、反復的なバイナリ パーティショニング スキームを使用して空間を領域に分割します。ツリー内の各ノードはサブ領域を表します。 Kd ツリーは、特定の範囲内のポイントを検索したり、特定のポイントの最近傍を見つけたりするのに特に効率的です。
同様に、r ツリーは N 次元空間にポイントを格納するためにも使用されますが、特定の領域内のポイントを検索したり、特定のポイントから特定の距離内にあるすべてのポイントを検索したりする場合には、はるかに効率的です。重要なことに、r ツリーは kd ツリーとボール ツリーに異なる分割スキームを使用します。それらはスペースをバイナリパーティションではなく「長方形」に分割します。
ツリーの実装はこの記事の範囲外であり、実装が異なれば検索結果も異なります。
おそらく、現在の検索ソリューションの最も重大な欠点は、外部の OpenAI API を呼び出してクエリの埋め込みベクトルを取得する必要があることです。アルゴリズムが最近傍をどれだけ迅速に見つけられたとしても、順次ブロックするステップが必要になります。
Text-search-babbage-query-001 Number of dimensions: 2048 Number of queries: 100 Average duration: 225ms Median duration: 207ms Max duration: 1301ms Min duration: 176ms
Text-search-ada-query-002 Number of dimensions: 1536 Number of queries: 100 Average duration: 264ms Median duration: 250ms Max duration: 859ms Min duration: 215ms
Text-search-davinci-query-001 Number of dimensions: 12288 Number of queries: 100 Average duration: 379ms Median duration: 364ms Max duration: 1161ms Min duration: 271ms
中央値を基準点とすると、ada-002 は +28% 遅く、davinci-001 は +76% 遅いことがわかります。
を参照
また、OpenAI ではトレーニング コストが比較的高くなります。
または、試すことを検討することもできます
Elasticsearch 8.0 は効率的な近似最近傍検索 (ANN) をサポートしており、線形 KNN よりも速く問題の大きさを解決するために使用できます。 Elasticsearch 8.0 は、Hierarchical Navigable Small World Graphs (HNSW) と呼ばれる ANN アルゴリズムを利用して、ベクトルを類似性に基づいてグラフに編成します。 1,000 万の埋め込みベクトルのデータセットでテストしたところ、KNN を使用した場合は 1 秒あたりわずか 2 クエリでしたが、1 台のコンピューティングに重点を置いたマシンで ANN を使用すると 1 秒あたり 200 クエリという印象的なパフォーマンスを達成しました。どちらも Elasticsearch によって提供されました。
エラスティックサーチによると
お気づきのことと思いますが、GPT-3 埋め込みは、インデックス作成の複雑さ、コスト、および検索操作の高い計算上の複雑さ (概算であっても) により、すべての検索問題に対する完璧なソリューションではありません。それにもかかわらず、GPT-3 Embeddings は、クエリの頻度が低く、インデックス作成の要件が控えめな検索ソリューションの強力なバックボーンを探している人にとって、依然として優れた選択肢です。
さらに、 Microsoft が最近 __を発表したことも追加する価値があります。発表によると、新しい Prometheus 言語モデルにより、Bing は関連性を高め、より正確にスニペットに注釈を付け、より新しい結果を提供し、地理位置情報を理解し、セキュリティを向上させることができます。これにより、検索ソリューションに自己回帰言語モデルを使用する新しい可能性が開かれる可能性があり、今後も注目していきます。
参考文献: