Elasticsearch:向量相似度计算 - 可笑的速度

作者:Chris Hegarty

任何向量数据库的核心都是距离函数,它确定两个向量的接近程度。 这些距离函数在索引和搜索期间执行多次。 当合并段或在图表中导航最近邻居时,大部分执行时间都花在比较向量的相似性上。 对这些距离函数进行微观优化是值得的,我们已经从之前类似的优化中受益,例如 参见 SIMD、FMA。

随着 Lucene 和 Elasticsearch 最近对标量量化的支持,我们现在比以往任何时候都更加依赖这些距离函数的 byte 变体。 根据之前的经验,我们知道这些变体仍有显着性能改进的潜力。

目前的状况

当我们利用巴拿马向量 API 来加速 Lucene 中的距离函数时,大部分注意力都集中在 float(32 位)变体上。 我们对这些方面所取得的性能改进感到非常满意。 然而,字节(8 位)变体的改进有点令人失望 - 相信我,我们尝试过! 字节变体的根本问题是它们没有充分利用 CPU 上可用的最佳 SIMD 指令。

在 Java 中进行算术运算时,最窄的类型是 int(32位)。 JVM 自动将字节值符号扩展为 int 类型的值。 考虑这个简单的标量点积实现:

int dotProduct(byte[] a, byte[] b) {int res = 0;for (int i = 0; i < a.length; i++) {res += a[i] * b[i];}return res;
}

a 和 b 中的元素相乘的执行方式就好像 a 和 b 都是 int 类型一样,其值是从符号扩展为 int 的相应数组索引加载的字节值。

我们的 SIMD 化实现必须是等效的,因此我们需要小心确保在乘以大字节值时不会丢失溢出。 我们通过显式地将加载的字节值扩展为 short(16位)来做到这一点,因为我们知道所有带符号的字节值相乘时都将适合带符号的 short 而不会丢失。 然后我们在累加时需要进一步扩展为 int (32 位)。

以下是 Lucene 128 位点积代码内循环体的摘录:

ByteVector va8 = ByteVector.fromArray(ByteVector.SPECIES_64, a, i);
ByteVector vb8 = ByteVector.fromArray(ByteVector.SPECIES_64, b, i);// process first "half" only: 16-bit multiply
Vector<Short> va16 = va8.convert(B2S, 0); // B2S Byte2Short
Vector<Short> vb16 = vb8.convert(B2S, 0);
Vector<Short> prod16 = va16.mul(vb16);// 32-bit add - S2I Short2Int
acc = acc.add(prod16.convertShape(S2I, IntVector.SPECIES_128, 0));

可视化这一点,我们可以看到我们一次只处理 4 个元素。 例如:

这一切都很好,即使有了这些显式的扩展对话,我们也可以通过算术运算的额外数据并行性获得一些不错的速度,只是没有我们知道的那么快。 我们知道还有剩余潜力的原因是,每次拓宽都会使车道数量减半,这实际上将算术运算的数量减半。 JVM 的 C2 JIT 编译器并未优化显式扩展对话。 此外,我们仅访问数据的下半部分 - 访问下半部分以外的任何内容都不会产生良好的机器代码。 这就是我们将潜在性能 “摆在桌面上” 的地方。

目前,这已经是我们在 Java 中所能做到的最好的了。 从长远来看,Panama Vector API 和/或 C2 JIT 编译器应该为此类操作提供更好的支持,但至少目前,这已经是我们能做的最好的了。 或者是吗?

介绍(另一个)巴拿马 API - FFM

OpenJDK 的巴拿马项目有几个不同的分支,我们已经看到了巴拿马向量 API 的实际应用,但该项目的旗舰是 Foregin Function and Memory API (FFM)。 FFM API 为与 Java 运行时之外的代码和内存交互提供了较低的开销。 JVM 是一项令人惊叹的工程,它抽象了架构和平台之间的许多差异,但有时它并不总是能够做出最佳权衡,这是可以理解的。 当 JVM 无法轻易做到这一点时,FFM 可以拯救我们,如果程序员不喜欢所做的权衡,那么她可以将事情掌握在自己手中。 这就是这样一个领域,巴拿马向量 API 的权衡对于 byte 大小的向量来说并不合适。

