跳转到内容

使用GPT文本嵌入和CLIP图像嵌入实现维基百科文章的多模态检索

在本笔记本中,我们将展示如何使用LlamaIndex构建一个多模态检索系统。

维基百科文本嵌入索引:使用OpenAI为文本生成GPT文本嵌入

维基百科图像嵌入索引:来自OpenAI的CLIP嵌入用于图像

查询编码器:

  • 使用GPT嵌入对文本索引进行编码器查询文本
  • 使用CLIP嵌入对图像索引进行编码器查询文本

框架:LlamaIndex

步骤:

  1. 下载维基百科文章的文本和图像原始文件
  2. 使用GPT嵌入为向量存储构建文本索引
  3. 使用CLIP嵌入为向量存储构建图像索引
  4. 使用不同的查询编码嵌入和向量存储同时检索相关文本和图像
%pip install llama-index-vector-stores-qdrant
%pip install llama_index ftfy regex tqdm
%pip install git+https://github.com/openai/CLIP.git
%pip install torch torchvision
%pip install matplotlib scikit-image
%pip install -U qdrant_client

从维基百科加载和下载包含文本和图像的多模态数据集

Section titled “Load and Download Multi-Modal datasets including texts and images from Wikipedia”

解析维基百科文章并保存到本地文件夹

from pathlib import Path
import requests
wiki_titles = [
"batman",
"Vincent van Gogh",
"San Francisco",
"iPhone",
"Tesla Model S",
"BTS",
]
data_path = Path("data_wiki")
for title in wiki_titles:
response = requests.get(
"https://en.wikipedia.org/w/api.php",
params={
"action": "query",
"format": "json",
"titles": title,
"prop": "extracts",
"explaintext": True,
},
).json()
page = next(iter(response["query"]["pages"].values()))
wiki_text = page["extract"]
if not data_path.exists():
Path.mkdir(data_path)
with open(data_path / f"{title}.txt", "w") as fp:
fp.write(wiki_text)

解析维基百科图片与文本。加载至本地文件夹

Section titled “Parse Wikipedia Images and texts. Load into local folder”
import wikipedia
import urllib.request
image_path = Path("data_wiki")
image_uuid = 0
# image_metadata_dict stores images metadata including image uuid, filename and path
image_metadata_dict = {}
MAX_IMAGES_PER_WIKI = 30
wiki_titles = [
"San Francisco",
"Batman",
"Vincent van Gogh",
"iPhone",
"Tesla Model S",
"BTS band",
]
# create folder for images only
if not image_path.exists():
Path.mkdir(image_path)
# Download images for wiki pages
# Assing UUID for each image
for title in wiki_titles:
images_per_wiki = 0
print(title)
try:
page_py = wikipedia.page(title)
list_img_urls = page_py.images
for url in list_img_urls:
if url.endswith(".jpg") or url.endswith(".png"):
image_uuid += 1
image_file_name = title + "_" + url.split("/")[-1]
# img_path could be s3 path pointing to the raw image file in the future
image_metadata_dict[image_uuid] = {
"filename": image_file_name,
"img_path": "./" + str(image_path / f"{image_uuid}.jpg"),
}
urllib.request.urlretrieve(
url, image_path / f"{image_uuid}.jpg"
)
images_per_wiki += 1
# Limit the number of images downloaded per wiki page to 15
if images_per_wiki > MAX_IMAGES_PER_WIKI:
break
except:
print(str(Exception("No images found for Wikipedia page: ")) + title)
continue
import os
os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"
import qdrant_client
from llama_index.core import SimpleDirectoryReader
from llama_index.vector_stores.qdrant import QdrantVectorStore
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.core.indices import MultiModalVectorStoreIndex
# Create a local Qdrant vector store
client = qdrant_client.QdrantClient(path="qdrant_db")
text_store = QdrantVectorStore(
client=client, collection_name="text_collection"
)
image_store = QdrantVectorStore(
client=client, collection_name="image_collection"
)
storage_context = StorageContext.from_defaults(
vector_store=text_store, image_store=image_store
)
# Create the MultiModal index
documents = SimpleDirectoryReader("./data_wiki/").load_data()
index = MultiModalVectorStoreIndex.from_documents(
documents,
storage_context=storage_context,
)
/Users/haotianzhang/llama_index/venv/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm

