🔡

(日本語訳) Vector databases (Part 2): Understanding their internals

2023/09/21に公開
1

日本語訳: ベクトルデータベース(パート2): 内部を理解する

訳者前書き

ベクトルデータベースについていろいろと調査・検証していたところ、以下の記事を見つけて、内容が非常によくまとまっており、多くの人にとっても有用な記事ではないか感じました。もはや翻訳などはDeepLやChatGPTで簡単にできる時代になりつつありますが、まだまだ検索エンジンで検索されることも多いと思いますし、少しでも参照しやすくなればと考えて、作者であるPrashanth Rao氏に許可を頂いた上で日本語に翻訳したものとなっています。

全4回の記事の第2回目となります。

元記事
https://thedataquarry.com/posts/vector-db-2/

Prashanth Rao氏のGitHubアカウント
https://github.com/prrao87

Prashanth Rao氏のTwitterアカウント
https://twitter.com/tech_optimist

第1回目の日本語訳はこちら

https://zenn.dev/kun432/articles/20230921-vector-databases-jp-part-1


背景

この記事はベクトルデータベースに関するシリーズの第2回目である。このシリーズの第1回目(元記事/日本語訳)で述べたように、2023年前半にはベクトルデータベースに関連したマーケティングが(そして残念ながら誇大広告も)盛んに行われている。これを読んでいる方は、ベクトルデータベースが実際にどのようなことを行っているのか、効率的なベクトルストレージの上に検索機能がどのように構築されているのかに興味があるだろう。

なぜ最近、誰もがベクトルデータベースについて話しているのか?

ベクトルDBが何であるかを深く知る前に、この分野での活発な動きや投資の背後にある理由は何だろうか?

大規模言語モデル(LLM)の時代

2022年11月、ChatGPT(GPT 3.5以降のOpenAIのインターフェース)の初期デモがリリースされ、その後わずか5日間で100万人のユーザーを獲得し、史上最も急成長したアプリケーションとなった🤯!実際に、主要なオープンソースのベクトルデータベースのGitHUbレポジトリの✨(訳注:GitHub Starと思われる)の推移を見てみると、2022年11月のChatGPTのリリースと、それに続く2023年3月のChatGPTプラグインのリリースの後、いくつかのレポジトリでスター数が明らかに急増している。これらの要因に加えて、Hacker Newsや人気メディア[1]などウェブサイトの記事で紹介されたことが、この分野での活発な動きの大きな要因となっている。


Made with ❤️ by star-history.com

LLMに依存することの問題点

LLMは生成的である。つまり、LLMはユーザーからのプロンプトに基づいて、意味のある首尾一貫したテキストを逐次的に生成する。しかし、人間の質問に答えるためにLLMを使用する場合、LLMはしばしば無関係な、あるいは事実と異なる結果を生成する場合がある。

  • LLMはしばしば幻覚を起こす。つまり、ユーザーに存在しないURLを教えたり、存在しない数字をでっち上げたりする。
  • LLMは学習データを圧縮したものを学習/記憶する。LLMは非常によく学習するが、完璧に学習するわけではない ー 情報の一部は常にモデルのデータの内部表現で「失われる」ことがある。
  • LLMはトレーニング完了後に発生した事実を知ることはできない。

ベクトルデータベースは、LLMが事実を効率よく検索するための基盤となるストレージレイヤーとして機能することで、これらの問題を解決するのに役立つ。従来のデータベースとは異なり、ベクトルDBはデータをベクトルとしてネイティブに表現することに特化している。その結果、最新の正確なデータ(LLMのトレーニング後の新しい後のデータ)を含むベクトルストレージレイヤーの上にLLMを使用したアプリケーションを構築し、「事実に基づいた」モデルとして幻覚の問題を軽減しつつ使えるようになった。

ベクトルデータベース(例:Vespa、Weaviate、Milvus)はLLMよりもずっと以前から存在していたが、ChatGPTのリリース以来、オープンソースコミュニティとベクトルDBベンダーのマーケティングチームは、高品質のテキスト生成と組み合わせた検索・取得が主流のユースケースであるという可能性を認識した。このことがベクトルデータベースの世界でのVC資金調達の絶対的なブームを説明している!

埋め込みとは何か?

