使用Chroma构建基于向量的AI应用

Chroma是一个强大的数据库,专为构建使用嵌入的AI应用而设计。在这篇文章中,我们将介绍如何安装和设置Chroma,并展示如何使用Chroma构建一个向量存储库(VectorStore)。此外,我们还会讲解如何使用SelfQueryRetriever进行语义搜索和实例选择。

技术背景介绍

在AI应用中,嵌入(embeddings)是将高维数据映射到低维空间的方式。向量存储(VectorStore)是一个存储向量数据的数据库,这在语义搜索和相似性比较中非常有用。Chroma是一个高度优化的向量数据库,它支持高效的向量存储、检索和管理。

核心原理解析

Chroma的核心概念是将文本或其他高维度数据转换为向量,并将这些向量存储在数据库中。通过高效的检索算法,Chroma能够快速找到与查询向量最相似的存储向量。这使得Chroma在构建语义搜索和实例选择的AI应用中非常有用。

代码实现演示

安装和设置

首先,我们需要安装langchain-chroma包:

pip install langchain-chroma
构建向量存储(VectorStore)

以下是如何使用Chroma构建一个向量存储库的示例代码:

from langchain_chroma import Chroma

# 初始化Chroma向量存储
vector_sto
<think>我们正在使用Chroma构建一个向量图片数据库,主要功能是通过文字搜索图片。根据引用[1],我们知道Chroma支持文字和图片,通过OpenClip模型对文字和图片做Embedding。因此,构建步骤包括: 1. 准备图片数据 2. 使用OpenClip模型对图片生成Embedding向量 3. 将向量和元数据(如图片路径)存储到Chroma 4. 对搜索文本同样用OpenClip生成Embedding,然后在Chroma中进行相似度搜索 具体步骤: 步骤1:安装必要的库 我们需要安装chromadb和open_clip_torch(或者使用OpenClip的API,但这里我们使用本地模型)。 步骤2:准备图片数据 将图片存放在一个目录中,并收集所有图片的路径。 步骤3:加载OpenClip模型 使用OpenClip加载预训练模型和处理器(用于图像预处理)。 步骤4:生成图片向量 遍历每张图片,用模型提取特征向量。 步骤5:创建Chroma集合 在Chroma中创建一个集合(collection),用于存储向量和元数据。 步骤6:将向量和元数据存入Chroma 将每张图片的向量、id(可以是图片路径)和元数据(如文件名等)添加到集合中。 步骤7:文本搜索 当用户输入搜索文本时,用同样的模型将文本转换为向量,然后在集合中搜索最相似的图片向量。 下面是一个示例代码框架: ```python import chromadb from chromadb.utils import embedding_functions import open_clip import torch from PIL import Image import os # 设置图片目录 image_dir = "path/to/your/images" # 初始化Chroma客户端 chroma_client = chromadb.PersistentClient(path="path/to/db") # 或者使用HttpClient连接远程 # 使用OpenClip的嵌入函数,这里我们自定义一个嵌入函数,因为chromadb的embedding_functions目前可能没有直接支持OpenClip # 但我们可以自己实现,或者使用chromadb的CustomEmbeddingFunction # 注意:chromadb支持自定义嵌入函数,我们只需要实现一个函数,输入为字符串列表(对于文本)或图像数据(对于图像),输出为向量列表。 # 由于我们的数据是图片,而搜索时输入文本,所以需要分别处理。 # 加载OpenClip模型 model, _, preprocess = open_clip.create_model_and_transforms('ViT-B-32', pretrained='laion2b_s34b_b79k') tokenizer = open_clip.get_tokenizer('ViT-B-32') # 定义图片嵌入函数 def image_embedder(images: list) -> list: # 注意:images是一个列表,每个元素是图片的路径(字符串)或者可以直接是PIL.Image对象?这里我们假设传入的是路径列表 embeddings = [] for img_path in images: image = Image.open(img_path).convert("RGB") image_input = preprocess(image).unsqueeze(0) # 增加一个batch维度 with torch.no_grad(): image_features = model.encode_image(image_input) image_features /= image_features.norm(dim=-1, keepdim=True) # 归一化,相似度计算用余弦相似度 embeddings.append(image_features.squeeze(0).tolist()) return embeddings # 定义文本嵌入函数(用于搜索时) def text_embedder(texts: list) -> list: embeddings = [] for text in texts: text_tokens = tokenizer([text]) with torch.no_grad(): text_features = model.encode_text(text_tokens) text_features /= text_features.norm(dim=-1, keepdim=True) embeddings.append(text_features.squeeze(0).tolist()) return embeddings # 创建集合(如果不存在) # 注意:我们使用自定义的嵌入函数,但chromadb要求嵌入函数必须实现为EmbeddingFunction的子类,因此我们可以使用CustomEmbeddingFunction # 但是,由于我们的嵌入函数是针对图片和文本分别的,而Chroma的集合只能有一个嵌入函数(用于输入数据),所以这里我们存储的是图片向量,因此集合的嵌入函数应该是图片嵌入函数?但实际上,在存储时我们使用图片嵌入函数生成向量,而搜索时我们使用文本嵌入函数生成向量,然后进行搜索。Chroma的集合在存储时并不需要指定嵌入函数(如果我们自己提供向量的话),我们可以直接提供向量。 # 因此,我们可以不使用集合的嵌入函数,而是自己计算好向量再存入。这样,集合的嵌入函数可以设置为None,然后我们存储时提供向量。 # 创建集合(不使用集合的嵌入函数) collection = chroma_client.create_collection(name="image_vectors") # 收集所有图片路径 image_paths = [os.path.join(image_dir, f) for f in os.listdir(image_dir) if f.endswith(('.jpg', '.png'))] # 生成图片向量 image_embeddings = image_embedder(image_paths) # 准备元数据和id ids = [str(i) for i in range(len(image_paths))] # 使用索引作为id,也可以使用图片路径的哈希值等 metadatas = [{"file_path": path} for path in image_paths] # 存入集合 collection.add( embeddings=image_embeddings, metadatas=metadatas, ids=ids ) # 现在,我们可以进行文本搜索 query_text = "a cat playing with a ball" query_embedding = text_embedder([query_text])[0] # 注意:text_embedder返回的是列表,我们取第一个 # 搜索 results = collection.query( query_embeddings=[query_embedding], n_results=3 ) # 输出结果 print(results) ``` 注意:上面的代码是一个简化示例,实际中需要考虑性能(批量处理)、错误处理、持久化等。另外,Chroma也支持直接使用集合的嵌入函数,但这里我们手动计算向量,所以更灵活。 但是,上面的代码有一个问题:在存储时我们使用了图片嵌入向量,而查询时使用了文本嵌入向量。由于OpenClip的模型将图片和文本映射到同一个向量空间,所以可以直接进行相似度比较。 另外,我们也可以使用chromadb的`Images`功能(如果支持的话),但目前Chroma主要针对文本,所以我们需要自己处理图片的嵌入过程。 改进:我们可以使用chromadb的`embedding_function`参数来指定一个自定义的嵌入函数,这样在添加数据时,我们可以传入图片的二进制数据或路径,然后由嵌入函数处理。但是,chromadb的嵌入函数目前只支持文本(默认),所以我们需要自定义一个支持图片的嵌入函数。不过,在chromadb中,自定义嵌入函数需要实现`EmbeddingFunction`接口,它有一个`__call__`方法,接收文本列表。因此,如果我们想同时支持图片和文本,可能需要做一些调整。 另一种做法:我们只存储图片向量,而查询向量由我们自己计算(如上面的例子)。这样,我们就不需要集合的嵌入函数了。 根据引用[2],Chroma以其简单性和开发者友好性著称,所以上述方法已经足够简单。 因此,我们按照上述步骤构建即可。 最后,关于OpenClip模型的选择,我们可以根据需求选择不同的预训练模型,例如'ViT-B-32'是一个平衡速度和精度的选择。 相关问题: 1. 如何优化Chroma向量图片数据库的搜索速度? 2. 除了OpenClip,还有哪些模型可以用于图片和文本的跨模态检索? 3. Chroma向量数据库支持哪些索引类型?如何选择? 4. 如何处理大规模图片数据(上百万张)的向量生成和存储? 5. 如何更新Chroma中的图片向量(例如,当图片被修改或删除时)?</think>### 如何使用 Chroma 构建向量图片数据库 以下是构建 Chroma 向量图片数据库的完整步骤,基于 OpenCLIP 模型实现文字搜索图片功能: --- #### **1. 环境准备** 安装必要库: ```bash pip install chromadb open_clip_torch pillow torch ``` --- #### **2. 核心流程** ```python import chromadb import open_clip import torch from PIL import Image import os # 初始化 Chroma 客户端 client = chromadb.PersistentClient(path="./image_vector_db") # 本地持久化存储 collection = client.create_collection(name="image_vectors") # 加载 OpenCLIP 模型 model, _, preprocess = open_clip.create_model_and_transforms('ViT-B-32', pretrained='laion2b_s34b_b79k') tokenizer = open_clip.get_tokenizer('ViT-B-32') # 图像向量生成函数 def get_image_embedding(image_path: str) -> list: image = Image.open(image_path).convert("RGB") image_tensor = preprocess(image).unsqueeze(0) with torch.no_grad(): image_features = model.encode_image(image_tensor) return image_features.squeeze(0).tolist() # 转为列表格式 # 文本向量生成函数 def get_text_embedding(text: str) -> list: text_tokens = tokenizer([text]) with torch.no_grad(): text_features = model.encode_text(text_tokens) return text_features.squeeze(0).tolist() # 添加图片到数据库 image_dir = "your_images_folder" for idx, img_file in enumerate(os.listdir(image_dir)): img_path = os.path.join(image_dir, img_file) embedding = get_image_embedding(img_path) collection.add( embeddings=[embedding], metadatas=[{"file_path": img_path}], # 存储原图路径 ids=[f"img_{idx}"] # 唯一ID ) # 文字搜索图片 def search_images(query: str, n_results=5): query_embedding = get_text_embedding(query) results = collection.query( query_embeddings=[query_embedding], n_results=n_results ) return results["metadatas"][0] # 返回匹配的图片元数据 # 示例:搜索"海滩日落" print(search_images("海滩日落")) ``` --- #### **3. 关键组件说明** 1. **向量生成** - 使用 OpenCLIP 的 `ViT-B-32` 模型将图片/文本映射到 512 维向量空间 - 同一模型保证图文向量可比对[^1] 2. **数据存储** - Chroma 存储三要素:`向量` + `元数据` + `ID` - 元数据建议包含:图片路径、创建时间、标签等 3. **检索流程** $$ \text{相似度} = \cos(\theta) = \frac {\vec{A} \cdot \vec{B}} {\|\vec{A}\| \|\vec{B}\|} $$ 默认使用余弦相似度计算文本向量与图片向量的匹配度 --- #### **4. 优化建议** - **批量处理**:使用 `collection.add(embeddings=[...])` 批量添加减少 I/O - **元数据过滤**: ```python collection.query(..., where={"category": "nature"}) # 按元数据字段过滤 ``` - **混合搜索**:结合关键词与向量搜索提升精度 - **分布式部署**:超过 100 万数据时使用 Chroma 集群模式[^2] --- #### **5. 应用场景** 1. 电商平台:用文字搜索商品图片 2. 相册管理:通过描述查找历史照片 3. 内容审核:检测违规图片 4. 推荐系统:相似图片推送 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值