从维基百科绘制已下载的图像

Section titled “Plot downloaded Images from Wikipedia”
from PIL import Image
import matplotlib.pyplot as plt
import os
def plot_images(image_metadata_dict):
original_images_urls = []
images_shown = 0
for image_id in image_metadata_dict:
img_path = image_metadata_dict[image_id]["img_path"]
if os.path.isfile(img_path):
filename = image_metadata_dict[image_id]["filename"]
image = Image.open(img_path).convert("RGB")
plt.subplot(8, 8, len(original_images_urls) + 1)
plt.imshow(image)
plt.xticks([])
plt.yticks([])
original_images_urls.append(filename)
images_shown += 1
if images_shown >= 64:
break
plt.tight_layout()
plot_images(image_metadata_dict)

png

def plot_images(image_paths):
images_shown = 0
plt.figure(figsize=(16, 9))
for img_path in image_paths:
if os.path.isfile(img_path):
image = Image.open(img_path)
plt.subplot(2, 3, images_shown + 1)
plt.imshow(image)
plt.xticks([])
plt.yticks([])
images_shown += 1
if images_shown >= 9:
break
test_query = "who are BTS team members"
# generate retrieval results
retriever = index.as_retriever(similarity_top_k=3, image_similarity_top_k=5)
retrieval_results = retriever.retrieve(test_query)
from llama_index.core.response.notebook_utils import display_source_node
from llama_index.core.schema import ImageNode
retrieved_image = []
for res_node in retrieval_results:
if isinstance(res_node.node, ImageNode):
retrieved_image.append(res_node.node.metadata["file_path"])
else:
display_source_node(res_node, source_length=200)
plot_images(retrieved_image)

节点ID: e30e1817-4e31-4047-be5d-37502560920c
相似度: 0.808149809808292
文本: BTS(韩语:방탄소년단;罗马化:Bangtan Sonyeondan;字面意思:防弹少年团),亦被称为Bangtan Boys,是于2010年成立的韩国男子音乐组合。该组合成员包括Jin、Suga、J-Hope、RM、Jimi…

节点ID: 024f3296-37c8-46d5-a184-2f78c621a99f
相似度: 0.7987048642063129
文本: === 粉丝圈 === 根据金亨均的说法,BTS的崛起得益于YouTube音乐视频节目和消费的大幅增长,以及偶像帝国的到来,包括周边商品…

节点ID: c564ccf4-a94f-408f-8b21-224538dc2e94
相似度: 0.7838098925118134
文本: == 历史 ==

=== 2010–2014年:组建与早期岁月 === 防弹少年团于2010年组建,当时Big Hit娱乐公司首席执行官房时赫希望围绕RM(金南俊)组建一个嘻哈团体,当时他还是一名大学生…

png

test_query = "what are Vincent van Gogh's famous paintings"
# generate retrieval results
retriever = index.as_retriever(similarity_top_k=3, image_similarity_top_k=5)
retrieval_results = retriever.retrieve(test_query)
retrieved_image = []
for res_node in retrieval_results:
if isinstance(res_node.node, ImageNode):
retrieved_image.append(res_node.node.metadata["file_path"])
else:
display_source_node(res_node, source_length=200)
plot_images(retrieved_image)

节点ID: e002927c-0bf5-482b-a0a1-0ee2f3cd48f9
相似度: 0.8675476190545354
文本: 文森特·威廉·梵高(荷兰语:[ˈvɪnsɛnt ˈʋɪləɱ vɑŋ ˈɣɔx];1853年3月30日-1890年7月29日)是一位荷兰后印象派画家,他是艺术史上最著名和最具影响力的人物之一…

节点ID: 69ef1c64-a5b4-468c-a58c-7d36151961a7
相似度: 0.8661792475490765
文本: ==== 花卉 ====

梵高绘制了多幅带有花卉的风景画,包括玫瑰、丁香、鸢尾花和向日葵。部分作品反映了他对色彩语言的兴趣,同时也展现了日本浮世绘…

节点ID: f971a611-a8b9-48b4-a81b-d3856438aab8
相似度: 0.8616832203971132
文本: ==== 肖像 ====

梵高曾说肖像画是他最大的兴趣。"在我的职业中,最令我着迷的,远超过其他一切的",他在1890年写道,"是肖像画,那…

png

