Meta FAIR 开源 e-means:k-means 十分之一的轮数跑出更低损失,已并入 Faiss

如果你的检索、推荐或者向量量化流水线里有聚类这一步,它用的更新规则大概率还是 Lloyd 在上世纪五十年代写下的那一个:把每个点分配给最近的中心,再把中心重算为分配点的均值,全量数据过一遍,重复二三十轮。硬件换了几代,向量维度从几十涨到几千,这一步的内核几乎没有变过。2026 年 11 月,Meta FAIR 的 Swann Bessa 与 Hugo Touvron、Hervé Jégou 等人开源了 e-means,把这套全批量更新换成带遗忘率的迷你批量更新,配上一套用标度律自动调参的机制,项目页放出当天就登上了 Hacker News 首页。官方在二十多个数据集上的结论是:用 Lloyd 二十五轮大约十分之一的轮数,拿到更低的聚类损失,墙钟时间在 GPU 上比最快的 Lloyd 实现还要快十到四十五倍。这篇就把它的机制、数字和调用方式拆开看。

Lloyd 循环的代价:全批量是机器学习里的独苗

k-means 的目标函数很朴素:给定 n 个 d 维向量和簇数 k,找 k 个中心,让所有点到最近中心的均方距离最小。难的是优化。Lloyd 的做法是全批量:每一轮把全部 n 个点重新分配一遍,用全部数据重算每个中心。一轮就是一次完整的数据遍历,二十到五十轮是工程常态。

在深度学习时代,这几乎是个异类。训练神经网络的标配是迷你批量加随机梯度,数据分成小批反复更新参数,而 k-means 领域的主流实现,包括以速度著称的 Faiss,仍然在做全批量更新。不是没人试过迷你批量。MacQueen 在 1967 年就给出过增量式规则:新来一批点,就把簇的计数和累加和直接加上去,中心等于历史上全部分配点的均值。这个规则的问题在于历史太长------训练早期中心位置很差时分配进来的点,永远压在均值里甩不掉,陈旧信息一路拖累后期精度。后来的 Staleness-Reduction 混合方法做过修补,但只在簇数很小的场景里体现出加速。迷你批量这条路于是被搁置了将近六十年,直到 e-means 把它重新捡起来,换上了深度学习的现代工具箱。

全批量路线的代价在今天被进一步放大。向量嵌入的维度普遍到了几百甚至三千维,数据规模从一百万到一亿条不等,一次全量遍历就是一次完整的最近邻扫描,二十几轮叠起来是实打实的算力账单。更隐蔽的问题在质量上:全批量每一步都朝损失下降最快的方向走到底,看似稳健,实则把优化路径锁死在了初始中心划定的吸引域里。后文会展开讲,这种单调下降正是 Lloyd 容易困在局部极小值的结构性原因,也是迷你批量路线被重新评估的动机。

e-means 的四件套:动量更新、余弦退火、死簇复活、精确收尾

e-means 的核心是把 MacQueen 式的累加换成指数滑动平均。每个簇维护计数 N 和向量和 S,中心取两者的比值;每来一个小批量,旧统计按一减步长的比例衰减,新批量按步长计入,即 S 更新为一减α乘旧 S、再加α乘本批的 s。α 就是遗忘率:早期差劲的分配会在若干步内被自然忘掉,中心始终跟踪最近的分配状态。这正是 VQ-VAE 训练码本时用的更新方式,e-means 的发现是它对静态数据集同样极其有效,前提是其余组件配套、超参数调对。

为什么不用梯度下降?作者的实验很直接:滑动平均更新保证中心永远落在分配点的凸包之内,而梯度更新在大学习率下会冲出凸包、表现不稳。在 DEEP 一百万向量和 SIFT 一千万向量、16384 个簇、五轮训练的设置下,梯度下降即使调到最佳,损失仍比滑动平均高 0.4% 到 1.6%。

围绕主规则还有三个配套设计。步长 α 按余弦曲线从初始值退火到十分之一,和深度学习里的学习率调度同一原理。死簇复活换了策略:不再像 EnCodec 那样从批量里随机抽点顶替死掉的中心,而是按簇大小成比例地挑一个大簇劈成两个,保住码本容量。收尾阶段把每个中心精算为最后一轮分配点的确切均值,用几乎为零的额外开销换一截损失下降。

超参数不用调:标度律直接算出批大小和步长

迷你批量方法历史上最大的使用门槛是调参:批量多大、步长多长,不同数据集的答案完全不同。e-means 的解法是拟合两条标度律。批大小 B 写成常数乘 k、n、轮数 T 各自幂次的幂律形式,初始步长 α0 同理由 k、B、n、T 的幂律给出,并在 1 处截断。两条律在一批数据集上拟合,再到没见过的数据集和规模上验证:留出数据集的 loss 遗憾值中位数只有万分之七,留出规模的遗憾值在同一量级,拟合优度 R 方在 0.95 上下。对使用者的含义很直白:调用时需要给的参数和 Lloyd 一样,只有簇数和轮数。

