f16
和 i8
- 半精度和四分之一精度支持。uint40_t
的空间高效点云,可容纳超过4B的大小。__技术洞察__和相关文章:
for
循环。sqrt
调用。PyArg_ParseTuple
以提高速度。FAISS是广受认可的高性能向量搜索引擎标准。 USearch和FAISS都使用相同的HNSW算法,但在设计原则上有显著差异。 USearch在不牺牲性能的情况下更加紧凑和广泛兼容,主要关注用户自定义度量和更少的依赖。
FAISS | USearch | 改进 | |
---|---|---|---|
索引时间 ⁰ | |||
1亿个96维 f32 、f16 、i8 向量 | 2.6 · 2.6 · 2.6 h | 0.3 · 0.2 · 0.2 h | 9.6 · 10.4 · 10.7 x |
1亿个1536维 f32 、f16 、i8 向量 | 5.0 · 4.1 · 3.8 h | 2.1 · 1.1 · 0.8 h | 2.3 · 3.6 · 4.4 x |
代码库长度 ¹ | 84 K SLOC | 3 K SLOC | 可维护 |
支持的度量 ² | 9种固定度量 | 任意度量 | 可扩展 |
支持的语言 ³ | C++, Python | 10种语言 | 可移植 |
支持的ID类型 ⁴ | 32位, 64位 | 32位, 40位, 64位 | 高效率 |
过滤 ⁵ | 禁用列表 | 任意谓词 | 可组合 |
所需依赖 ⁶ | BLAS, OpenMP | - | 轻量级 |
绑定 ⁷ | SWIG | 原生 | 低延迟 |
Python绑定大小 ⁸ | ~ 10 MB | < 1 MB | 易部署 |
⁰ 在Intel Sapphire Rapids上测试,使用最简单的内积距离,等效召回率和内存消耗,同时还提供了更优的搜索速度。 ¹
usearch/
相比faiss/
更短的代码库使项目更易于维护和审核。 ² 用户自定义度量允许你为各种应用定制搜索,从GIS到为多个AI模型的复合嵌入或混合全文和语义搜索创建自定义度量。 ³ 使用USearch,你可以在各种编程语言中重用同一个预构建索引。 ⁴ 40位整数允许你存储超过4B个向量,而无需为邻近图中的每个邻居引用分配8字节。 ⁵ 使用USearch,索引可以与任意外部容器(如布隆过滤器或第三方数据库)结合,在索引遍历期间过滤掉不相关的键。 ⁶ 缺少必要的依赖使USearch更加可移植。 ⁷ 原生绑定比更简单的方法引入更低的调用延迟。 ⁸ 更轻量的绑定使下载和部署更快。
基本功能与FAISS相同,如果你曾研究过近似最近邻搜索,接口应该很熟悉:
# pip install numpy usearch import numpy as np from usearch.index import Index index = Index(ndim=3) vector = np.array([0.2, 0.6, 0.4]) index.add(42, vector) matches = index.search(vector, 10) assert matches[0].key == 42 assert matches[0].distance <= 0.001 assert np.allclose(index[42], vector, atol=0.1) # 确保在混合精度比较中使用高容差
更多设置始终可用,API设计旨在尽可能灵活。
默认存储/量化级别取决于硬件以提高效率,但对大多数现代CPU推荐使用f16
。
index = Index( ndim=3, # 定义输入向量的维度数 metric='cos', # 选择'l2sq'、'ip'、'haversine'或其他度量,默认='cos' dtype='f16', # 存储为'f64'、'f32'、'f16'、'i8'、'b1'...,默认=None connectivity=16, # 可选:限制每个图节点的邻居数 expansion_add=128, # 可选:控制索引的召回率 expansion_search=64, # 可选:控制搜索质量 multi=False, # 可选:允许每个键多个向量,默认=False )
Index
USearch支持多种序列化形式:
后者允许你从外部内存提供索引服务,使你能够针对索引速度和服务成本优化服务器选择。 这可以在AWS和其他公共云上实现__20倍的成本降低__。
index.save("index.usearch") loaded_copy = index.load("index.usearch") view = Index.restore("index.usearch", view=True) other_view = Index(ndim=..., metric=...) other_view.view("index.usearch")
当精确的暴力搜索变得过于资源密集时,通常会使用近似搜索方法,如HNSW。
这通常发生在集合中有数百万个条目时。
对于较小的集合,我们提供了一种更直接的方法,即search
方法。
from usearch.index import search, MetricKind, Matches, BatchMatches import numpy as np # 生成10'000个随机向量,每个向量有1024个维度 vectors = np.random.rand(10_000, 1024).astype(np.float32) vector = np.random.rand(1024).astype(np.float32) one_in_many: Matches = search(vectors, vector, 50, MetricKind.L2sq, exact=True) many_in_many: BatchMatches = search(vectors, vectors, 50, MetricKind.L2sq, exact=True)
如果传入exact=True
参数,系统将完全绕过索引,使用来自SimSIMD的SIMD优化相似度度量,对整个数据集执行暴力搜索。
与FAISS的IndexFlatL2
在Google Colab上相比,USearch可能提供高达20倍的性能提升:
faiss.IndexFlatL2
: 55.3毫秒。usearch.index.search
: 2.54毫秒。虽然大多数向量搜索包只专注于两种度量,即"内积距离"和"欧几里德距离",但USearch允许使用任意用户自定义度量。 这种灵活性使您可以为各种应用定制搜索,从使用罕见的Haversine距离计算地理空间坐标,到为多个AI模型的复合嵌入创建自定义度量,如联合图像-文本嵌入。 您可以使用Numba、Cppyy或PeachPy来在Python中定义自定义度量:
from numba import cfunc, types, carray from usearch.index import Index, MetricKind, MetricSignature, CompiledMetric @cfunc(types.float32(types.CPointer(types.float32), types.CPointer(types.float32))) def python_inner_product(a, b): a_array = carray(a, ndim) b_array = carray(b, ndim) c = 0.0 for i in range(ndim): c += a_array[i] * b_array[i] return 1 - c metric = CompiledMetric(pointer=python_inner_product.address, kind=MetricKind.IP, signature=MetricSignature.ArrayArray) index = Index(ndim=ndim, metric=metric, dtype=np.float32)
在C、C++和Rust接口中实现类似效果甚至更容易。 此外,与KD树和局部敏感哈希等较旧的高维空间索引方法不同,HNSW不要求向量长度相同。 它们只需要可比较。 因此,您可以在奇特的应用中使用它,比如搜索相似集合或模糊文本匹配,使用GZip压缩率作为距离函数。
有时您可能想要根据某些外部数据库交叉引用搜索结果或根据某些条件过滤它们。 在大多数引擎中,您必须手动执行分页请求,逐步过滤结果。 在USearch中,您只需将谓词函数传递给搜索方法,该函数将直接在图遍历过程中应用。 在Rust中,这看起来像这样:
let is_odd = |key: Key| key % 2 == 1; let query = vec![0.2, 0.1, 0.2, 0.1, 0.3]; let results = index.filtered_search(&query, 10, is_odd).unwrap(); assert!( results.keys.iter().all(|&key| key % 2 == 1), "所有键必须为奇数" );
训练量化模型和降维是加速向量搜索的常见方法。
然而,这些方法并不总是可靠的,可能会显著影响数据的统计属性,并且如果分布发生变化,需要定期调整。
相反,我们专注于对降精度向量进行高精度运算。
相同的索引、add
和search
操作将自动在f64_t
、f32_t
、f16_t
、i8_t
和单比特表示之间进行降精度或提升精度。
您可以使用以下命令检查是否启用了硬件加速:
$ python -c 'from usearch.index import Index; print(Index(ndim=768, metric="cos", dtype="f16").hardware_acceleration)' > sapphire $ python -c 'from usearch.index import Index; print(Index(ndim=166, metric="tanimoto").hardware_acceleration)' > ice
使用较小的数值类型将节省存储向量所需的RAM,但您也可以压缩形成我们近邻图的邻居列表。
默认情况下,使用32位的uint32_t
来枚举这些列表,但如果需要寻址超过40亿个条目,这是不够的。
对于这种情况,我们提供了一个自定义的uint40_t
类型,它仍然比常用的8字节整数节省37.5%的空间,并且可以扩展到1万亿个条目。
Indexes
用于多索引查找对于针对数十亿甚至万亿向量的大型工作负载,并行多索引查找变得非常有价值。 您可以构建多个较小的索引,而不是构建一个大型索引,并将它们一起查看。
from usearch.index import Indexes multi_index = Indexes( indexes: Iterable[usearch.index.Index] = [...], paths: Iterable[os.PathLike] = [...], view: bool = False, threads: int = 0, ) multi_index.search(...)
一旦构建了索引,USearch可以比独立的聚类库(如SciPy、UMap和tSNE)更快地执行K近邻聚类。
对PCA进行降维也是如此。
本质上,Index
本身可以被视为一种聚类,允许迭代深化。
clustering = index.cluster( min_count=10, # 可选 max_count=15, # 可选 threads=..., # 可选 ) # 获取聚类及其大小 centroid_keys, sizes = clustering.centroids_popularity # 使用Matplotlib绘制直方图 clustering.plot_centroids_popularity() # 导出聚类的NetworkX图 g = clustering.network # 获取特定聚类的成员 first_members = clustering.members_of(centroid_keys[0]) # 深入到该聚类,将其分成更多部分,支持所有相同的参数 sub_clustering = clustering.subcluster(min_count=..., max_count=...)
生成的聚类结果与K-Means或其他传统方法不完全相同,但serve相同的目的。 另外,在使用Scikit-Learn处理100万数据点的数据集时,查询可能需要几分钟到几小时的时间,具体取决于您想要突出显示的聚类数量。 对于50,000个聚类,USearch与传统聚类方法的性能差异可能轻松达到100倍。
当今的一个重大问题是人工智能将如何改变数据库和数据管理的世界。 大多数数据库仍在努力实现高质量的模糊搜索,而且它们所知道的唯一连接类型是确定性的。 "连接"与搜索每个条目不同,它需要一对一映射,禁止在不同的搜索结果之间出现冲突。
精确搜索 | 模糊搜索 | 语义搜索? |
---|---|---|
精确连接 | 模糊连接? | 语义连接?? |
使用USearch,可以实现亚二次复杂度的近似、模糊和语义连接。 这在数据库管理软件常见的任何模糊匹配任务中都很有用。
men = Index(...) women = Index(...) pairs: dict = men.join(women, max_proposals=0, exact=False)
阅读更多内容,请参阅文章:语义搜索的组合稳定婚姻 💍
目前,所有绑定都支持核心功能。 更广泛的功能按需移植。 在某些情况下,如批处理操作,功能对等是没有意义的,因为宿主语言具有完整的多线程能力,而USearch索引结构在设计上是并发的,因此用户可以以最适合其应用的方式实现批处理/调度/负载平衡。
C++ 11 | Python 3 | C 99 | Java | JavaScript | Rust | GoLang | Swift | |
---|---|---|---|---|---|---|---|---|
添加、 搜索、删除 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
保存、加载、查看 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
用户自定义度量 | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
批处理操作 | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
过滤谓词 | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |
连接 | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
可变长度向量 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
4B+容量 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
人工智能有越来越多的应用,但最酷的经典想法之一是将其用于语义搜索。 可以使用多模态编码器模型,如UForm,以及Web编程框架,如UCall,仅用20行Python代码就可以构建一个文本到图像的搜索平台。
from ucall import Server from uform import get_model, Modality from usearch.index import Index import numpy as np import PIL as pil processors, models = get_model('unum-cloud/uform3-image-text-english-small') model_text = models[Modality.TEXT_ENCODER] model_image = models[Modality.IMAGE_ENCODER] processor_text = processors[Modality.TEXT_ENCODER] processor_image = processors[Modality.IMAGE_ENCODER] server = Server() index = Index(ndim=256) @server def add(key: int, photo: pil.Image.Image): image = processor_image(photo) vector = model_image(image) index.add(key, vector.flatten(), copy=True) @server def search(query: str) -> np.ndarray: tokens = processor_text(query) vector = model_text(tokens) matches = index.search(vector.flatten(), 3) return matches.keys server.run()
类似的体验也可以在其他语言和客户端实现,消除网络延迟。
对于Swift和iOS,请查看ashvardanian/SwiftSemanticSearch
仓库。
GitHub上提供了一个更完整的Streamlit演示。 我们已预处理了一些常用数据集,清理了图像,生成了向量,并预构建了索引。
数据集 | 模态 | 图像数 | 下载 |
---|---|---|---|
Unsplash | 图像和描述 | 25 K | HuggingFace / Unum |
Conceptual Captions | 图像和描述 | 3 M | HuggingFace / Unum |
Arxiv | 标题和摘要 | 2 M | HuggingFace / Unum |
比较分子图和搜索相似结构是昂贵且缓慢的过程。 这可以被视为NP完全子图同构问题的一个特例。 幸运的是,存在针对特定领域的近似方法。 化学领域常用的方法是从SMILES生成结构,然后将其哈希为二进制指纹。 后者可以使用二进制相似度度量(如Tanimoto系数)进行搜索。 以下是使用RDKit包的示例。
from usearch.index import Index, MetricKind from rdkit import Chem from rdkit.Chem import AllChem import numpy as np molecules = [Chem.MolFromSmiles('CCOC'), Chem.MolFromSmiles('CCO')] encoder = AllChem.GetRDKitFPGenerator() fingerprints = np.vstack([encoder.GetFingerprint(x) for x in molecules]) fingerprints = np.packbits(fingerprints, axis=1) index = Index(ndim=2048, metric=MetricKind.Tanimoto) keys = np.arange(len(molecules)) index.add(keys, fingerprints) matches = index.search(fingerprints, 10)
该方法被用于构建"USearch Molecules",这是最大的化学信息学数据集之一,包含70亿个小分子和280亿个指纹。
类似于向量和分子搜索,USearch也可用于地理信息系统。 Haversine距离是现成可用的,但你也可以定义更复杂的关系,如考虑地球扁率的Vincenty公式。
from numba import cfunc, types, carray import math # 将维度定义为2,表示纬度和经度 ndim = 2 # 自定义度量的签名 signature = types.float32( types.CPointer(types.float32), types.CPointer(types.float32)) # WGS-84椭球参数 a = 6378137.0 # 长半轴(米) f = 1 / 298.257223563 # 扁率 b = (1 - f) * a # 短半轴 def vincenty_distance(a_ptr, b_ptr): a_array = carray(a_ptr, ndim) b_array = carray(b_ptr, ndim) lat1, lon1, lat2, lon2 = a_array[0], a_array[1], b_array[0], b_array[1] L, U1, U2 = lon2 - lon1, math.atan((1 - f) * math.tan(lat1)), math.atan((1 - f) * math.tan(lat2)) sinU1, cosU1, sinU2, cosU2 = math.sin(U1), math.cos(U1), math.sin(U2), math.cos(U2) lambda_, iterLimit = L, 100 while iterLimit > 0: iterLimit -= 1 sinLambda, cosLambda = math.sin(lambda_), math.cos(lambda_) sinSigma = math.sqrt((cosU2 * sinLambda) ** 2 + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) ** 2) if sinSigma == 0: return 0.0 # 重合点 cosSigma, sigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda, math.atan2(sinSigma, cosSigma) sinAlpha, cos2Alpha = cosU1 * cosU2 * sinLambda / sinSigma, 1 - (cosU1 * cosU2 * sinLambda / sinSigma) ** 2 cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cos2Alpha if not math.isnan(cosSigma - 2 * sinU1 * sinU2 / cos2Alpha) else 0 # 赤道线 C = f / 16 * cos2Alpha * (4 + f * (4 - 3 * cos2Alpha)) lambda_, lambdaP = L + (1 - C) * f * (sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM ** 2)))), lambda_ if abs(lambda_ - lambdaP) <= 1e-12: break if iterLimit == 0: return float('nan') # 公式未收敛 u2 = cos2Alpha * (a ** 2 - b ** 2) / (b ** 2) A = 1 + u2 / 16384 * (4096 + u2 * (-768 + u2 * (320 - 175 * u2))) B = u2 / 1024 * (256 + u2 * (-128 + u2 * (74 - 47 * u2))) deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM ** 2) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma ** 2) * (-3 + 4 * cos2SigmaM ** 2))) s = b * A * (sigma - deltaSigma) return s / 1000.0 # 距离(公里) # 使用示例: index = Index(ndim=ndim, metric=CompiledMetric( pointer=vincenty_distance.address, kind=MetricKind.Haversine, signature=MetricSignature.ArrayArray, ))
@software{Vardanian_USearch_2023, doi = {10.5281/zenodo.7949416}, author = {Vardanian, Ash}, title = {{USearch by Unum Cloud}}, url = {https://github.com/unum-cloud/usearch}, version = {2.13.4}, year = {2023}, month = oct, }
AI小说写作助手,一站式润色、改写、扩写
蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。
字节跳动发布的AI编程神器IDE
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。
全能AI智能助手,随时解答生活与工作的多样问题
问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。
实时语音翻译/同声传译工具
Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。
一键生成PPT和Word,让学习生活更轻松
讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。
深度推理能力全新升级,全面对标OpenAI o1
科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。
一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型
Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。
AI助力,做PPT更简单!
咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。
选题、配图、成文,一站式创作,让内容运营更高效
讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。
专业的AI公文写作平台,公文写作神器
AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。
最新AI工具、AI资讯
独家AI资源、AI项目落地
微信扫一扫关注公众号