本文探讨了使用 OpenAI CLIP、Claude Sonnet 3.5 和 pgvector 构建 AI 驱动的图片库的 RAG 应用挑战。
译自 Building an AI Image Gallery: Advanced RAG With Pgvector and Claude Sonnet 3.5,作者 Haziqa Sajid。
Anthropic 是人工智能 (AI) 研究领域的一家巨头,主要专注于安全和道德的人工智能系统,它推出了另一个家族成员,Claude Sonnet 3.5。对于许多人来说,Claude 家族的最新成员凭借其智能、速度和成本效益,迅速取代了 GPT-4o 成为默认的大型语言模型 (LLM),树立了新的行业标准。Sonnet 3.5 不仅用途广泛,而且可靠性也使其在开发人员中广受好评。
这些大型语言模型可以理解和处理各种模态,例如图像、文本和音频,使它们能够为从多模态搜索引擎到先进的 AI 驱动的创意工具等各种未来应用提供支持。 在之前的一篇文章中,您了解了如何使用 Claude Sonnet 3.5 和 pgvector 构建一个简单的检索增强生成 (RAG) 应用程序。
在本文中,我们将提高挑战级别,创建一个AI 图像库,让您搜索图像并提出问题。我们将使用相同的工具构建一个 RAG 应用程序:带有 pgvector 的 PostgreSQL 作为向量数据库,以及 Claude Sonnet 3.5 作为 LLM。
RAG,即检索增强生成,是一种 AI 框架,通过将生成式语言模型与传统的信息检索系统相结合来增强生成式语言模型。
RAG 采用两个主要步骤:
让我们深入了解我们将用于 RAG 应用程序的工具的详细信息。
对于 RAG 应用程序,我们将使用带有 pgvector 的 PostgreSQL 作为我们的向量数据库,Claude Sonnet 3.5 将作为我们的 LLM。让我们讨论它们是什么以及它们的功能。
从 PostgreSQL 16 开始,原生向量支持不可用,但pgvector通过允许您在 PostgreSQL 中存储和搜索向量数据来弥补了这一差距。这个开源扩展允许 PostgreSQL 执行通常与向量数据库相关的任务,包括:
Anthropic 的 Claude Sonnet 3.5 在各种评估中优于竞争对手和 Claude 3 Opus,同时与 Claude 3 Sonnet 的速度和成本相匹配。以下是 Claude Sonnet 3.5 LLM 的一些关键功能:
Claude 3.5 Sonnet 的成本和智能展示
如需了解使用 Claude Sonnet 3.5 和 pgvector 来执行基本 RAG 应用程序示例(或仅仅为了复习你的知识),你随时可以查看我们的前一篇文章。为了本教程,我们将构建一个智能图像库,在那里你可以用自然语言查询图像并对它们进行提问。
我们使用 RAG 的 AI 画廊应用程序的示意图
随着我们构建智能图像库应用程序,我们的数据集必须反映与典型手机用户类似的图像。Flickr30k数据集是出于此目的的绝佳选择。它是一个著名的基于句子的图像描述基准,其中包含31,783张描绘人们从事日常活动和事件的图像。
Flickr30k被广泛用作标准基准,非常适合评估生成基于句子的图像描述的模型。为了更贴近现实,我们不会提供标题,因为在手机上拍照时通常不会包含标题。该数据集可以在Kaggle上找到,并且可以轻松下载。以下是如何操作:
od.download("https://www.kaggle.com/datasets/hsankesara/flickr-image-dataset")
该代码会提示您输入凭证,您可以通过导航到设置>>创建新令牌轻松生成凭证:
为 Kaggle 创建新令牌的设置
由于数据集非常大,大约为 8 GB,我们取 100 张图片大小的样本。以下代码使用 shutil 随机选取 100 张图片并将其复制到目标文件夹。
# Define the path to the folder containing the images
folder_path = 'flickr-image-dataset/flickr30k_images/flickr30k_images'
destination_folder = 'Subset_dataset'
num_images_to_select = 100
# Ensure the destination folder exists
os.makedirs(destination_folder, exist_ok=True)
# List all files in the folder
all_files = os.listdir(folder_path)
# Optionally filter out non-image files (if necessary)
image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff']
image_files = [file for file in all_files if any(file.lower().endswith(ext) for ext in image_extensions)]
# Randomly select 100 images
selected_images = random.sample(image_files, num_images_to_select)
# Copy the selected images to the destination folder
for image in selected_images:
src_path = os.path.join(folder_path, image)
dst_path = os.path.join(destination_folder, image)
shutil.copy(src_path, dst_path)
destination_files = os.listdir(destination_folder)
destination_filepaths = [os.path.join(destination_folder, file) for file in destination_files]
为了将图像转换为嵌入,我们将使用 OpenAI 开发的 CLIP(对比语言图像预训练)。CLIP 是一个通过从图像和描述中学习来链接视觉和文本文档的模型。在下面的代码中,我们:
from sentence_transformers import SentenceTransformer
from PIL import Image
# Load CLIP model
img_model = SentenceTransformer("clip-ViT-B-32")
# Encode an image:
img_emb = model.encode([Image.open(filepath) for filepath in destination_filepaths])
img_emb = img_emb.tolist()
我们将创建 image_gallery
表来存储我们的图像及其嵌入。通常,图像不会直接存储在数据库中;而是存储对包含图像的文件系统的引用。我们将采用相同的方式。该表将包含以下列:
TEXT
。VECTOR
。VECTOR
的大小设置为 512,即用于图像表示的嵌入的维度。cursor.execute(document_table)
conn.commit()
以下代码构建了一个 SQL INSERT
语句,用于将图像文件路径及其嵌入添加到 image_gallery
表中。它通过交错文件路径和嵌入来准备参数,然后执行语句并将事务提交到数据库。
sql = 'INSERT INTO image_gallery (path, embedding) VALUES ' + ', '.join(['(%s, %s)' for _ in img_emb])
params = list(itertools.chain(*zip(destination_filepaths, img_emb)))
cursor.execute(sql, params)
conn.commit()
Creating the ivfflat index just like before:
ivfflat = """CREATE INDEX ON image_gallery USING ivfflat (embedding vector_cosine_ops)"""
cursor.execute(ivfflat)
conn.commit()
以下代码根据文本查询执行图像搜索。它定义了一个名为 image_search
的函数,该函数将查询编码为嵌入。然后,它在 image_gallery
表中搜索前五个最接近的图像嵌入,并返回其文件路径。
def image_search(conn, query):
query_embeddings = img_model.encode(query).tolist()
with conn.cursor() as cur:
cur.execute('SELECT path FROM image_gallery ORDER BY embedding <=> %s::vector LIMIT 5', (query_embeddings))
return cur.fetchall()
query = ["What is my grandpa holding"]
print(image_search(conn, query))
这是从函数中检索到的图像:
根据嵌入距离计算,图片搜索返回的结果
现在,让我们向 Claude 模型询问更多关于图像的信息。
您可以将以下代码分解为以下部分:
image_search
以根据文本查询获取相关图像rag_function
以下是代码:
def Smart_gallery(conn, client, model_name, query):
relevant_images = image_search(conn, query)
image_media_type = "image/jpeg"
with open(relevant_images[0][0], "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
image_data =encoded_string.decode('utf-8')
full_query = (f"Context: The following are relevant pictures for the given query.\n"
f"Based on the image, explain what is the picture about:\n"
f"Question: {query[0]}")
message = client.messages.create(
model="claude-3-5-sonnet-20240620",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": image_media_type,
"data": image_data,
},
},
{
"type": "text",
"text": "Describe this image."
}
],
}
],
)
return relevant_images[0][0], message.content
# Example usage:
query = ["What is my grandpa holding"]
image, text = Smart_gallery(conn, client, "claude-3-5-sonnet-20240620", query)
plt.imshow(Image.open(image))
print(text)
以下是检索到的图像和查询结果:
该模型通过计算图像搜索检索到的结果的嵌入距离和文本,并进行分析后,提供了结果。
>>> 图像显示一位头发花白、留着白胡子的老人,手里拿着一个看起来像是手工制作的木制橱柜或小型结构。他穿着灰色 T 恤,里面是白色长袖衬衫。他手中的木制品看起来像是玩具屋、宠物围栏或装饰性储物柜。它有雕刻的小门和小窗,看起来像房子。这位老人似乎是在家中,背景中可以看到窗帘。他的表情表明他可能正在检查或展示这件木制品,可能是他自己制作的。
万事俱备!感谢 pgvector 和 Claude Sonnet 3.5,我们成功地完成了 AI 驱动的图像库。
受增强型检索增强生成 (RAG) 与 LLM 能力的启发,我们开发了一个 AI 图像搜索库。该系统根据文本查询检索类似图像,并将它们用作 Sonnet 3.5 的上下文。
为了将图像和文本链接起来,我们使用 CLIP 模型生成嵌入,然后使用 pgvector 将其存储在 PostgreSQL 中。我们执行了相似性搜索以检索图像路径,然后将其提供给 Sonnet 3.5 用于上下文。
Timescale 可以帮助您更快、更高效地构建 AI 应用程序。使用 Timescale Cloud,开发人员可以访问 pgvector、pgvectorscale 和 pgai——这些扩展将 PostgreSQL 变成易于使用且高性能的向量数据库,以及完全托管的云数据库体验。
pgia 和 pgvectorscale 均在 PostgreSQL 许可证下开源。如欲安装,请查看 pgia 和 pgvectorscale 的 GitHub 存储库(欢迎 ⭐!)。您可以在 Timescale Cloud PostgreSQL 平台上的任何数据库服务上访问 pgai 和 pgvectorscale。立即使用 Timescale Cloud 构建您的 AI 应用程序。