ベクトルデータベースは、元のデータ(画像、音声、テキストなど)だけではなく、その符号化された形式である*埋め込み(embeddings)*も格納する。埋め込みは、データの文脈的な表現を格納している数値のリスト(すなわちベクトル)である。直感的に私達が「埋め込み」と言う場合、それは実際には高次元で存在するデータ(画像、テキスト、音声)の、圧縮された低次元表現を指している。

ストレージレイヤー内では、データベースはm個のベクトルをスタックし、各ベクトルはn次元のデータポイントを表しているので、合計サイズはm×nとなる。スタックは通常、クエリ・パフォーマンスの観点からシャーディングによって分割される。

埋め込みはどのように生成されるのか?

NLPにおけるtransformerの革命[2]は、このような圧縮された表現、つまり埋め込みを非常に効率的かつ大規模に生成するための十分な手段を提供することとなった。

基礎となるベクトルの次元が低ければ低いほど、埋め込み空間での表現がコンパクトになり、下流のタスク品質に影響を与える可能性があることに留意することが重要である。Sentence Transformers (sbert) は、384、512、768の範囲のn次元の埋め込みモデルを提供し、モデルは完全にフリーでオープンソースである。OpenAIとCohereの埋め込みは、それらを生成するための有料のAPIコールを必要とするが、数千の次元性を持つ、より高品質なものと考えられる。データが多言語である場合は、埋め込みを生成するために有料のAPIを使用することは適切な理由の1つになる(Cohereは、オープンソースの亜種に比べてより優れた性能を発揮することが知られている高品質の多言語埋め込みモデルを有していることで知られている)。

📄 注記

埋め込みモデルの選択は、通常、品質とコストのトレードオフである。ほとんどの場合、英語のテキストデータに対しては、テキストがあまり長くない場合(テキストシーケンスで300~400語)であれば、オープンソースのsentence-transformersモデルをそのまま利用することができる。sentence-transformerのコンテキストの長さよりも長いテキストを扱うことは可能だが、の場合はさらに外部ツールが必要になる。その話題はまた別の記事で!

埋め込みデータをベクトルデータベースに格納する

ベクトルデータベースは埋め込み空間での操作に適しているため、さまざまな形式のデータ(テキスト、画像、音声)に対するセマンティックまたは類似性ベースの検索に非常に役立つことがわかっている。セマンティック検索では、ユーザーから送られた入力クエリ(通常は自然言語)は、データ自体と同じ埋め込み空間内でベクトル形式に変換され、入力クエリと最も類似した上位k件(top-k)の結果が返される。これを視覚化したものを以下に示す。

類似性はどのように計算されるのか?

様々なベクトル・データベースは類似度を計算するための異なる指標を提供しているが、テキストに関しては、以下の2つの指標が最も一般的に使用されている:

  • ドット積: 任意の大きさの非正規化された値を生成する。
  • コサイン距離: 正規化された値(-1から1の間)を生成する。

コサイン距離の測定例

単純化した例として、赤ワインと白ワインの品名を2次元空間でベクトル化することを考えてみよう。水平軸は赤ワインを、垂直軸は白ワインを表す。この空間では、点同士が近ければば似たような言葉や概念を共有するワインを表し、遠ければはそれほど共通点がないことを表す。コサイン距離は、埋め込み空間における各ワインの位置を原点に結ぶ線のなす角のコサインとして定義される。

cos \theta = \frac{a^T \cdot b}{|a| \cdot{ |b|}}

視覚化することで、より直感的に理解できるようになる。

左側の図では、2つのワイン(the Reserve WhiteとToscana Red)は、語彙と概念の両方でほとんど共通点がないため、コサイン距離がゼロに近づいている(ベクトル空間では直交している)。右側では、Napa Valley産の2つのZinfandelは共通点が多いので、1に近いより大きなコサイン類似性を持っている。なお、究極的にはコサイン距離は1になる、つまり、ある文は自分自身と比較した場合には常に最も類似することになる。

もちろん、現実のシチュエーションでは、実際のデータは高次元のベクトル空間に存在し(ワインの品種以外にも多くの軸がある)、2次元の平面上では可視化できないが、コサイン類似性の原理は同じである。

スケーラブルな最近傍探索