我们已经在利用 Lucene 中的外部内存支持来协调对映射的堆外索引数据的更安全的访问。 为什么不使用外部调用支持来调用已经优化的距离计算函数? 由于我们的距离计算函数很小,并且对于我们已经知道最佳 CPU 指令集的某些部署和架构集,为什么不只编写我们想要的一小块本机代码。 然后通过外部调用API来调用它。

采用外部函数 - going foregin

Elastic Cloud 具有针对向量搜索优化的配置文件。 此配置文件针对 ARM 架构,因此让我们看看如何对此进行优化。

让我们使用一些 ARM Neon 内在函数用 C 语言编写距离函数(例如点积)。 同样,我们将重点关注循环的内部主体。 看起来是这样的:

int32x4_t acc1, acc2 // = vdupq_n_s32(0);...
// Read into 16 x 8 bit vectors.
int8x16_t va8 = vld1q_s8((const void*)(a + i));
int8x16_t vb8 = vld1q_s8((const void*)(b + i));int16x8_t va16 = vmull_s8(vget_low_s8(va8), vget_low_s8(vb8));
int16x8_t vb16 = vmull_s8(vget_high_s8(va8), vget_high_s8(vb8));// Accumulate 4 x 32 bit vectors (adding adjacent 16 bit lanes).
acc1 = vpadalq_s16(acc1, va16);
acc2 = vpadalq_s16(acc2, vb16);

我们将 a 和 b 向量中的 16 个 8 位值分别加载到 va8 和 vb8 中。 然后,我们将下半部分相乘并将结果存储在 va16 中 - 该结果包含 8 个 16 位值,并且该操作隐式处理加宽。 与上半部分类似。 最后,由于我们对完整的原始 16 个值进行操作,因此使用两个累加器来存储结果会更快。 vpadalq_s16 加法和累加内在函数知道如何在累加到 4 个 32 位值时隐式扩展。 总之,我们在每个循环迭代中对所有 16 字节值进行了操作。 好的!

其反汇编非常干净并且反映了上述本质。

ldr    q2, [x1, x8]     # loads first vector data into 128-bit q2
ldr    q3, [x2, x8]     # loads second vector data into 128-bit q3
smull.8h   v4, v2, v3   # multiplies low half, result in v4
smull2.8h  v2, v2, v3   # multiplies high half, result in v2
sadalp.4s  v0, v4       # accumulates into v0
sadalp.4s  v1, v2       # accumulates into v1

ARM 上的 Neon SIMD 具有算术指令,可以提供我们想要的语义,而无需进行额外的显式扩展。 C 内联公开了这些指令,以便我们可以利用的方式使用这些指令。 对密集包含值的寄存器进行的操作比我们使用巴拿马向量 API 所做的要干净得多。

回到 Java-land

最后一个难题是 Java 中的一个小 “垫片 (shim)” 层,它使用 FFM API 链接到我们的外部代码。 我们的向量数据是堆外的,我们将其映射到 MemorySegment,并根据向量维度确定偏移量和内存地址

static int dot8s(MemorySegment a, MemorySegment b, int dims) {var mh$ = dot8s$MH();try {return (int)mh$.invokeExact(a, b, dims);} catch (Throwable ex$) {...}
}

我们还有更多的工作要做,因为现在这是特定于平台的 Java 代码,因此我们仅在 aarch64 平台上执行它,而回退到其他平台上的替代实现。

那么它实际上比巴拿马向量代码更快吗?

性能

上述有符号字节值的点积的微观基准显示,与巴拿马向量代码相比,性能提高了大约 6 倍。 这包括外部呼叫的开销。 加速的主要原因是我们能够将完整的 128 位寄存器与值打包在一起,并对所有这些值进行操作,而无需显式移动或扩展数据。

启用标量量化的宏基准测试 SO_Dense_Vector 显示出合并时间的显着改进,大约快了 3 倍 - 该实验仅插入了用于段合并的优化点积。 我们预计搜索基准也会有所改善。

概括

