AI 与向量

使用Amazon Titan实现语义图像搜索

使用Amazon Titan和Supabase Vector在Python中实现语义图像搜索


Amazon Bedrock 是一项全托管服务,提供来自领先AI公司(如AI21 Labs、Anthropic、Cohere、Meta、Mistral AI、Stability AI和亚马逊)的高性能基础模型(FMs)选择。每个模型都通过统一的API访问,该API实现了广泛的功能集,旨在帮助构建具有安全性、隐私性和负责任AI考虑的生成式AI应用。

Amazon Titan 是一个基础模型(FMs)系列,支持文本和图像生成、摘要、分类、开放式问答、信息提取以及文本或图像搜索。

本指南将介绍如何通过Python使用Amazon Titan多模态模型和vecs客户端开始结合Amazon Bedrock与Supabase Vector。

您可以在GitHub上找到完整的应用代码,这是一个基于Python Poetry的项目。

使用Poetry创建新Python项目

Poetry 为Python提供打包和依赖管理功能。如果尚未安装,请通过pip安装poetry:

1
pip install poetry

然后初始化新项目:

1
poetry new aws_bedrock_image_search

快速启动带 pgvector 的 Postgres 数据库

如果尚未创建项目,请前往 database.new 创建一个新项目。每个 Supabase 项目都附带完整的 Postgres 数据库和预配置的 pgvector 扩展

创建项目时,请务必记下数据库密码,因为在下一步构建 DB_URL 时需要用到。

您可以在项目仪表板中找到数据库连接字符串,点击 Connect。使用会话池连接字符串,格式如下:

1
postgresql://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres

安装依赖项

我们需要为项目添加以下依赖项:

  • vecs: Supabase 向量 Python 客户端
  • boto3: AWS Python SDK
  • matplotlib: 用于显示图像结果
1
poetry add vecs boto3 matplotlib

导入必要的依赖项

在您的 Python 主脚本顶部,导入依赖项并将上述 DB URL 存储在变量中:

1
2
3
4
5
6
7
8
9
10
import sysimport boto3import vecsimport jsonimport base64from matplotlib import pyplot as pltfrom matplotlib import image as mpimgfrom typing import OptionalDB_CONNECTION = "postgresql://postgres.[PROJECT-REF]:[YOUR-PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres"

接下来,获取 AWS 账户凭证 并实例化 boto3 客户端:

1
2
3
4
5
6
7
8
bedrock_client = boto3.client( 'bedrock-runtime', region_name='us-west-2', # 来自您 AWS 账户的凭证 aws_access_key_id='<replace_your_own_credentials>', aws_secret_access_key='<replace_your_own_credentials>', aws_session_token='<replace_your_own_credentials>',)

为您的图像创建嵌入向量

在项目根目录下,创建一个名为images的新文件夹并添加一些图片。您可以使用GitHub示例项目中的图片,也可以在Unsplash上寻找免版税图片。

要将图片发送到Amazon Bedrock API,我们需要将其编码为base64字符串。创建以下辅助方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def readFileAsBase64(file_path): """将图片编码为base64字符串""" try: with open(file_path, "rb") as image_file: input_image = base64.b64encode(image_file.read()).decode("utf8") return input_image except: print("无效文件名") sys.exit(0)def construct_bedrock_image_body(base64_string): """构造请求体 参考文档:https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-titan-embed-mm.html """ return json.dumps( { "inputImage": base64_string, "embeddingConfig": {"outputEmbeddingLength": 1024}, } )def get_embedding_from_titan_multimodal(body): """通过API请求调用Amazon Titan模型""" response = bedrock_client.invoke_model( body=body, modelId="amazon.titan-embed-image-v1", accept="application/json", contentType="application/json", ) response_body = json.loads(response.get("body").read()) print(response_body) return response_body["embedding"]def encode_image(file_path): """为指定路径的图片生成嵌入向量""" base64_string = readFileAsBase64(file_path) body = construct_bedrock_image_body(base64_string) emb = get_embedding_from_titan_multimodal(body) return emb

接下来,创建一个seed方法,该方法将创建一个新的Supabase向量集合,为您的图片生成嵌入向量,并将这些向量插入数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def seed(): # 创建向量存储客户端 vx = vecs.create_client(DB_CONNECTION) # 获取或创建一个1024维的向量集合 images = vx.get_or_create_collection(name="image_vectors", dimension=1024) # 使用Amazon Titan模型生成图片嵌入向量 img_emb1 = encode_image('./images/one.jpg') img_emb2 = encode_image('./images/two.jpg') img_emb3 = encode_image('./images/three.jpg') img_emb4 = encode_image('./images/four.jpg') # 向images集合添加记录 images.upsert( records=[ ( "one.jpg", # 向量标识符 img_emb1, # 向量值,可以是列表或np.array {"type": "jpg"} # 关联的元数据 ), ( "two.jpg", img_emb2, {"type": "jpg"} ), ( "three.jpg", img_emb3, {"type": "jpg"} ), ( "four.jpg", img_emb4, {"type": "jpg"} ) ] ) print("已插入图片") # 为集合创建索引以提高搜索性能 images.create_index() print("已创建索引")

pyproject.toml文件中添加这个方法作为脚本:

1
2
3
[tool.poetry.scripts]seed = "image_search.main:seed"search = "image_search.main:search"

通过poetry shell激活虚拟环境后,您现在可以通过poetry run seed运行种子脚本。您可以在Supabase仪表板的Table Editor中查看生成的嵌入向量,选择vecs模式和image_vectors表。

通过文本查询执行图像搜索

我们可以使用 Supabase Vector 来查询我们的嵌入向量。既可以使用图像作为搜索输入,也可以从字符串输入生成嵌入向量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def search(query_term: Optional[str] = None): if query_term is None: query_term = sys.argv[1] # 创建向量存储客户端 vx = vecs.create_client(DB_CONNECTION) images = vx.get_or_create_collection(name="image_vectors", dimension=1024) # 编码文本查询 text_emb = get_embedding_from_titan_multimodal(json.dumps( { "inputText": query_term, "embeddingConfig": {"outputEmbeddingLength": 1024}, } )) # 查询集合,筛选元数据中"type"为"jpg"的记录 results = images.query( data=text_emb, # 必需参数 limit=1, # 返回记录数量 filters={"type": {"$eq": "jpg"}}, # 元数据筛选器 ) result = results[0] print(result) plt.title(result) image = mpimg.imread('./images/' + result) plt.imshow(image) plt.show()

通过将查询结果限制为一条,我们可以向用户展示最相关的图像。最后使用 matplotlib 向用户展示图像结果。

您可以立即测试这个功能,运行 poetry run search 命令后,将会显示一张"红色砖墙前的自行车"图片。

总结

仅需几行 Python 代码,您就能利用 Amazon Titan 多模态模型和 Supabase Vector 实现图像搜索和反向图像搜索功能。