2024年2月4日日曜日

LangChain の Embddings (ベクトル化) を試す

LangChain の Embddings (ベクトル化) を試す

概要

LangChain の Embeddings を試してみました
Embeddings は簡単に言えばベクトル化 (数値化) で特定のテキストをベクトル化します
ベクトル化にはモデルが必要でそのモデルに応じてベクトル化する次元数と数値が決まります

環境

  • macOS 11.7.10
  • Python 3.11.6
  • langchain 0.1.4
    • langchain-community 0.0.17
    • sentence-transformers 2.3.1
    • faiss-cpu 1.7.4

インストール

  • pipenv install langchain-community
  • pieenv install sentence-transformers

まずは動かす

まずはやってみましょう
ベクトル化するモデルは HaggingFace にあるものを使います
その場合は HuggingFaceEmbeddings というクラスを使います
ちなみにベクトル化するためのモデルは ChatGPT や AzureOpenAI なども提供しておりそれらを使う場合は WebAPI でコールできるので手元にベクトル化用のモデルを持ってくる必要はありません

import pprint

from langchain_community.embeddings import HuggingFaceEmbeddings

# ベクトル化するテキスト
text = "これは、テストドキュメントです。\nそうですこれはテストです。"

# HuggingFaceEmbeddings を使って HuggingFace にあるモデルを使ってテキストをベクトル化する
# モデルを指定しない場合 https://huggingface.co/sentence-transformers/all-mpnet-base-v2 のモデルが使われる
# /path/to/.cache/huggingface/hub/models--sentence-transformers--all-mpnet-base-v2 に保存されている
embeddings = HuggingFaceEmbeddings()
query_result = embeddings.embed_query(text)
doc_result = embeddings.embed_documents([text])

# ベクトル化された数値の確認
# all-mpnet-base-v2 の場合次元数は768で固定、どんなテキストを渡しても同じ次元数になります(たとえ一文字でも
# query の場合は一次元、doc の場合は2次元の配列になる
print(len(query_result))
pprint.pprint(query_result)
print(len(doc_result[0]))
pprint.pprint(doc_result)

実行するとわかりますがずらーっと数字が並ぶのが確認できます
何の数字だかよくわかりませんがとりあえずベクトル化すると数字になることがわかりました

また同じテキストであれば何度実行しても同じ数値になることが確認できると思います

ベクトルを保存する

ベクトルの保存は faiss と呼ばれる facebook が提供する類似度検索ツール方式で保存します
保存はファイルでされます

他にも chromadb などファイル以外でもベクトル情報を検索、保存できるツールがあるので興味があれば調べてみてください

また今回は faiss 上での検索は cpu のみを使用するので faiss-cpu というライブラリを使っています

import pprint

from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS

# ベクトル化するテキスト
text = "これは、テストドキュメントです。\nそうですこれはテストです。"

# HuggingFaceEmbeddings を使って HuggingFace にあるモデルを使ってテキストをベクトル化する
# モデルを指定しない場合 https://huggingface.co/sentence-transformers/all-mpnet-base-v2 のモデルが使われる
# /path/to/.cache/huggingface/hub/models--sentence-transformers--all-mpnet-base-v2 に保存されている
embeddings = HuggingFaceEmbeddings()
query_result = embeddings.embed_query(text)
doc_result = embeddings.embed_documents([text])

# ベクトル化された数値の確認
# all-mpnet-base-v2 の場合次元数は768で固定、どんなテキストを渡しても同じ次元数になります(たとえ一文字でも
# query の場合は一次元、doc の場合は2次元の配列になる
print(len(query_result))
pprint.pprint(query_result)
print(len(doc_result[0]))
pprint.pprint(doc_result)

# テキストを HuggingFaceEmbeddings を使ってベクトル化し保存
# やっていることは embed_documents と同じ (はず
vectorstore = FAISS.from_texts([text], embeddings)
vectorstore.save_local("./vectorstore")

# ファイルに保存したベクトル情報の呼び出し
new_index = FAISS.load_local("./vectorstore", embeddings)

# faiss を使って類似度検索してみる
# ベクトル化した文章が少ないのでおそらくどんな単語で検索してもテキストが検索される (はず
docs = new_index.similarity_search("hawksnowlog")
pprint.pprint(docs)

せっかくなので最後に作成した faiss のインデックス情報を使って類似度検索もしています

保存に成功すると以下のようなファイルが生成されていることが確認できます

tree vectorstore/
vectorstore/
├── index.faiss
└── index.pkl

0 directories, 2 files

最後に

LangChain の Embeddings 機能を使ってみました
またベクトル化したデータを FAISS というベクトル類似度ツールを使って保存し検索も試してみました

次回は LLM を組み合わせる方法を紹介します

参考サイト

0 件のコメント:

コメントを投稿