矢量数据库简单介绍:在 Postgres使用 pg_vector
作为向人工智能大规模转变的一部分,矢量数据库越来越受欢迎。它们也称为矢量化数据库,在人工智能领域发挥着至关重要的作用,因此了解它们的工作原理非常重要。为此,我们首先需要了解什么是向量。
什么是向量?
向量是表示文本或图像等 非结构化数据 的数字数组。
例如,让我们将这些句子表示为向量:
s1 = “I love data”
s2 = “I love candy”
我们可以采用所有单词并创建具有四个维度(每个术语一个)的所谓“词袋”(BoW)模型:
BoW 的问题在于,它们依赖于词频,并且假设每个单词独立于其他单词出现,这是不切实际的假设。这是一个显着的简化,因为在自然语言中,上下文和含义通常在很大程度上取决于词序和词之间的关系。例如,“not good”和“good”在 BoW 模型中被视为相同的两个单词,即使由于“not”的存在而导致它们的含义相反。
为了解决这些限制,开发了更先进的技术。其中包括诸如词嵌入(或嵌入)之类的模型,它们通过考虑单词出现的上下文来捕获更多语义信息。
什么是嵌入(Embedding)?
由神经网络创建的具有大量维度的向量,这些向量是通过预测每个单词的相邻单词可能是什么来创建的。
下面是使用 200 个维度的 Word2Vec 模型生成的嵌入的可视化。您可以使用 Tensorflow Projector 进行模拟.
这个想法是将这些嵌入保存到数据库中以便快速检索。
什么是矢量索引与矢量数据库?
“索引”是一种提高数据库表数据检索操作速度的数据结构。
矢量索引是一种用于根据矢量内容有效地组织和检索矢量的机制。
矢量数据库是一种专门为高效处理和存储矢量数据而设计的数据库。它是一个数据库,包含旨在管理矢量数据的功能,包括存储、检索和查询处理。它可以利用向量索引作为其高效面向向量操作策略的一部分。
什么是 pg_vector?
Postgres 的开源矢量相似性搜索。如果您现在拥有或使用 Postgres,则可以安装 pg_vector 扩展以向 Postgres 添加矢量数据库功能。转到项目GitHub - pgvector/pgvector: Open-source vector similarity search for Postgres以获取安装说明。
pg_vector 入门
要在 Postgres 中启用它,只需执行以下命令:
CREATE EXTENSION IF NOT EXISTS vector;
接下来,创建一个表来保存嵌入向量。在此示例中,我们将把图像转换为嵌入向量并将它们存储在 Postgres 的图像表中。
DROP TABLE IF EXISTS images;
CREATE TABLE images (
id bigserial PRIMARY KEY,
path varchar(64),
embedding vector(512)
)
请注意,有一个embedding
列,它有 512 个维度。
现在,我们可以添加向量索引。
添加向量索引
pg_vector 有两个向量索引:HNSW 和 IVFFLAT。下面的示例使用 HNSW。
CREATE INDEX ON images USING hnsw (embedding vector_l2_ops);
向向量列添加索引时,必须提供距离算法。 pg_vector 带有三种不同的距离算法:
-
L2距离(欧氏距离)
-
Inner product 内积
-
Cosine distance 余弦距离
距离算法决定点周围的半径。半径内的任何记录都被视为在该距离内。
这将有助于有效地在图像表中找到相似的嵌入向量。
现在我们有一个表,其中包含用索引定义的embedding
列,我们如何将图像转换为嵌入以将其插入到images表中?
Embeddings Model
为了将图像转换为嵌入,我们将使用 CLIP 模型(由 Hugging Face 提供)和 Python psycopg 连接 Postgres数据库。
import psycopg
from sentence_transformers import SentenceTransformer
from PIL import Image
image_path = './my_image.png'
model = SentenceTransformer('clip-ViT-B-32')
img_emb = model.encode(Image.open(image_path))
conn = psycopg.connect(dbname="postgres", autocommit=True)
cur.execute('INSERT INTO images (embedding, path) VALUES (%s,%s)', (img_emb.tolist(), image_path))
请注意,我们已在表中添加了一个path
列。重要的是要知道embedding不包含图像本身,因此一旦找到相似的记录,我们需要一种方法来查找图像。这在本文后面将变得更加重要。
相似性搜索
下面的 Python 代码执行以下操作:
-
让用户描述她想要查看的图像。
-
将用户描述转换为embedding。
-
对embedding描述的图像表执行 select 语句并返回结果。
-
显示找到的图像以及与描述embedding的距离。
from matplotlib import pyplot as plt
from matplotlib import image as mpimg
query_string = input("What image to you want to see:")
text_emb = model.encode(query_string)
cur = conn.cursor()
cur.execute("""
SELECT id, path, embedding <-> %s AS distance
FROM images ORDER BY embedding::vector(512) <-> %s
""",
(str(text_emb.tolist()),str(text_emb.tolist())))
rows = cur.fetchall()
path = rows[0][1]
distance = rows[0][2]
plt.title(f'{path} {distance}')
image = mpimg.imread(path)
plt.imshow(image)
plt.show()
换句话说,假设此应用程序询问您想要查看什么图像,然后您输入:
“a white bike in front of a red brick wall”
矢量数据库返回如下图像:
总之:
-
拍摄图像 → 使用 CLIP 模型从图像生成嵌入 → 将它们插入到 启用pg_vector的 Postgres 中。
-
获取图像的描述(文本)→ 使用 SAME CLIP 模型从文本生成embedding。
-
使用 SQL 生成 select 语句,并使用文本嵌入在图像表中搜索相似的embedding。
我们正在比较图像嵌入和文本嵌入!!!!!!
pg_vector 进行相似性搜索以查找与图像描述最相似的图像path。