いったんベクトルが生成・保存され、ユーザーが検索クエリを送信したときに、類似検索のゴールは、入力クエリ自身のベクトルに最も類似した上位k個のベクトルを提供することになる。これについても、もう一度単純化した2次元空間で視覚化してみよう。

これを行う最も単純な方法は、クエリベクトルをデータベース内のすべてのベクトルと比較する、いわゆるk近傍法(k-Nearest Neighbor: kNN)を使用することである。しかし、データポイントが数百万(または数十億)になってくると、必要な比較の数がデータとともに線形に増加するため、これはすぐに非常にコストがかかりすぎる方法となる

近似最近傍(ANN)

既存のすべてのベクトルデータベースは、近似最近傍Approximate Nearest Neighbours: ANN)検索と呼ばれるアルゴリズムのクラスによって、データセットのサイズに関係なく、検索を非常に効率的にすることに重点を置いている。データベース内のすべてのベクトルを網羅的に比較する代わりに、最近傍の近似検索が行われることで、結果の精度に若干の損失が生じることがある(真に最も近いベクトルが常に返されるとは限らない)が、ANNアルゴリズムの使用により大幅なパフォーマンスの向上が可能となる。

インデックス作成

データは、ベクトルデータベースにインデックス作成という行為を通じて保存される。これは、検索空間を迅速に絞り込むことでベクトルの効率的な検索を可能にするデータ構造、すなわちインデックスを作成することを指している。通常使用される埋め込みモデルは、10^2または10^3のオーダーの次元を持つベクトルを格納し、ANNアルゴリズムは、時間と空間において可能な限り効率的にデータの実際の複雑さを捉えようとする。

様々なベクトルDBで使用されているインデックス作成アルゴリズムは数多くあり、詳細は本記事の範囲外である(今後の記事で勉強するつもり)。しかし、参考までにそのいくつかを以下にリストアップする。

  • 転置ファイルインデックス(Inverted File Index: IVF)
  • Hierarchical Navigable Small World(HNSW)グラフ
  • Vamana(DiskANNの実装で利用されている)

一言で言えば、インデックス作成の最先端はHNSWやVamanaのような新しいアルゴリズムによって達成されているが、VamanaのDiskANN実装を提供しているデータベースベンダーはわずかである(2023年現在)

  • Milvus
  • Weaviate(進行中...)
  • LanceDB(進行中...)

すべてをまとめる

これまでの説明をすべて踏まえて、ベクトルデータベースが実際にはどのようなものかをイメージすることができる。

各データベースベンダーがスケーラビリティをどのように実現しているかの詳細(Kubernetes、シャーディング、ストリーミングなど)は実務家にとっては重要ではない。レイテンシ、コスト、スケーラビリティの間のトレードオフを考慮してシステムを設計するのはそれぞれのベンダーの責任領域である。

ストレージレイヤーとデータ取り込み

  • (ローカルまたはクラウド上の)データは、埋め込みモデルに渡され、ベクトル形式に変換され、APIゲートウェイを介してベクトルDBのストレージレイヤーに取り込まれる。
  • データはインデックス化され、その過程でスケーラビリティと高速な検索のためにパーティション化/シャーディングされる。
  • クエリエンジンはストレージレイヤーと緊密に統合されており、データベースのANN実装を介して最近傍を素早く検索できる。

アプリケーションレイヤー

  • ユーザーは、アプリケーションのUIを介して埋め込みモデルにクエリを送信する。埋め込みモデルは、入力されたクエリを、データと同じ埋め込み空間にあるベクトルに変換する。
  • ベクトル化されたクエリは、APIゲートウェイ経由でクエリエンジンに送られる。
    • 複数のクエリが非同期で処理され、top-kの結果がユーザに返される。

ベクトルデータベースを拡張して他の機能を提供する

上記のユースケースは、数年前には、大手テック企業で莫大なリソースを持っていない限り、実現不可能だったスケールでのセマンティック検索を、ベクトルデータベースがどう実現しているかを示している。しかしこれは氷山の一角に過ぎない。ベクトルデータベースは、多くの下流の機能をサポートするために使用されている。

ハイブリッド検索システム

