大模型向量库
- 向量:AI核心
- 向量库:语义近似搜索
- 大模型 + 向量库
- YOLO + 向量数据库
- 嵌入(Embedding)设计
- 最近邻搜索
- 近似近邻搜索
- 主流向量数据库
- Milvus 实践
向量:AI核心
向量伴随着 AI 模型的发展而发展。
向量:AI 理解世界的通用数据形式,是多模态数据的压缩。
比如大模型输入输出都是文字文本,但模型实际接触和学习数据是向量化文本。
这个步骤叫 Embedding(嵌入),将文字文本转化为保留语义关系的向量文本。
embedding 模型对自然语言的压缩和总结,将高维数据映射到低维空间。
不仅文字,图像也是向量化之后进行处理:
向量库:语义近似搜索
传统数据库是基于文本的精确匹配、SQL语言查找符合条件的数据,适合关键字搜索。
向量库:专门存储和查询向量的数据库,适合语义搜索。
向量数据库步骤:
- 向量数据的存储:向量数据通常是高维的数值型数据,如图像特征向量、文本词向量等;向量数据库使用基于向量的存储结构,以便快速查询和处理;
- 向量索引:向量数据库使用PQ、LSH或HNSW等算法为向量编制索引,并将向量映射到数据结构,以便更快地进行搜索;
- 向量查询:向量数据库将查询向量与数据库中的向量进行比较,从而找到最近邻的向量;
- 查询结果的返回:向量数据库返回查询结果,通常包括与给定向量最相似的向量列表、向量之间的相似度得分等信息;该环节可以使用不同的相似性度量对最近邻重新排序。
传统数据库索引是精确匹配,要么符合查询要求(返回数据),要么不符合查询要求(无数据返回)。
向量搜索
- 在海量存储的向量中找到最符合要求的 Top N 个目标。
- 向量搜索是模糊匹配,返回的是相对最符合要求的N个数据,并没有精确标准答案
向量数据库
- 时间上:用以高效存储和搜索向量,自带语义理解(向量位置之间的相关性,距离越近越相关),为AI模型提供长期记忆功能
- 空间上:向量数据库本地部署后可以存储企业有关的大量隐私数据,通过特别的Agent大模型可以在有保护的情况下访问向量数据库
- 成本上:更低成本的搜索、查询、存储向量
- 速度上:保证100%信息完整的情况下,通过向量嵌入函数(embedding)精准描写非结构化数据的特征,从而提供查询、删除、修改、元数据过滤等操作,同时实现极高效率的近似搜索
- 功能上:跨模态搜索,例如让用户用文字来搜索图片,因为向量能够捕捉到语义相似性,使来自不同语言的查询和内容能够相互匹配。
传统数据库无法满足此类操作和需求,只能实现部分向量数据的存储,且无法高效搜索向量。
向量搜索能够实现对语义更为精准的理解,在多模态、不同语言等环境下能够输出更为准确的结果。
如:英文的Capital可以指“资本”或者“首都”,“从中国去美国”和“从美国去中国”存在方向,传统的数据库不能很好解决这些问题。
-
已知传统数据库,适合关键字搜索。
-
已知向量库,适合语义搜索。
那是不是还可以组合俩者,提供更加全面和精准的搜索?
或者加速搜索速度,先使用向量库进行初步的语义搜索以缩小搜索范围,然后在这个范围内使用传统数据库进行精确的关键字搜索。
大模型 + 向量库
Step 1 语料库准备:
- 将与行业相关的大量知识或语料上传至向量数据库,储存为向量化文本;
Step 2 问题输入:
- 输入的问题被Embedding引擎变成带有向量的提问;
Step 3 向量搜索:
- 向量化问题进入提前准备好的向量数据库中,通过向量搜索引擎计算向量相似度,匹配出Top N条语义最相关的答案
Step 4 Prompt优化:
- 输出的Top N条Facts,和用户的问题一起作为prompt输入给模型。
Step 5 结果返回:
- 有记忆交互下得到的生成内容更精准且缓解了幻觉问题。
YOLO + 向量数据库
假设你正在使用YOLO模型来识别和分类眼底图像中的疾病,比如糖尿病性视网膜病变、青光眼等。
不使用向量数据库的情况:
- 每次识别都需要YOLO模型从头开始处理图像,并实时输出分类结果。
- 对于历史数据的搜索和比较可能需要重新运行模型或手动检查。
- 难以进行大规模的相似案例搜索,比如寻找有相似视网膜特征的病例进行对比分析。
- 每次查询都是独立的,不利用先前的计算结果和数据。
使用向量数据库的情况:
- YOLO模型可以将识别到的特征(例如视盘、视杯、血管异常等)转换为向量,并存储在向量数据库中。
- 一旦存储了特征向量,就可以快速进行相似性搜索,找到具有类似病理特征的其他眼底图像。
- 可以实现快速的案例检索,帮助医生进行诊断对比,或者用于研究和教育目的。
- 可以跟踪病情的进展,通过比较新旧图像的特征向量来观察病变的变化。
- 可以更高效地管理和利用存储的数据,为大数据分析和机器学习提供支持,可能还能发现新的疾病模式或趋势。
假设一个医院收集了数千张眼底图像,并使用YOLO模型来识别各种疾病标志。
如果没有向量数据库,每次新的病例来临时,医生可能需要手动查找和比较历史病例来辅助诊断。
这不仅费时,而且无法保证一致性和准确性,特别是在病例数量庞大时。
如果使用向量数据库,YOLO模型可以将每张图像中识别出的疾病标志转换为特征向量并存储。
当新病例来临时,模型会对新眼底图像进行分析,并将其特征向量与数据库中现有的向量进行比较。
这样可以迅速找到历史病例中与新病例具有相似特征的图像,为医生提供即时的、数据驱动的参考。
此外,医生还可以追踪特定患者的病情变化,通过比较同一患者不同时间点的眼底图像的特征向量。
用与不用向量数据库的具体区别:
- 诊断速度和效率:使用向量数据库可以大大加快诊断过程,因为相似性搜索可以即时完成。
- 诊断一致性:数据库可以帮助医生获得一致的比较结果,而不是依赖个人的记忆或手动搜索。
- 数据驱动的洞见:通过分析存储的特征向量,可能发现新的疾病模式或趋势,这对于医学研究和临床实践都是非常宝贵的。
- 患者跟踪和管理:医生可以更容易地跟踪患者的病情进展,并根据历史数据进行有效管理。
那俩者怎么结合呢?
使用YOLO模型和向量数据库进行目标检测和检索涉及几个步骤:
-
数据准备:
- 收集并标注眼底图像数据集。
- 对图像进行预处理,如调整大小、归一化等。
-
YOLO模型训练:
- 使用标注好的眼底图像数据集训练YOLO模型。
- 训练完成后,模型应能够在眼底图像中识别出疾病标志。
-
特征提取:
- 将训练好的YOLO模型应用于眼底图像。
- 模型将输出每个检测到的对象的边界框、类别标签和特征向量。
-
构建向量数据库:
- 设计数据库架构,用于存储特征向量以及与之关联的元数据(如图像ID、诊断结果等)。
- 选择适合高维向量检索的数据库系统,如使用Faiss、Annoy、Elasticsearch等。
-
存储特征向量:
- 将YOLO提取出的特征向量存储到向量数据库中。
- 确保数据库有适当的索引结构,以支持高效的检索。
-
实现检索功能:
- 开发一个界面或API,允许用户提交新的眼底图像。
- 使用YOLO模型提取新图像的特征向量。
- 将提取出的特征向量与数据库中存储的向量进行比较,找出最相似的匹配项。
-
使用检索结果:
- 将检索结果(相似的眼底图像或案例)展示给医生或研究人员。
- 结合医生的专业知识和模型的检索结果进行诊断或研究分析。
假设医生想要诊断一个新的眼底图像,以确定是否有糖尿病性视网膜病变的迹象。
医生通过界面上传图像,系统自动进行以下步骤:
- 使用YOLO模型对上传的图像进行处理,模型检测图像中的特征并生成特征向量。
- 特征向量被送到向量数据库进行检索,数据库快速返回最相似的历史案例。
- 医生收到系统提供的相似案例,这些案例包含历史图像、诊断信息和其他相关数据。
- 医生可以查看匹配的案例并参考这些信息,辅助自己作出诊断决策。
使用向量数据库可以大大加快医生访问和比较历史案例的速度,提高工作效率,并可能提高诊断的准确性。
嵌入(Embedding)设计
嵌入的核心思想是将每个单词或短语映射到一个高维空间(通常是数百到数千维)中的点。
这些点的相对位置可以表示不同单词之间的语义关系,例如同义词会在高维空间中彼此靠近,而无关的词则会相距较远。
举个例子:假设我们有三个单词:“猫”、“狗”和“汽车”。
在一个良好构建的嵌入空间中,“猫”和“狗”的向量会比“猫”和“汽车”的向量更为接近,因为“猫”和“狗”在语义上更相关(都是宠物),而“汽车”则与这两者在语义上相距较远。
设计步骤:
-
预处理文本数据:
- 清洗文本:去除无关字符、标点符号、HTML标签等。
- 分词(Tokenization):将文本分解成单词、短语或其他有意义的字符序列。
- 归一化(Normalization):转换为统一的大小写,进行词干提取(Stemming)或词形还原(Lemmatization)。
-
构建词汇表:
- 根据预处理后的文本,创建一个唯一单词的集合,称为词汇表。
- 可能会设置最小出现频率,排除出现次数过少的单词。
- 特殊标记:如未知词(UNK)、句子开始(SOS)、句子结束(EOS)等。
-
选择嵌入方法:
- One-hot Encoding:最简单的方法,每个单词由一个大向量表示,该向量中只有一个元素是1,其余都是0。
- Word Embeddings:
- 预训练嵌入(如Word2Vec、GloVe):使用大型文本语料库训练得到的,能够捕捉语义关系的密集向量。
- 自定义训练嵌入:在特定任务上从头开始训练得到的嵌入向量。
- 上下文嵌入(如BERT、GPT):生成的嵌入向量不仅取决于单词本身,还取决于单词在句子中的上下文。
-
嵌入向量的维度选择:
- 嵌入向量的维度通常是超参数,需要根据问题的复杂性和训练数据的大小进行调整。
- 维度越大,模型的表达能力越强,但计算量也越大,且可能导致过拟合。
-
训练嵌入层:
- 如果使用预训练的嵌入,可以直接加载到模型中,也可以进一步在特定任务上进行微调。
- 如果是自定义训练,将嵌入层作为模型的一部分,通过误差反向传播进行训练,学习到最适合当前任务的嵌入向量。
-
处理OOV(Out-of-Vocabulary)问题:
- 对于在词汇表中不存在的单词,通常会用特殊的UNK向量表示。
- 可以通过子词嵌入(如Byte-Pair Encoding)处理未知单词,将单词分解为更小的单位。
-
优化和评估:
- 使用验证集评估嵌入层对于任务的有效性。
- 调整嵌入层的参数或训练策略,以提高模型性能。
- 可视化嵌入向量,检查语义关系是否符合预期(如使用t-SNE技术)。
最近邻搜索
在D维空间中的查询向量q
与一组向量x_1, x_2, ..., x_N
进行比较,以找到最近的向量。
数学表达式是查询向量q
与每个数据库向量x_n
之间的平方欧几里得距离的argmin。
结果是查询q
的最近向量x_74
。
两种寻找最近邻的实现方式:
- 一种是简单的朴素实现
- 另一种是使用Facebook AI Research (FAIR)的Faiss库的快速实现。
朴素实现非常直接,使用简单的循环计算q
和x
之间的平方差。
Faiss实现,对查询数量较少的情况(M <= 20
)使用SIMD(单指令多数据)以及对查询数量较多的情况使用BLAS(基本线性代数子程序)进行计算。
上图介绍了,向量如何组装进SIMD寄存器以及计算过程以达到结果。
如何使用SIMD指令计算平方欧几里得距离,这些指令允许并行计算,可以显著加快计算速度。
如何利用SIMD和BLAS进行大规模矩阵计算。
上图展示了如何将查询向量和数据库向量堆叠成矩阵,并使用sgemm
函数(BLAS的矩阵乘法函数)来高效计算内积。
它还指出了不同BLAS实现之间的性能差异,比如Intel MKL和OpenBLAS,其中Intel MKL报告称比OpenBLAS快30%。
主要主题是最近邻搜索的优化,特别关注如何使用高级技术如SIMD和优化的库如BLAS高效计算高维向量之间的距离。
结论是,通过使用这些高级技术,可以在最近邻搜索中实现显著的性能提升,这对于机器学习和数据检索中的许多应用至关重要。
近似近邻搜索
在不同数据规模下,原始数据与压缩数据处理的对比。
左侧是为原始数据设计的方法,如局部敏感哈希(LSH)、树/空间划分和图遍历,这些方法在较小规模的数据集上表现良好。
右侧是为压缩数据设计的方法,包括查找表和哈明距离基础上的线性扫描,适用于更大规模的数据集。
几乎与上图相同,但它标记了局部敏感哈希(LSH)方法,可能是为了强调这种方法在处理原始数据时的重要性。
MinHash-LSH 哈希模糊去重:如何解决医学大模型的大规模数据去重?
详细介绍了局部敏感哈希(LSH)的工作原理,它是一种通过哈希函数将相似项映射到相同符号的概率很高的技术。
图中展示了数据记录时如何应用多个哈希函数,并在搜索时如何使用相同的哈希函数来定位可能的候选项,然后通过欧几里得距离进行比较。
FLANN(Fast Library for Approximate Nearest Neighbors)是一个用于近似最近邻搜索的库,支持如随机化KD树和k均值树等数据结构。
它在2000年代末到2010年代初非常流行,已经被集成到OpenCV和PCL库中。
但FLANN的缺点是内存消耗大,且需要存储原始数据,目前也不再积极维护。
输入输出:
输入:一个查询向量和一个高维数据集。
输出:数据集中与查询向量最近的一个或多个最近邻向量。
import numpy as np
import pyflann
# 创建一个FLANN对象
flann = pyflann.FLANN()
# 生成随机样本数据
num_data = 1000
dim = 10
data = np.random.rand(num_data, dim).astype(np.float32)
# 训练数据集
flann.build_index(data, algorithm='kdtree')
# 生成一个查询向量
query = np.random.rand(dim).astype(np.float32)
# 搜索最近邻
result, _ = flann.nn_index(query, num_neighbors=5)
# 输出最近邻的索引
print(result)
Annoy 是另一个用于近似最近邻搜索的库,使用“2均值树”和“多树”以及“共享优先队列”来提高搜索的效率和准确度。
它随机选择两点来划分空间,并递归地重复这个过程,以构建出层次化的树结构。
通过这种方式,Annoy能够快速定位查询点所在的单元格,并比较距离以找到最近邻。
from annoy import AnnoyIndex
# 初始化AnnoyIndex
f = 40 # 维度
t = AnnoyIndex(f, 'angular') # 使用Angular距离
# 添加数据到索引
for i in range(1000):
v = [np.random.gauss(0, 1) for z in range(f)]
t.add_item(i, v)
# 构建索引
t.build(10) # 10棵树
# 保存索引
t.save('test.ann')
# 加载索引
u = AnnoyIndex(f, 'angular')
u.load('test.ann') # 快速加载
# 查询
print(u.get_nns_by_item(0, 3)) # 查询与第0个向量最近的3个邻居
PQ是一种将向量分割成子向量,并对每个子向量进行量化的方法,它简单且内存高效。
PQ通常通过对训练数据执行k均值聚类来事先训练,然后使用编码本来量化新的向量。
例如,在图像检索系统中,有一个高维的特征向量表示每个图像的内容。
PQ 可以用来减少这些特征向量的存储空间,同时保持能够快速检索相似图像的能力。
使用方法:
- 将高维向量分解为较小的子向量。
- 对每个子向量执行k均值聚类,创建一个编码本。
- 每个子向量由其在编码本中的索引表示。
- 用这些索引替换原始向量,以压缩数据。
在实际应用中,PQ通常与倒排索引结合使用,以在大型数据库中快速检索最近邻。
倒排索引允许系统只搜索与查询向量具有相似PQ编码的那些数据点,从而大大减少计算量。
主流向量数据库
全球主流向量数据库:Pinecone、Milvus、Vespa、Weaviate、Qdrant。
超过70%的向量数据库选择了开源,超过一半的向量数据库具有云化部署的能力。
大部分向量数据库产品在进行ANN相似性搜索时采用HNSW(Hierarchical Navigable Small World)算法。
对比每个向量数据库的特点、能力和架构选择。
- Pinecone:
- 网站:pinecone.io
- 这是一个托管的向量数据库,是封闭源代码的。
- 价值主张包括:
- 完全托管的向量数据库
- 单阶段过滤
- 水平扩展
- 实时索引更新
- 架构图展示了数据输入通过嵌入模型,到通过API网关、负载均衡器处理查询和更新,以及围绕Kubernetes pods结构化的向量数据库的工作流程。
Pinecone适用场景:
适合需要完全托管解决方案的企业,不愿意或没有资源自己维护和管理数据库基础设施。
由于其支持水平扩展和实时索引更新,Pinecone非常适合动态数据集和实时搜索应用,如个性化推荐系统和实时监测系统。
- Milvus:
- 网站:milvus.io
- 它是一个自托管的向量数据库,并且是开源的。
- 价值主张包括:
- 整个搜索引擎的可扩展性
- 使用多种近似最近邻(ANN)算法索引数据的能力
- 图表展示了架构,包括SDK、负载均衡器、协调服务、代理以及数据、索引和查询处理的不同节点。
Milvus 适用场景:
适合希望自主托管和拥有更大控制权的企业,特别是那些需要高度可扩展的搜索引擎和支持多种ANN算法的场合。
这可能包括大规模的相似性搜索任务,如图像或视频检索,以及在选择最佳算法方面需要灵活性的场景。
- Vespa:
- 网站:vespa.ai
- 可以托管或自托管,代码是开源的。
- 价值主张包括:
- 在大型数据集上进行低延迟计算
- 存储和索引数据,以便在服务时间进行查询、选择和处理
- 可定制的功能性和深度数据结构,适用于数据科学和深度学习
- 架构概览显示了HTTP请求处理、无状态Java容器集群和内容集群等组件。
Vespa 适用场景:
由于其低延迟处理大数据集的能力,Vespa适合需要高性能和实时查询的应用,如新闻文章、广告和推荐系统。
Vespa的可定制性和深度数据结构使其适合于复杂查询的场景,例如金融服务中的风险分析和实时决策支持。
- Weaviate:
- 网站:semi.technology/developers/weaviate/current/
- 可以托管或自托管,且是开源的。
- 价值主张包括:
- 表达式查询语法和类GraphQL的接口
- 向量搜索、对象存储和倒排索引的组合
- 令人印象深刻的问答组件,尤其适用于演示
- 图表显示了包含推理模块、API、业务逻辑和持久化层的系统级概览。
Weaviate 适用场景:
Weaviate的GraphQL-like接口和强大的问答组件使其非常适合需要复杂查询和自然语言处理能力的应用,如知识图谱、语义搜索和客户支持自动化。
它的接口友好性可能特别适合需要快速原型设计和演示的研发团队。
- Qdrant:
- 网站:qdrant.tech
- 它是一个自托管的向量数据库,云服务在规划路线中,并且是开源的。
- 价值主张包括:
- 带有扩展过滤支持的向量相似性引擎
- 动态查询规划和负载数据索引
- 字符串匹配、数值范围、地理位置等
- 度量深度学习
- 架构图描述了数据库分割成多个段的情况,有优化器、搜索器、索引器以及各种数据和索引存储组件。
Qdrant 适用场景:
Qdrant的优化器和扩展过滤支持使其适合需要高度优化和灵活查询规划的应用,如电子商务中的个性化推荐和多维度过滤。
其对动态查询规划和负载数据索引的支持还适用于需要处理各种类型数据的应用程序,包括地理位置数据和文本。
Milvus 实践
教程:https://milvus.io/docs
代码:https://github.com/milvus-io/milvus
基于您提供的描述,Milvus是一个强大的向量数据库系统,具有以下特点和架构层次:
特点:
-
易于使用:
- 快速部署:可以迅速创建大规模的相似性搜索服务。
- 简单直观的SDK:支持多种编程语言,降低学习曲线。
-
速度:
- 硬件效率高:充分利用硬件资源,提高性能。
- 高级索引算法:加速检索速度,比传统方法快10倍。
-
高可用性:
- 实战测试:在超过一千名企业用户中经过测试,证明了其实用性和稳定性。
- 系统组件广泛隔离:提高了系统的弹性和可靠性。
-
高度可扩展性:
- 分布式和高通量:适合处理大规模向量数据,保持高效服务。
- 适应大规模数据集:能够扩展以处理庞大的数据量。
-
云原生:
- 计算与存储分离:增加了灵活性,方便扩展。
- 系统化云原生方法:支持横向和纵向扩展。
-
功能丰富:
- 数据类型支持:可以处理各种类型的数据。
- 增强向量搜索:具有属性过滤等功能。
- UDF(用户定义函数)支持:为搜索和索引提供自定义功能。
- 可配置的一致性级别:适应不同的数据一致性要求。
- 时间旅行:能够访问数据的历史版本。
架构层次:
-
接入层(Access Layer):
- 由无状态代理组成,作为用户系统的接入点。
-
协调器服务(Coordinator Service):
- 分配任务,管理工作流程,是系统的中心神经系统。
-
工作节点(Worker Nodes):
- 执行操作,处理DML和DDL命令,是系统的执行部分。
-
存储(Storage):
- 数据持久性保障,包括元数据存储、日志代理和对象存储。