LlamaIndex + Weaviate + Llavaを使って、不毛なことをする。
前提
まず、WeaviateとLlavaを試してみたいっていうのが大前提にあります。
具体的には以下2つです、これさえできればそれでいいです。
①WeaviateにPDFを取り込んで、質問に答えてもらう。
②Llavaに画像を取り込んで、その画像が何か答えてもらう。
やりたいこと
Weaviateに読み込んだPDFから、Llavaに取り込んだ画像についての情報を取り出す。
今回Weaviateに取り込むPDFは、こちらです。
CyberAgent第26回定時株主総会2023年9月期質疑応答の要約
読み物として面白いので選びました。
今回Llavaに画像の内容を答えてもらうための画像はこれです。
(以下Youtubeのアイコンから引用)
グランブルーファンタジーです。
上記PDFにグランブルーファンタジーに関する質疑応答があるためです。
出来レースです。
Llavaにグランブルーファンタジーの画像を渡して、グランブルーファンタジーだと認識してもらい、グランブルーファンタジーに関してPDFを検索するという不毛なことをします。
実際サービスとして提供するなら、PDF読み込んで、そこからよく出てくる固有名詞を抽出して、その固有名詞の画像をいくつか画面上に表示して、その画像をクリックすると、その画像に関するPDFの内容が説明されるとかの建付けが良さそうですが、今回はそこまでやりたくないのでこの形になりました。
不毛なことをしている感は拭えないのですが、勘弁してください。
使う技術
LlamaIndex
大規模言語モデル(LLM)を使ったアプリケーション構築を支援するデータフレームワーク。
Weaviate
ベクトル検索およびマルチモーダル検索を実現するためのオープンソースのデータプラットフォーム。
Cohere
今回はWeaviateのClientにPDFを取り込んで、それをEmbeddingする際に使用します。
Llava
GPT-4と同等の能力を持つ大規模マルチモーダルモデル。
- github
https://llava-vl.github.io/ - デモサイト
https://llava.hliu.cc/
Replicate
機械学習モデルをホストし、デプロイし、実行するためのプラットフォーム。
今回Llavaは、このReplicateが公開しているAPI経由で使用しています。
前準備
API KEY取得
今回は、CohereとReplicateのAPI KEYを使用するので、サイトに登録して取得します。
ファイル準備
pythonファイルを作成し、それと同じディレクトリに先程のCyberAgent第26回定時株主総会2023年9月期質疑応答の要約のpdfとグランブルーファンタジーの画像を配置します。
コードを書こう
ライブラリの準備
from llama_index.multi_modal_llms import ReplicateMultiModal
from llama_index.schema import ImageDocument
from llama_index.multi_modal_llms.replicate_multi_modal import (
REPLICATE_MULTI_MODAL_LLM_MODELS,
)
import os
from llama_index import download_loader
from llama_index.node_parser import SimpleNodeParser
import weaviate
from pathlib import Path
from llama_index.vector_stores import WeaviateVectorStore
from llama_index import VectorStoreIndex, StorageContext
API KEY、画像とPDF準備
os.environ["REPLICATE_API_TOKEN"] = "自分のAPIKEY"
os.environ["X-Cohere-Api-Key"] = "自分のAPIKEY"
imageUrl = "./GF.jpg"
pdfPath = "./cyber.pdf"
llava_multi_modal_llm = ReplicateMultiModal(
model=REPLICATE_MULTI_MODAL_LLM_MODELS["llava-13b"],
max_new_tokens=200,
temperature=0.1,
)
Llava
- Replicate経由でLlavaモデルを取得。
- 画像に写っているゲームの名前を端的に答えてもらうためのプロンプトを準備(グランブルーファンタジーが返ってくることを予定)。
- モデルにプロンプトと画像を渡して返答を得る。
llava_multi_modal_llm = ReplicateMultiModal(
model=REPLICATE_MULTI_MODAL_LLM_MODELS["llava-13b"],
max_new_tokens=200,
temperature=0.1,
)
prompt = "Please answer this game name shortly"
llava_response = llava_multi_modal_llm.complete(
prompt=prompt,
image_documents=[ImageDocument(image_path=imageUrl)],
)
Weaviate
- WeaviateのClientを作成。EmbeddingはCohereを使用するのでCohereのAPI KEYを渡す。
- PDFを読み込む
- SimpleNodeParserを使用してPDFのテキストを分割
- Weaviate上で検索用のインデックスを作成
- Llavaからの返答を元に検索を行う
client = weaviate.Client(
embedded_options=weaviate.embedded.EmbeddedOptions(),
additional_headers={
"X-Cohere-Api-Key": os.environ["X-Cohere-Api-Key"]
})
PDFReader = download_loader("PDFReader")
loader = PDFReader()
documents = loader.load_data(file=Path(pdfPath))
parser = SimpleNodeParser()
nodes = parser.get_nodes_from_documents(documents)
vector_store = WeaviateVectorStore(weaviate_client = client, index_name="PDF", text_key="content")
storage_context = StorageContext.from_defaults(vector_store = vector_store)
index = VectorStoreIndex(nodes, storage_context = storage_context)
query_engine = index.as_query_engine()
query = llava_response.text + "について"
response = query_engine.query(query)
print(query)
print(response)
コードを動かした結果
このpythonファイルを作成したところ、以下の結果を得ることができました。
Granblue fantasyについて
「グランブルーファンタジー」は、長く運用しているタイトルで、運営もユーザーの方とコミュニケーションを重要視しています。今後は、リアルの「グラブルフェス 2023」や、コンシューマゲームの提供など、ユーザーの皆様に喜んでいただけるような企画を予定しており、ご意見を活かしながら長く遊んで頂けるように努めていきます。
Llavaは画像をグランブルーファンタジーだと認識し、グランブルーファンタジーに関する文章をWeaviateは返していることが確認できました。
以上
参考
LlamaIndexとWeaviateを一緒に使う例
Llavaに関するウェビナー
Llavaの概要を、Llavaの開発者の方直々に話してくれている
LlamaIndexとLlavaを一緒に使う例
3つ例を出しているが、今回は1番上の例を参考にした。
WeaviateのEmbeddingにcohereを使う方法
おまけ(完成形コード)
# ReplicateMultiModalモデルをインポート
from llama_index.multi_modal_llms import ReplicateMultiModal
# ImageDocumentスキーマをインポート
from llama_index.schema import ImageDocument
# ReplicateMultiModalのモデルをインポート
from llama_index.multi_modal_llms.replicate_multi_modal import (
REPLICATE_MULTI_MODAL_LLM_MODELS, # プレトレインモデル定義
)
# ローダーをダウンロード
from llama_index import download_loader # ローダー取得用関数
# ノードパーサーをインポート
from llama_index.node_parser import SimpleNodeParser # ノードパーサークラス
# Weaviateベクトルストアをインポート
from llama_index.vector_stores import WeaviateVectorStore # Weaviateベクトルストア
# IndexとContextをインポート
from llama_index import VectorStoreIndex, StorageContext # インデックスとコンテキスト
import os # 環境変数やファイルパス操作用
# Weaviateクライアントをインポート
import weaviate # Weaviateへのアクセス
from pathlib import Path # ファイルパスオブジェクト
# 環境変数にAPIキーをセット
os.environ["REPLICATE_API_TOKEN"] = "自分のAPIKEY"
os.environ["X-Cohere-Api-Key"] = "自分のAPIKEY"
# 画像のパスを指定
imageUrl = "./グランブルーファンタジーに関する画像"
# PDFのパスを指定
pdfPath = "./CyberAgent第26回定時株主総会2023年9月期質疑応答の要約のpdf"
# ReplicateMultiModalモデルをインスタンス化
llava_multi_modal_llm = ReplicateMultiModal(
model=REPLICATE_MULTI_MODAL_LLM_MODELS["llava-13b"], # Llava-13bモデル指定
max_new_tokens=200, # 生成トークン数
temperature=0.1, # 確率分布の温度パラメータ
)
# プロンプトを定義
prompt = "Please answer this game name shortly"
# Replicateに画像とテキストのプロンプトを渡し応答を取得
llava_response = llava_multi_modal_llm.complete(
prompt=prompt,
image_documents=[ImageDocument(image_path=imageUrl)], # 画像パス指定
)
# Weaviateクライアントをインスタンス化
client = weaviate.Client(
embedded_options=weaviate.embedded.EmbeddedOptions(), # 埋め込みオプション指定
additional_headers={
"X-Cohere-Api-Key": os.environ["X-Cohere-Api-Key"] # APIキー指定
})
# PDFReaderローダーをダウンロード
PDFReader = download_loader("PDFReader")
# ローダーをインスタンス化
loader = PDFReader()
# PDFを読み込みドキュメントにパース
documents = loader.load_data(file=Path(pdfPath))
# ノードパーサーをインスタンス化
parser = SimpleNodeParser()
# ドキュメントからノードを抽出
nodes = parser.get_nodes_from_documents(documents)
# Weaviateベクトルストアをインスタンス化
vector_store = WeaviateVectorStore(weaviate_client = client, index_name="PDF", text_key="content")
# コンテキストをインスタンス化
storage_context = StorageContext.from_defaults(vector_store = vector_store)
# インデックスをベクトルストアとコンテキストから構築
index = VectorStoreIndex(nodes, storage_context = storage_context)
# インデックスからクエリエンジンを取得
query_engine = index.as_query_engine()
# クエリを定義
query = llava_response.text + "について"
# クエリを実行し結果を取得
response = query_engine.query(query)
# クエリを表示
print(query)
# 結果を表示
print(response)
Discussion