Java 的最新进展,即 FFM API,允许以比以前更高性能和更简单的方式与本机代码进行互操作。 通过提供通过 FFM 调用的微优化平台特定向量距离函数,可以获得显着的性能优势。

我们期待 Elasticsearch 的未来版本,其中标量量化向量可以利用这种性能改进。 当然,我们正在大量思考这与 Lucene 甚至巴拿马向量 API 的关系,以确定如何改进这些。

原文:Vector Similarity Computations - ludicrous speed — Elastic Search Labs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/271757.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言从入门到精通 第十二章(程序的编译及链接)

写在前面&#xff1a; 本系列专栏主要介绍C语言的相关知识&#xff0c;思路以下面的参考链接教程为主&#xff0c;大部分笔记也出自该教程。除了参考下面的链接教程以外&#xff0c;笔者还参考了其它的一些C语言教材&#xff0c;笔者认为重要的部分大多都会用粗体标注&#xf…

Doris-数据分区

数据分区&#xff1a;即将大表划分为小表&#xff0c;数据分区主要有两个级别&#xff1a;Partition和Bucket&#xff08;Tablet&#xff09;。 Partition&#xff1a;逻辑分区&#xff0c;按照一定规则将表按照行进行划分&#xff0c;每个部分就是一个Partition。 Bucket&…

根据用户名称实现单点登录