Colin Harman氏は、彼の素晴らしいレビュー記事[3]で、今日のベクトルデータベースのマーケティング資料の多さのため、多くの企業が検索・取得分野において「トンネルビジョン」(訳注: 日本語では直線思考や視野狭窄の罠、などが意味的に近いと思われる)を経験していると述べている。私たち実務家としては、ベクトルデータベースが検索の万能薬ではないことを覚えておく必要がある。ベクトルデータベースはセマンティック検索においては非常に優れているが、多くの場合、伝統的なキーワード検索の方がより関連性の高い結果とユーザー満足度の向上を実現できる。それはなぜか?それは主に、コサイン類似度のような指標に基づくランキングが、特定の入力キーワードを含む部分一致よりも高い類似度スコアを持つ結果を上位に表示させるため、エンドユーザにとっての関連性を低下させることに関連している。

しかし、純粋なキーワード検索にもその限界がある。ユーザが保存されたデータと意味的に類似している(ただし正確ではない)用語を入力した場合、有用で関連性が高い可能性がある結果は返されない。このトレードオフの結果、検索・取得の現実的なユースケースにおいては、キーワードとベクトルの検索の組み合わせが求められ、ベクトルデータベースはその重要なコンポーネントとなっている(埋め込みを格納し、セマンティック類似性検索を可能にし、非常に大きなデータセットにも対応できるため)。

以上の点をまとめるとこうなる。

  • キーワード検索
    ユーザが何を探しているのかをわかっている場合や検索語句の正確なフレーズと一致する結果を期待する場合に、関連性のある有用な結果を見つける。ベクトルデータベースは必要ない。
  • ベクトル検索
    ユーザが具体的に何を探しているのかをわかっていない場合に、関連性のある結果を見つける。ベクトルデータベースが必要。
  • ハイブリッドなキーワード+ベクトル検索
    通常、フルテキストキーワード検索とベクトル検索からの候補結果を組み合わせ、クロスエンコーダーモデル[4](以下参照)を使用して再ランクする。ドキュメントデータベースとベクトルデータベースの両方が必要。

それぞれ図で視覚化すると以下のようにわかりやすい。


Diagram inspired by Qdrant blog post

BM25[5]は、特定のデータベース(Elasticsearch、Opensearch、MongoDBなど)のキーワード検索に使用される最も一般的なインデックス作成アルゴリズムである。これは、逆文書頻度(IDF)とキーワードとなる単語の出現頻度を関連付けて考慮することで、ベクトルを生成する。対照的に、ベクトルデータベースは通常、密ベクトル(BM25とは異なり、ベクトル内の単語はどれもゼロではない)で表現される埋め込みにテキストをエンコードして格納する。これには通常、BERTのようなbi-エンコーダーモデルを介して行われ、文書のペアに対して文の埋め込みを生成し、それを比較してコサイン類似度スコアを生成することができる。

訳者注

bi-エンコーダーと交差-エンコーダーの違いを理解する

ハイブリッド検索を効果的に実行するためには、BM25(キーワード検索)とコサイン類似度(ベクトル検索)を通じて得られた検索結果候補を組み合わせる必要があり、これには交差-エンコーダが必要になる。これは下図に示すように、2つの文を同時にBERTのようなエンコーダモデルに渡すための下流ステップとして行われる。文の埋め込みを生成するために使用されるbi-エンコーダとは異なり、交差-エンコーダは埋め込みを生成するのではなく、ソフトマックス層を介して、0から1の間でスコアを2つの文からなるペアに割り当てることによって、文のペアを分類することができる。これはリランキングと呼ばれ、両方の長所(キーワード+ベクトル検索)を組み合わせた結果を得るための非常に強力なアプローチである。

訳者注


Diagram inspired by Sentence transformers docs

ℹ️ 情報

交差-エンコーダによるリランキングは、クエリ時にtransformerモデルを使用する必要があるため、コストがかかるステップであることに注意すべきである。このアプローチは、検索の品質が非常に重要なユースケースで使用される。そして、アプリケーションが意図した通りに動作していることを確認するために、より多くの計算リソース(通常はGPU)やチューニング時間が必要となる。

ジェネレーティブQA:「データとチャットする」