这里值得多说一句遗憾值的含义。它是用标度律给定的超参数跑出的损失,和穷搜整个超参数网格找到的最优损失之间的相对差距。万分之七意味着自动选出的配置几乎贴着穷搜的最优点,工程师省掉的是整套网格搜索的试错成本。官方还给了两条批大小律供选择:默认律吞吐优先,质量律牺牲一部分速度换更好的聚类质量,两条律的指数完全相同,只是常数不同,切换的成本就是改一个枚举值。

这组标度律还顺手回答了一个老问题。Lloyd 其实是 e-means 的极端特例:把批大小设为全量 n、步长设为 1,一次 e-means 迭代就精确退化成一次 Lloyd 迭代。但在批大小乘步长的损失地形图上,Lloyd 落在角落里,远远偏离损失最低的那条对角带------大批量必须配大步长,而 Lloyd 的全批量配等效步长 1 的组合恰好是最差的区域。沿用了几十年的默认配置,在新框架下被证明是超参数空间里的一个差角。

数字对比:十分之一的轮数,更低的损失

官方在 24 个嵌入和合成数据集上做了系统验证,主结果可以这样概括:Lloyd 跑到 25 轮收敛处的测试损失,e-means 用 1.2 到 3 轮就能追平甚至更低。在 VIBE 嵌入基准的 11 个数据集上------覆盖文本、代码、图像和多模态嵌入,维度 200 到 3072,簇数 8192 或 16384------每个数据集所需轮数稳定在 1.6 到 2.4 之间,对照 Lloyd 的 25 轮。轮数省下来之后,墙钟时间还叠加了内核收益:作者为最近中心分配写了融合内核,把算法优势翻译成实打实的时间收益。在一千万向量、65536 个簇、单张 H100 的测试里,朴素 PyTorch 版 Lloyd 的 25 轮要 142 到 155 秒,最快的 Lloyd 实现 Flash-KMeans 要 14 到 22 秒,而 e-means 端到端再快十到四十五倍;CPU 上对照 Faiss 也有八到十五倍。

指标 Lloyd(全批量) e-means
追平 Lloyd 25 轮测试损失所需轮数 25(基准) 1.2--3 轮
GPU 墙钟时间(对照 Flash-KMeans) 基准 快 10--45 倍
CPU 墙钟时间(对照 Faiss) 基准 快 8--15 倍
需手调的超参数 仅簇数与轮数 同样为零,标度律自动给定

这组数字的特殊之处在于:以往 k-means 的加速方法几乎都要在速度和质量之间做取舍,e-means 是两头同时更好,这也是论文标题敢直接写超越的底气。还有一个细节容易被忽略:项目主页的演示里,十万个点、两百个簇的数据上,Lloyd 一轮只做一次更新,e-means 一轮做九十七次更新,两者按轮数对齐比较时,e-means 的单次更新成本被摊得极薄。需要注意,这些数字全部来自官方论文与项目页,第三方复现还没有大规模出现,读者在自己的负载上验证之前,宜把它们看作官方口径而非社区共识。

为什么更能跳出局部极小值

速度快好理解,迷你批量为什么质量也更好?作者用玩具数据做了机制层面的验证。两个大小悬殊的簇、要求分八类的场景里,Lloyd 经常把两个中心压在小簇上、大簇反而缺中心,重复两百个随机起点,有 26% 的次数卡在病态配置里出不来;e-means 从同样的起点出发,几轮之内就能爬出来,卡壳率只有 3.5%。三乘三网格共九个簇、要求分十类的场景里,Lloyd 的卡壳率是 43%,e-means 是 4%。五个簇排成一线分五类,Lloyd 有 46% 的起点被困住,e-means 是零。

作者的解释合乎直觉:Lloyd 的损失每轮严格下降,这听起来是优点,实则意味着它一旦陷入局部极小就只会原地利用、永不探索;迷你批量带来的噪声更新反而提供了跳出陷阱的扰动,类似随机梯度在神经网络训练里的隐式正则效果。死簇复活的对照数据指向同一结论:一百万向量、16384 个簇的设置下,关掉复活策略会有 26.3% 的簇死掉,EnCodec 那种从批量随机顶替的策略仍有 14.3% 的死簇,而按比例劈分大簇的策略把死簇压到 0.3%,测试损失随之一路下降。质量优势的来源不是单点技巧,而是更新规则、调度与复活策略的组合。

这对日常工程的意义在于,聚类结果的方差变小了。用 Lloyd 跑大簇数任务时,换一批初始中心结果可能肉眼可见地变差,工程上的应对通常是多跑几次取最优,这把账单的倍数又翻了上去。e-means 在玩具实验里展现的稳定性如果在大规模数据上成立,意味着同样的精度预算下可以少跑多次重试,这部分隐性节省往往比墙钟时间本身更值钱。

在 Faiss 里直接调用

代码已经并进 Faiss 主仓库的 contrib 目录,不在单独的实验仓库里,这是它能立刻进生产评估的关键。接口只有三行:

python 复制代码
from faiss.contrib.e_means import Emeans  # NumPy 数组用 NumpyEmeans

em = Emeans(d, k, nepochs=T)      # T 为训练轮数,默认 5
centroids, labels = em.train(x)   # x 是形状为 (n, d) 的 PyTorch 张量

返回的 centroids 是学出的 k 个中心,labels 是最后一轮每个向量的簇归属。默认五轮的设置来自论文实验:这个轮数对 Lloyd 远远不够,对 e-means 已经富余。接口与 Faiss 现有 k-means 对齐,意味着迁移成本主要是改一行导入、换掉训练调用,数据布局与设备放置都不用动。项目页还放了一个浏览器内的交互演示,可以直接观察两种算法在同一数据上的收敛差异,给团队做技术汇报时是现成的素材。对已经在用 Faiss 做聚类或向量量化的团队,这是一天内就能完成接入评估的改动量级。

几个上手细节值得提前知道。训练入口接受的是 PyTorch 张量,论文的墙钟时间实验就是在数据常驻 GPU、bf16 精度的配置下测的,评估时对齐这个配置,测出来的数字才和官方口径可比;如果手头只有 NumPy 数组,用 NumpyEmeans 这个变体即可,不必先转框架。轮数参数默认是 5,从论文的收敛曲线看,多数数据集在两轮上下就已越过 Lloyd 二十五轮的水平,追求极致质量可以把轮数和质量律一起调,但收益会快速递减。输入数据不需要事先归一化,算法本身只做距离计算,不过如果你的向量来自不同量纲的特征拼接,先做标准化仍然是聚类任务的通用前提,与算法选择无关。

eval 阶段的验证建议这样做:固定同一批初始中心,用原有实现和 e-means 各跑一次,直接比较测试集上的均方误差和簇大小分布。死簇数量是第二个必看指标,尤其在簇数上万的码本场景,劈分复活策略和随机顶替策略的差距会直观反映在空簇数量上。跑通之后再看墙钟时间,GPU 上记得把数据预留在显存里,避免把主机到设备的拷贝算进算法时间。

什么时候值得换,什么时候不用折腾

值得立刻试的场景很清楚:向量量化、码本训练、大规模去重和语义分桶这类簇数动辄上万、数据千万级起步的重负载,e-means 的轮数优势直接乘在 GPU 时长账单上;簇数越大,死簇问题越严重,复活策略的收益也越明显。已经在用 Faiss 的团队迁移成本最低。

可以保持观望的也要如实说清。一是成熟度:contrib 目录意味着接口还可能调整,论文 2026 年 11 月才挂上 arXiv,生产级的踩坑样本还少。二是小数据场景:几千个点、几十个簇的聚类,Lloyd 全量遍历本来就只要毫秒级,换不换感知不强。三是流程绑定:聚类步骤如果嵌在不支持 PyTorch 张量的老管线里,数据搬运开销可能吃掉收益。四是标度律主要在嵌入向量上拟合,对极度稀疏的计数特征或超高维稀疏数据,官方还没有给出验证结论,这类负载建议先小样本回归再上量。

还有一类团队需要额外多想一步:用聚类做离线批处理、且任务排在夜间窗口里的,墙钟时间本来就不是瓶颈,换成 e-means 的直接收益有限,真正的吸引力在于更稳定的解质量------少跑几次重试、少几次人工检查坏簇,这类收益要按自己管线的故障频率来折算,不能照搬官方的倍数。

对从业者来说,更大的启示也许是方法论上的:一个被当作经典教材完结篇的算法,用深度学习时代的优化工具重新审视一遍,还能拿到数量级的改进。MacQueen 的迷你批量思路等了将近六十年,等的不是新数学,而是动量、调度和标度律这套现代工具箱。

相关推荐
IT_陈寒9 分钟前
Vue这个奇葩的响应式问题让我加班到凌晨
前端·人工智能·后端
yunhuibin17 分钟前
AI分类任务种类
人工智能·自然语言处理·分类
东坡肘子18 分钟前
参与学生移动应用大赛有感 -- 肘子的 Swift 周报 #161
人工智能·swiftui·swift
天天被压力20 分钟前
【A股分钟级高频数据完全手册 #11】券商实时行情数据接口:实时交易(券商源)接入与字段
java·人工智能·python
唐老板25 分钟前
agent 撑爆 Git 之后,两家改的不是同一层
人工智能·ai编程
天天被压力33 分钟前
【A股分钟级高频数据完全手册 #12】股票五档盘口数据接口:买卖五档实时盘口解析
java·人工智能·python
爱敲代码的小黄9 小时前
神经网络入门指南:从 CNN、RNN 到 Attention
人工智能·面试·程序员
一只爱撸猫的程序猿10 小时前
我看着一个 AI 引擎在 14 天里,从"记忆"走进了"搜索"
人工智能·后端·架构
我登哥MVP10 小时前
DeepSeek-Harness-Super-Agent-学习笔记
人工智能·深度学习·神经网络·机器学习·自然语言处理·agent