一、参数格式 二、后端实现 Controller层 public class IAccessTokenLoginController extends BaseController {Autowiredprivate ISysUserService sysUserService;Autowiredprivate ISingleTokenServiceImpl tokenService;/*** 登录方法** return 结果*/PostMapping("/l…

AI智能分析网关V4智慧园区视频智能监管方案

一、背景需求分析 随着科技的不断发展&#xff0c;智慧园区建设已成为现代城市发展的重要方向。通过智能化技术提高园区的运营效率、降低成本、增强环境可持续性等具有重要作用。视频智能监管作为智慧园区安全管理体系的重要组成部分&#xff0c;对于提高园区的安全管理水平和…

手写简易操作系统(一)--环境配置

本专栏是我新开设的一个学术专栏&#xff0c;旨在全面介绍手写操作系统的相关内容。其中包括实模式向保护模式的过渡、锁机制、信号量操作、内存分配、硬盘驱动、文件系统、简单shell和管道等操作系统核心知识。该专栏旨在为有意开发自己操作系统的研究人员提供指导与帮助。作为…

阿里云服务器怎么使用?3分钟搭建网站教程2024新版

使用阿里云服务器快速搭建网站教程&#xff0c;先为云服务器安装宝塔面板&#xff0c;然后在宝塔面板上新建站点&#xff0c;阿里云服务器网aliyunfuwuqi.com以搭建WordPress网站博客为例&#xff0c;来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流…

探索数据结构:单链表的实战指南

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 贝蒂的主页&#xff1a;Betty‘s blog 前言 在上一章节中我们讲解了数据结构中的顺序表&#xff0c;知道了顺序…

【校园导航小程序】2.0版本 静态/云开发项目 升级日志

演示视频 【校园导航小程序】2.0版本 静态/云开发项目 演示 首页 重做了首页&#xff0c;界面更加高效和美观 校园指南页 新增了 “校园指南” 功能&#xff0c;可以搜索和浏览校园生活指南 地图页 ①弃用路线规划插件&#xff0c;改用SDK开发包。可以无阻通过审核并发布…

吴恩达机器学习-可选实验室:特征工程和多项式回归(Feature Engineering and Polynomial Regression)

文章目录 目标工具特征工程和多项式回归概述多项式特征选择功能备用视图扩展功能复杂的功能 恭喜! 目标 在本实验中&#xff0c;你将:探索特征工程和多项式回归&#xff0c;它们允许您使用线性回归的机制来拟合非常复杂&#xff0c;甚至非常非线性的函数。 工具 您将利用在以…

【vue2基础教程】vue指令

文章目录 前言一、内容渲染指令1.1 v-text1.2 v-html1.3 v-show1.4 v-if1.5 v-else 与 v-else-if 二、事件绑定指令三、属性绑定指令总结 前言 Vue.js 是一款流行的 JavaScript 框架&#xff0c;广泛应用于构建交互性强、响应速度快的现代 Web 应用程序。Vue 指令是 Vue.js 中…

cf火线罗技鼠标宏最细教程(鬼跳,上箱,一键顺,usp速点,雷神三连发及压枪,AK火麒麟压枪.lua脚本)

一.前言 因为我发现火线的鼠标宏非常多&#xff0c;想着自己也有罗技鼠标&#xff0c;看能不能自己写一写让游玩的时候更方便操作一些&#xff0c;可能不一定有什么帮助&#xff0c;但也是一个学习的过程&#xff0c;下面就把我自己的心得和代码详细的记录下来&#xff0c;好多…

注意力机制(代码实现案例)

学习目标 了解什么是注意力计算规则以及常见的计算规则.了解什么是注意力机制及其作用.掌握注意力机制的实现步骤. 1 注意力机制介绍 1.1 注意力概念 我们观察事物时&#xff0c;之所以能够快速判断一种事物(当然允许判断是错误的), 是因为我们大脑能够很快把注意力放在事物…

C语言从入门到精通 第十一章(文件操作)

写在前面&#xff1a; 本系列专栏主要介绍C语言的相关知识&#xff0c;思路以下面的参考链接教程为主&#xff0c;大部分笔记也出自该教程。除了参考下面的链接教程以外&#xff0c;笔者还参考了其它的一些C语言教材&#xff0c;笔者认为重要的部分大多都会用粗体标注&#xf…

算法刷题day25:多路归并

目录 引言概念一、鱼塘钓鱼二、技能升级三、序列 引言 关于这个多路并归蓝桥杯考的不是很多&#xff0c;如果要出的话&#xff0c;可能模型都会差不多&#xff0c;因为不会出太难的题&#xff0c;难题基本上都是贪心、DP之类的&#xff0c;所以好好刷题刷熟练就行了&#xff0…

Vue事件处理:.passive修饰符与应用场景

.passive修饰符 passive这个修饰符会执行默认方法。你们可能会问&#xff0c;明明默认执行为什么会设置这样一个修饰符。这就要说一下这个修饰符的本意了。 浏览器只有等内核线程执行到事件监听器对应的JavaScript代码时&#xff0c;才能知道内部是否会调用preventDefa…

一次电脑感染Synaptics Pointing Device Driver病毒的经历,分享下经验

没想到作为使用电脑多年的老司机也会电脑中病毒&#xff0c;周末玩电脑的时候突然电脑很卡&#xff0c;然后自动重启&#xff0c;奇怪&#xff0c;之前没出现这个情况。 重启后电脑开机等了几十秒&#xff0c;打开任务管理器查看开机进程&#xff0c;果然发现有个Synaptics Po…

【计网】TCP协议安全与风险:深入探讨网络通信的基石

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 &#x1f310;前言 &#x1f512;正文 TCP (Transmission Control Protocol): UDP (User Datagram Protocol): HTTP (Hypertext Transfer …

【动态规划.3】[IOI1994]数字三角形 Number Triangles

题目 https://www.luogu.com.cn/problem/P1216 观察下面的数字金字塔。 写一个程序来查找从最高点到底部任意处结束的路径&#xff0c;使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。 7→3→8→7→5 的路径产生了最大权值。 分析 这是一个动态规划…

3.8 动态规划 背包问题

一.01背包 46. 携带研究材料&#xff08;第六期模拟笔试&#xff09; (kamacoder.com) 代码随想录 (programmercarl.com) 携带研究材料: 时间限制&#xff1a;5.000S 空间限制&#xff1a;128MB 题目描述: 小明是一位科学家&#xff0c;他需要参加一场重要的国际科学大会…

杨辉三角(附html,Python,c++杨辉三角代码)

1、前言 杨辉三角很早学编程就知道&#xff0c;但不知道杨辉是古人&#xff01; 一次偶然的机会&#xff0c;和杨辉三角对上了眼神——杨辉&#xff01;究竟你是怎么发现杨辉三角的呢&#xff1f; 于是经过了长达3个月锲而不舍的探究。 终究也没发现自己想要的最终结果。 …