GPT-4のような強力なLLMの出現により、アプリケーションのユーザエクスペリエンスと、ベクトルDBに格納された正確で事実に基づいた情報を効果的に統合して、ユーザは自然言語でデータを問い合わせることができるようになった。質問応答は単なる情報検索の域を超えることがあるため(単に問い合わせるだけでなく、データの一部を分析する必要があるかもしれない)、アプリケーションのUIとベクトルDBの間にLangChain[6]のようなエージェントベースのフレームワークを含めると、ベクトルDBに直接繋ぐよりもはるかに強力になる。

ベクトルDBはクエリされるデータを埋め込みとして格納し、LLMはその中の知識も埋め込みとしてエンコードするため、生成型のQAアプリケーションにおいて、それらは自然な組み合わせとなる。ベクトルデータベースは知識ベースとして機能し、LLMは埋め込み空間内でデータのサブセットを直接問い合わせることができる。これは以下のアプローチで行うことができる。

  1. 人間がUIを通じて自然言語で質問する。
  2. 質問のテキストが埋め込みモデル(bi-エンコーダ)に渡され、埋め込みモデルは文の埋め込みベクトルを返す。
  3. 質問のベクトがベクトルDBに渡され、ベクトルDBはANN検索によって最も類似したtop-kの結果を返す。
  • このステップは、次のステップで使用されるLLMの検索空間を大幅に絞り込むため、非常に重要
  1. LLMプロンプトが(開発者の定義済みテンプレートに基づいて)構築され、埋め込みに変換され、LLMに渡される。
  • LangChainのようなフレームワークは、このステップを実行するのに便利で、プロンプトは動的に構築され、LLMのネイティブな埋め込みモジュールが呼び出される。開発者が各ワークフローに多くのカスタムコードを書く必要はない。
  1. LLMがその情報に関するtop-kの結果を検索し、質問に対する回答を生成する。
  2. 回答が人間に返される。

上記のワークフローはさまざまな方法で拡張することができる ー 例えば、ユーザーの質問にデータベースから取得した数値の計算(LLMはこれが非常に苦手)が含まれていた場合、LangChainエージェントはまず計算が必要であると判断する。そして、top-kの結果から抽出された数値情報を計算APIに渡し、計算を実行し、回答をユーザーに返す。このような組み合わせ可能なワークフローを使えば、ベクトルデータベースにより、いかに強力な生成型のQAチャットインターフェースが実現可能であることがわかる。

結論

LLMとベクトルDBのそれぞれのメリットを組み合わせて構築できる便利なアプリケーションは他にもたくさんある。しかし、ベクトルDBの基本的な制約を理解しておくことは重要である。

  • 検索アプリケーションにおける関連性に関して、必ずしもキーワードフレーズの完全一致を優先するわけではない。
  • ベクトルデータベースに格納され検索されるデータは、使用される埋め込みモデルの最大シーケンス長(BERTのようなモデルの場合、これは数百語以下)に収める必要がある。現在のところ、これを実現する最善の方法は、LangChainやLlamaIndex[7]のようなフレームワークを利用して、モデルのコンテキストに合うように固定サイズのベクトルにデータをチャンク分割するか、圧縮することである。

ベクトルデータベースは信じられないほど強力だが、Harman氏[3:1]が言うように、結論はすべてのデータベースに当てはまる。

もしあなたがベクトルデータベースや、一般的な検索・情報検索の分野についての知識があまりないのであれば、以下のような資料を、技術スタックを選択する際の意思決定のための主要な情報源にすべきではない

  • 超敏腕VCによるインフラスタック
  • 人気のLLMアプリケーションフレームワークのチュートリアル

他の領域と同じように、ビジネスケースを明確に定義し、手持ちのツールを研究することで、それらを効果的に組み合わせれば現実の問題は解決できる。その意味で、ベクトルDBに関するこのシリーズが役に立てたなら幸いである!

このシリーズの他の記事


脚注
  1. "The rise of vector databases", Forbes ↩︎

  2. "Revolution in NLP is changing the way companies understand text", TechCrunch ↩︎ ↩︎

  3. "Beware tunnel vision in AI retrieval: Colin Harman︎", Substack ↩︎ ↩︎

  4. "On hybrid search", Qdrant blog ↩︎

  5. "Okapi BM25", Wikipedia↩︎

  6. LangChainドキュメント, python.langchain.com ↩︎

  7. LlamaIndexドキュメント ↩︎

GitHubで編集を提案