test_query = "what is the popular tourist attraction in San Francisco"
# generate retrieval results
retriever = index.as_retriever(similarity_top_k=3, image_similarity_top_k=5)
retrieval_results = retriever.retrieve(test_query)
retrieved_image = []
for res_node in retrieval_results:
if isinstance(res_node.node, ImageNode):
retrieved_image.append(res_node.node.metadata["file_path"])
else:
display_source_node(res_node, source_length=200)
plot_images(retrieved_image)

节点ID: 8c14be3e-345a-4764-9b64-dacff771bc04
相似度: 0.8689195893277072
文本内容: === 旅游与会展 ===

旅游业是旧金山最重要的私营产业之一,占该市就业岗位的七分之一以上。这座城市频繁被描绘…

节点ID: 22aa7d86-017f-433d-98dc-4007d9f67c17
相似度: 0.8452524742723133
文本: === LGBT ===

旧金山长期以来一直有着对LGBT友好的历史。它是美国第一个女同性恋权利组织"比利提斯之女"的所在地;也是首位公开同性恋身份竞选公职的人……

节点ID: 3846a17a-79d8-415e-9bcf-76c818b27203
相似度: 0.8329496262980858
文本: == 公园与休闲 ==

旧金山的多个公园及几乎所有海滩构成了金门国家休闲区的一部分,这是美国国家公园系统中访问量最大的区域之一…

png

test_query = "which company makes Tesla"
# generate retrieval results
retriever = index.as_retriever(similarity_top_k=3, image_similarity_top_k=5)
retrieval_results = retriever.retrieve(test_query)
retrieved_image = []
for res_node in retrieval_results:
if isinstance(res_node.node, ImageNode):
retrieved_image.append(res_node.node.metadata["file_path"])
else:
display_source_node(res_node, source_length=200)
plot_images(retrieved_image)

节点ID: 214c61be-dad6-403c-b301-bc2320b87e7a
相似度: 0.7808396168295813
文本: 特斯拉Model S是由特斯拉公司自2012年起生产的电池电动全尺寸豪华轿车,采用掀背式车身设计。Model S采用电池供电的双电机全轮驱动布局,…

节点ID: 15b737b4-90e3-443a-87aa-13a7d7e80b87
相似度: 0.7807424063856144
文本: === P100D === P100D在测功机上的输出功率为439千瓦(589马力),扭矩为1,248牛·米(920磅力·英尺)。截至2017年3月,P100D是全球加速最快的量产车,NHRA滚动起步加速至6…

节点ID: e134452b-3031-47b0-a20c-df4fe32f1bcf
相似度: 0.7754107325086438
文本: === 召回记录 === 截至2021年12月,特斯拉已对Model S车型进行过七次召回: 2013年6月14日,特斯拉召回了2013年5月10日至2013年6月8日期间生产的Model S车辆,原因是存在不规范的制造工艺…

png

test_query = "what is the main character in Batman"
# generate retrieval results
retriever = index.as_retriever(similarity_top_k=3, image_similarity_top_k=5)
retrieval_results = retriever.retrieve(test_query)
retrieved_image = []
for res_node in retrieval_results:
if isinstance(res_node.node, ImageNode):
retrieved_image.append(res_node.node.metadata["file_path"])
else:
display_source_node(res_node, source_length=200)
plot_images(retrieved_image)

节点ID: ff85b136-08c8-465d-96f5-a554c65067d8
相似度: 0.8461934674061043
文本: ==== 人物性格 ==== 蝙蝠侠的主要性格特征可概括为“财富;体能优势;推理能力与执念”。蝙蝠侠漫画的细节与基调随时间推移不断演变…

节点ID: 55f5b842-6fd0-4e45-aef2-27f74f670e82
相似度: 0.8229623965891602
文本: 蝙蝠侠是出现在DC漫画公司出版的美国漫画书中的超级英雄。该角色由艺术家鲍勃·凯恩和作家比尔·芬格创作,首次亮相于漫画书第27期…

节点ID: cb4755db-088e-46af-92b2-3a4a3649d9fe
相似度: 0.8218281955244808
文本: === 敌人 ===

蝙蝠侠面对各种各样的敌人,从普通罪犯到古怪的超级反派。其中许多反派映射了蝙蝠侠角色特质与发展历程的某些方面,往往带有悲剧性…

png