埋め込みとは何か、そしてなぜ重要なのか
(simonwillison.net)- 埋め込みは、テキスト・画像・コードのようなコンテンツを固定長の浮動小数点配列に変換し、意味的に近い項目を距離計算で見つけられるようにする
- 同じモデルが作ったベクトル空間では、個々の数値の意味が分からなくても コサイン類似度 によって関連文書、類似画像、コード断片を比較できる
- OpenAI
text-embedding-ada-002で472本のTIL記事を1,536次元ベクトルとして保存した事例では、関連記事検索クエリに約400msかかり、402,500トークン全体の埋め込みコストは約 $0.04 だった - ローカルモデルと小さなツールの組み合わせだけでも、README検索、コード検索、画像検索、クラスタリング、RAGを実装でき、
LLM、llm-sentence-transformers、Symbex、CLIP、E5-large-v2が例として使われる - 埋め込みベースの 意味検索 は正確な単語一致に依存しないため、社内文書の質疑応答のようなRAGで関連抜粋をLLMプロンプトに入れるための中核的な手段となる
埋め込みの基本概念
- 埋め込み は、ひとかたまりのコンテンツを浮動小数点数の配列に変換する方式である
- コンテンツの長さに関係なく、配列の長さは常に同じ
- 配列の長さは使う埋め込みモデルが決め、例として300個、1,000個、1,536個の数値がある
- この配列は、多次元空間の 座標 のように見なせる
- 空間内での位置は、埋め込みモデルが理解したコンテンツの意味を表す
- 色、形、概念のようなコンテンツ特性が反映されることがある
- 個々の数値の意味を完全に理解できなくても、位置関係を利用すれば近い項目を見つけるなど有用な作業ができる
関連コンテンツの推薦: TILブログの事例
- 472本の記事があるTILサイトで、OpenAI
text-embedding-ada-002モデルを使って各記事の 1,536次元埋め込みベクトル を計算した- ベクトルはサイトのSQLiteデータベースに保存された
- 関連記事は、対象記事ベクトルと他のすべての記事ベクトルのコサイン類似度を計算し、近い10件を返す方式で見つけた
- 例の記事 “Geospatial SQL queries in SQLite using TG, sqlite-tg and datasette-sqlite-tg” の関連記事上位結果は、SQLite、SpatiaLite、GDAL、空間SQLクエリ関連の記事で構成されていた
- 自分自身との類似度は1.0
sqlite_geopoly.mdは 0.8817322855676049spatialite_viewing-geopackage-data-with-spatialite-and-datasette.mdは 0.8813094978399854
- 関連記事計算クエリには約 400ms かかったため、全記事について上位10件の類似度を事前計算し、
similaritiesテーブルに保存した - OpenAI埋め込みAPIのコストは、TILサイト基準で約402,500トークンに対し $0.0001/1,000トークンの料金で $0.04 だった
- 独自モデルには運用上の注意が必要である
- OpenAIは過去に一部の古い埋め込みモデルを終了した
- 既存モデルで保存した埋め込みが多い場合、新しいコンテンツを埋め込むためにサポート対象モデル基準で再計算が必要になることがある
- OpenAIは新モデルへの再埋め込みコストを負担すると約束したが、独自モデル依存のリスクは残る
- 公開ライセンスモデルは自前のハードウェアで実行できるため、モデル終了リスクを避けられる
Word2Vecで見るベクトル空間
- Google Researchの Efficient Estimation of Word Representations in Vector Space は、2013年1月16日に公開されたWord2Vec論文である
- Word2Vec は、単語1つを300個の数値配列に変換する初期の埋め込みモデルである
- turbomaze.github.io/word2vecjson は、10,000語と各単語の300個の数値配列を探索できるデモである
- “france” に近い単語として
french、belgium、paris、germany、italy、spainが出てくる
- “france” に近い単語として
- ベクトル演算からも関係が見えてくる
- “germany” ベクトルに “paris” を足して “france” を引くと、結果ベクトルは “berlin” に最も近くなる
- モデルが国籍と地理の関係をベクトル空間内に捉えたことを示している
- Word2Vecは16億語のコンテンツで学習されており、現在の埋め込みモデルははるかに大きなデータセットで学習され、より豊かな関係を捉える
LLMツールで埋め込みを計算する
- LLM は、大規模言語モデルを扱うためのコマンドラインツール兼Pythonライブラリである
pip install llmまたはbrew install llmでインストールできる- デフォルトではOpenAI APIと一緒に使える
- プラグインをインストールすると、新しい言語モデルや埋め込みモデルを追加できる
llm-sentence-transformersプラグインは、SentenceTransformers ライブラリをラップしたプラグインであるall-MiniLM-L6-v2モデルをHugging Faceからダウンロードしてローカルで使えるllm embedコマンドは、文1つをJSON数値配列として出力する
- 埋め込みは単独の数値配列だけでは大きな意味はなく、保存して比較してこそ有用になる
llm embed-multiは、複数のコンテンツを一度に埋め込み、コレクション というSQLiteテーブルに保存できる- 例のコマンドは、ホームディレクトリ配下のすべての
README.mdファイルを見つけてreadmesコレクションに保存する --storeオプションは、元のテキストもSQLiteテーブルに一緒に保存する- 実行結果では16,796個の
README.mdファイルが保存され、ローカルコンピュータで約30分かかった
- 例のコマンドは、ホームディレクトリ配下のすべての
意味検索と “vibes-based search”
llm similarコマンドは、保存された埋め込みコレクションから入力文と類似した項目を探すsqlite backup toolsという文でreadmesコレクションを検索すると、sqlite-diffable、sqlite-dump、sqlite-generate、sqlite-history、sqlite-utilsなど、SQLiteバックアップや関連プロジェクトのREADMEが上位に出てくる- 結果文書に “backups” という単語が直接含まれている保証はない
- コンテンツが検索語と 意味的に類似 していれば結果になりうる
- この方式は意味検索であり、原文ではこれを vibes-based search と呼んでいる
- 正確なテキスト一致だけでは利用者が探しているものを常に見つけられるとは限らず、さまざまなコンテンツ検索エンジンに有用である
コード埋め込み: SymbexとDatasette
- Symbex は、Pythonコードベースのシンボルを探索するツールである
- Python関数やクラスを素早く見つけてLLMに渡すために作られた
- その後、コードベース内のすべての関数埋め込みを計算してコード検索エンジンを作れるようになった
- Symbexは見つけたシンボルをJSONまたはCSVで出力でき、その形式は
llm embed-multiの入力として利用できる - Datasetteプロジェクト内のすべての関数とクラスメソッドを埋め込む例では、gte-tiny モデルを使う
gte-tinyは60MBのファイルであるsymbex '*' '*:*' --nlは、現在のディレクトリの関数とクラスメソッドをnewline-delimited JSONで出力するllm embed-multi ... --format nlは、その出力をそのまま入力として受け取り埋め込む
- その後、Datasetteと datasette-llm-embed プラグインを使って、SQLでコードの意味検索を実行できる
- SQLiteは、複数のツールを束ねる 統合ポイント として使われる
- コードから関数を抽出する
- 埋め込みモデルに通す
- 結果をSQLiteに記録する
- SQLで検索する
CLIPでテキストと画像を同じ空間に埋め込む
- CLIP は、OpenAIが2021年1月に公開したモデルで、テキストと画像の両方を埋め込める
- 中核は、テキストと画像を 同じベクトル空間 に入れる点にある
- “dog” という文字列の埋め込み位置と犬の写真の埋め込み位置が同じ空間で近くなる
- テキストで関連画像を探したり、画像で関連テキストを探したりできる
- ブラウザで動くCLIPデモ はObservable notebookで作られており、CLIPモデルをブラウザ内で実行する
- ページは158MBのリソースを読み込む
- CLIPテキストモデルは64.6MB、画像モデルは87.6MBである
- 海辺の写真に対して、テキストごとの類似度スコアを計算した例がある
beach: 26.946%city: 19.839%sunshine: 24.146%california beach: 27.427%
- 任意の写真と単語1つの類似度を問うこと自体よりも、その上に検索インターフェースを作ることが重要である
Faucet Finder: CLIPベースの画像検索
- Faucet Finder は、浴室の蛇口写真を探すためのカスタム検索ツールである
- Drew Breunigは、蛇口サプライヤーから20,000枚の蛇口写真を収集し、CLIP埋め込みを計算した
- 実装にはLLMと llm-clip プラグインが使われた
- Datasetteでデプロイされた
- このツールにより、特定の蛇口と見た目が似た別の蛇口を見つけられる
- 高価な蛇口が気に入ったら、見た目が似たより安価な選択肢を探せる
- Drewのデモは、事前計算済みの埋め込みを使うことで、サーバー上でCLIPモデルを実行しなくても類似結果を表示する
- その後、サーバー側のCLIPモデルを Fly.io にデプロイし、テキスト文字列埋め込みAPIと蛇口埋め込みテーブルAPIを組み合わせたObservable notebookデモが作られた
- “gold purple” のような検索語で蛇口画像を意味ベースで検索できる
クラスタリングと2D可視化
- 埋め込みは、関連記事推薦や意味検索以外にも クラスタリング に使える
- llm-cluster は、scikit-learnの sklearn.cluster を使ってクラスタリングを実装したプラグインである
- GitHub issues APIと paginate-json を使って
simonw/llmリポジトリのissueタイトルからllm-issuesコレクションを作り、10個のクラスタを生成できる llm cluster llm-issues 10 --summaryオプションは、クラスタテキストをLLMに渡して説明的な名前を生成する- 例として “Log Management and Interactive Prompt Tracking”、“Continuing Conversation Mechanism and Management” のような名前が出てくる
- 高次元空間は可視化が難しいため、主成分分析(PCA) によって次元を減らせる
- Matt Webbは、BBC
In Our Timeポッドキャストのエピソード説明をOpenAI埋め込みで表現し、PCAで2D可視化を作成した - 1,536次元を2次元に減らしても、歴史上の戦争関連エピソードや現代科学の発見関連エピソードが互いに近く現れる
- Matt Webbは、BBC
平均位置で文を分類する
- 埋め込みは分類にも使える
- 特定の方法で分類された埋め込みグループの平均位置をまず計算する
- 新しいコンテンツの埋め込みがそれらの位置のどこに近いかを比較してカテゴリを割り当てる
- Amelia Wattenbergerの Getting creative with embeddings は、文が具体的か抽象的かをスコア化する事例である
- 具体的な文と抽象的な文のサンプルを作り、各グループの平均位置を計算する
- 新しい文は、2つの平均位置のどちらに近いかに応じてスコアを受け取る
- このスコアは、文がどれだけ抽象的または具体的かをゆるやかに表す色にも変換できる
RAG: 個人文書と社内文書の質疑応答
- ChatGPTを使ったことがある人は、個人ノートや社内文書をもとに質問へ答えさせる方法を知りたがる
- 答えは高価なカスタムモデル学習ではなく、既製のLLMと 検索拡張生成(RAG) の組み合わせかもしれない
- RAGの基本手順は単純である
- ユーザーが質問する
- 個人文書の中から質問に関連しそうなコンテンツを検索する
- LLMのサイズ制限を守りつつ、関連抜粋と元の質問をプロンプトに入れる
- LLMが与えられた追加コンテンツをもとに回答する
- 一般的なサイズ制限は3,000〜6,000語程度である
- RAGで難しいのは、プロンプトに入れるべき最良の抜粋を見つけることだ
- 埋め込みベースの意味検索は、関連性が高そうなコンテンツを集めるのに適している
E5-large-v2でブログベースのオフラインQ&Aを実装する
- ブログコンテンツを使ったRAGの例では、E5-large-v2 を利用する
- 質問文と回答文は文法が異なるため、質問が回答を含む文書と常に意味的に近く捉えられるとは限らない
- E5-large-v2は2種類のコンテンツをサポートする
- factual sentence は phrase として埋め込む
- question は query として埋め込む
- これはCLIPが画像とテキストを同じ空間に入れる方式に似ている
- ブログの19,000個の段落をphraseとして埋め込み、質問をqueryとして埋め込んで、答えに近い段落を探す
- 例では、BashのワンライナースクリプトでRAGを実装する
llm similarで関連段落を探すjqでコンテンツを抽出する- ローカルノートPCで動くLlama 2 Chat 7Bモデルに質問と段落を渡す
What is shot-scraper?という質問に対して、shot-scraperはPlaywrightをラップするPythonユーティリティであり、コマンドラインインターフェースとYAMLベースの設定フローによってWebページのスクリーンショットやJavaScriptベースのスクレイピングを自動化するという回答を生成した- 生成された回答は、既存ブログコンテンツの正確な文一致ではなかった
実務で調整できる選択肢
- LangChainは、LLM上の機能実装のためのフレームワークであり、RAGはLangChainの中核機能の1つである
- 同じ機能をLangChain上に構築することもできるが、LangChainを理解するにはかなりの投資が必要である
- ここでは、すべてを解決する単一フレームワークよりも、組み合わせて使える小さなツール群が好まれている
- 距離関数としてはコサイン類似度が標準的に使われる
- 他の距離関数はまだ試していない
- RAGには、距離関数、埋め込みモデル、プロンプト戦略、LLMなど調整可能な要素が多い
- 例はいずれも最大で約20,000件の埋め込み規模で、この程度なら全件に対するbrute forceのコサイン類似度計算でも妥当な時間で結果を得られる
- 10億オブジェクトのようなさらに大規模なデータでは、ベクトルデータベースや既存データベース拡張が選択肢になる
- SQLiteには sqlite-vss がある
- PostgreSQLには pgvector がある
- Facebookの FAISS も実験に使われており、これを利用するDatasetteプラグイン datasette-faiss もある
- 今後期待される流れは、マルチモーダルモデル とより小型のモデルである
- Facebookの ImageBind は、画像、テキスト、音声、深度、熱、IMUデータの6つのモダリティの共同埋め込みを学習する
- 60MBの
gte-tinyのように小型化するモデルは、制約のあるデバイスやブラウザでの実行可能性を高める
さらに読む
- What are embeddings? by Vicki Boykis
- Text Embeddings Visually Explained by Meor Amer for Cohere
- The Tensorflow Embedding Projector: 埋め込み空間を探索するインタラクティブツール
- Learn to Love Working with Vector Embeddings: Pineconeのベクトル埋め込みチュートリアル集
1件のコメント
Hacker News のコメント
この記事を投稿したあと、埋め込みをより低いレベルで理解するのに役立つ資料をいくつか見つけた
私の記事は意図的にかなり高いレベルで、主に応用に焦点を当てている
Cohere の Text Embeddings Visually Explained: https://txt.cohere.com/text-embeddings/
Tensorflow Embedding Projector ツール: https://projector.tensorflow.org/
Vicki Boykis の What are embeddings? も読む価値がある: https://vickiboykis.com/what_are_embeddings/
ページ下部の “further reading” に追加する予定
埋め込みを使って関連記事へのエンゲージメントを高めた。個人的には、埋め込みは過小評価されている強力なツールだと思う
文書や抜粋の間を類似度で探索したり、逆にユニークなコンテンツを見つけたりするのに使え、ハルシネーションを心配しなくてよいのでかなり「安全」でもある
埋め込みがどのように作られるのかも興味深いかもしれない。たとえば、学習後に分類層を切り落とす方式や EfficientNet のようなアプローチがある
機械学習の中核的な基盤になりつつある
コンピュータビジョンとビジュアル SLAMアルゴリズムでは、埋め込みが場所認識の事実上の標準的手法になっており、この記事の内容と非常によく似ている
「bag-of-word place recognition」と呼ばれ、最近のほぼすべてのオープンソースライブラリで使われている
要点は、各画像を特徴抽出・記述子パイプラインに通し、上位 N 個の特徴を含むベクトルへ「埋め込む」こと
カメラが移動している間に keyframe という画像データベースを作り、画像ははるかに低次元のベクトルとして保存される
その後、すべての画像でデータベースにクエリを投げ、コサイン類似度のような方法でベクトルデータベースから最適なマッチを探す
マッチが見つかれば、クエリ画像とマッチした画像の間のステレオ制約を計算して地図を更新できる
元論文は [1] で、最も有名な実装は https://github.com/dorian3d/DBoW2
[1]: https://www.google.com/search?client=firefox-b-d&q=Bags+of+B...
優れた入門用の参考資料だ
以前、自分で iOS のメモアプリを作ったが、既存の全文検索に埋め込みを追加するのは 1) 驚くほど簡単で、2) 最初に予想していたよりはるかに強力だった
“dog” を検索すれば “canine” が入ったメモも出るだろうとは分かっていたが、“自分が好きそうなペット” のような検索で、ポジティブな感情を含む複数の動物関連メモが拾われるのを実際に試して初めて理解した
それが最初の大きな「なるほど」の瞬間だった
当時は Supabase の DocsGPT PR がサンプルコードとして役に立った: https://github.com/supabase/supabase/pull/12056
多くのアプリケーションは名前や固有名詞に大きく依存しており、文脈が不足している場合も多い
飼い犬を説明なしに名前だけで呼ぶと、特定の埋め込みモデルでは拾えないかもしれない
人、場所、通り名のような固有名詞は、パーソナライズやドメイン特化検索を固定するうえで非常に重要になり得るが、汎用言語モデルはそれを知らない
この問題に対処する具体的な方法があるのか気になる
今いちばん大きな疑問は、どれだけのテキストを 1 つの埋め込みにするかだ
文ごとにするか、それともメモアプリの 1 ページに属する文ブロック全体を 1 つにするかで悩んでいる
単語埋め込みの代表例は、有名な King - Man + Woman = Queen である
ベクトル空間ではうまく機能するが、2次元に投影すると視覚的にはあまりピンとこない
私の経験では、PCA、MDS、t-SNE のいずれも同様だった: https://bhugueney.gitlab.io/test-notebooks-org-publish/jupyt...
ブラウザ上で単語埋め込みを実行する JupyterLite Notebook で、スマートフォンでは実行しないほうがよい
単語埋め込みの代表例を見やすく可視化する方法を知っているか気になる
本当に直交性が欲しければ Gram-Schmidt を使えばよい
3次元では、Z軸を “king”-“queen” とする軸をもう1本置けるし、直交化した版はモデルが見ている距離の概念により近い
2次元では “king”-“man”+“woman” を計算したときに “queen” からどれだけ外れているかは示せないが、残りの距離は正確に得られる
3次元では正確な距離を出せるはずだ
“queen” は通常、X="king"-"man"+"woman" に最も近い埋め込みを持つ単語として選ばれる
2次元チャートに次に近い単語をいくつか表示し、各単語に2次元平面からの直交距離を付けることもできる
そうすれば、“queen” は X からの二乗距離と平面からの二乗直交距離の和が最小の単語であるはずなので、目でもある程度確認できる
「4次元は可視化できない……少なくとも私はできない。brane が3つしかないので」というようなもので、branes と brains を使った言葉遊びだった
後で ChatGPT はそれが作り話だと認め、謝罪した
続いて John von Neumann、H. G. Wells、Ian Stewart の引用も出してきて、最後には「4次元を可視化するには、3次元を可視化してから『n+1』と言えばよい」というような答えを出した。記憶にあるジョークに最も近かったが、あまり面白くはなかった
そこで Deepak Chopra 風に高次元空間を可視化する幻覚的な引用を作ってみてと頼んだところ、septillion-dimensional embeddings、Hilbert space、Poincaré conjecture、Heisenberg uncertainty principle、Shannon entropy といった表現を混ぜた、もっともらしい偽の引用を大量に出してきた
実用的な三角法でよくあるミスは、不要な 平方根計算 をしてしまうことだ
サンプルコードの
magnitude_a = sum(x * x for x in a) * 0.5とmagnitude_b = sum(x * x for x in b) * 0.5には*0.5は不要コサインを比較するだけなら二乗値を比較すればよいので、コストの高いルート計算を避けられる
同様に、楕円曲線暗号でも逆元計算のような高価な演算はできるだけ後回しにしたり、2点を比較するだけなら標準値の計算自体を避けたりする
そうでなければ低レベルの SIMD コード に置き換えていただろう
dot_product = sum(x * y for x, y in zip(a, b))とは、なぜこんなことをして ベクトル化された numpy 演算 を使わないのか不思議だ「複数バージョンのコサイン類似度コードを ChatGPT に書かせた」というくだりを見て納得した
第一に、人に説明するときには numpy の構文はむしろ邪魔になると感じる
第二に、numpy は最も軽い依存関係ではない
性能が必要なときは使うが、デフォルトの選択肢にはしたくない
Show HN の投稿、ProductHunt のスタートアップ、YC 企業、Github リポジトリの中で LLM 埋め込み に関連するものを見たいなら、リリースしたばかりの LLM-Embeddings-Based Search Engine MVP ですばやく見つけられる
https://payperrun.com/%3E/search?displayParams={%22q%22:%22L...
複数の フィルターボタン を押すと検索結果がすぐ更新されると思っていて、検索し直す必要があるとは思わなかった
なぜそうしたのかは理解できる
ここ数か月で読んだ「AI」関連のものの中で最も興味深い
一覧で 埋め込みモデル を見るたびに、それが何なのか気になっていたし、なぜ皆がベクトルDBの話をしているのかも気になっていた
長く続けているサイドプロジェクトにすぐ適用する方法が思い浮かぶ
すべての文書に埋め込みがあれば、ユーザーデータの有用なクラスタリングが現実的に可能になるかもしれない
実際に埋め込みを近似最近傍やクラスタリング以外に使ったことがある人がいるのか気になる
思い浮かぶ可能性としては、任意の軸への射影・インデックス化・ソートがある。例えば「熱い-冷たい」「幸福-悲しみ」「SF-リアリズム」「文学性-商業性」のような軸
埋め込み空間でSVM式の分類をしたり、word2vec式の推論である woman-man+king=queen をしたり、LLMの1つの層を取り出したりする以外にも、埋め込みを直接学習させる方法もあるはず
対照学習が使われているのは知っているが、関数ニューラルネットワークと一緒に埋め込みを学習し、関数方程式を生成して平均二乗誤差損失を計算するなど、ほかの方法も探求する価値がありそう
セマンティック検索にあまりに集中しているように見えて驚くし、きっと他にも興味深い応用があるはず
1つ目と3つ目は実質的に同じ
コンピュータビジョンでは、写真にメガネを追加するように、意味的に画像を変えたいことがあり、Google広告で見かける作業がその例
こうした作業は潜在空間で行われる
正規化フローでは空間をガウス分布に変換するため、特に分かりやすい
拡散モデルも近似手法として似たことをするが、可逆ではなく、戻すことはできる
操作したい画像・文章・データを射影し、ガウス空間で操作してから対象空間に戻す
ただし、埋め込みという言葉があまりにも多くの意味を持つ過負荷な用語なので、お互いに混乱しているだけかもしれない
離散的な整数トークンを連続的な浮動小数点に変える最初のブロックだけを考えているのかもしれない
しかしその埋め込みも学習されるので、ルックアップテーブルのようになっても、依然としてニューラルネットワークの過程
この空間でSVMを使うこともある
潜在空間に似ているが、もう少し抽象的だと見ている
少なくとも埋め込みは単射であるべき。数学的にはそうだが……
埋め込みを直接学習させるというのは、文字通り元祖の埋め込みモデルであるWord2Vecのこと
化学・生化学の名称におけるハイフン表記、非ハイフン表記、スペース区切り表記のような変種や略語を多く見つけた
おそらく技術用語辞書も作れたと思う
定義までどこまで行けたかは分からないが、ベクトルだけでは限界があっても出発点にはなる
他の人たちもこの方式で辞書構築をしていた可能性が高い
埋め込みを触ってみて、いくつか本番環境でのユースケースも作ってみたが、優れた応用をたくさん可能にしてくれる素晴らしいツール
しかし特定ドメインで作っていると、既製の埋め込みモデルの限界にぶつかる
既製モデルは次元が多いが、そのうちある次元は自分のアプリケーションの分類、コンテンツ類似度、クラスタリングなどに重要で、ある次元は重要でないことがある
言い換えると、関心のない次元で近いために、2つのベクトルが近く見えることがある
埋め込みモデルのファインチューニングのための、より良いツールと文献が出てくることを期待している
こういうツールは昔からあり、例えばデータに少しラベルを付けた後、埋め込み空間上で分類用SVMを学習させればよい