NumPy 矩阵化相似度计算是什么
小规模或本地原型可以直接用 NumPy 做批量向量检索:先对文档矩阵与查询向量做 L2 归一化,一次矩阵乘法求出全部内积,再用 argpartition 取 top-k 候选、argsort 对候选排序。数万条以内用内存矩阵完全够用,省掉引入向量库的部署与运维成本;当数据规模上升,或出现过滤、增量更新需求时,再迁移到向量库更合适。
基本信息
| 适用规模 | 数万条以内的原型与离线实验 |
|---|---|
| 依赖 | numpy,向量推荐 float32 |
| 步骤 | 归一化、矩阵乘法、取前 k、对候选排序 |
| 复杂度 | 每次查询与数据量成线性关系 |
| 前提 | 向量已归一化,内积才等价于余弦 |
| 迁移时机 | 需要过滤、增量更新或规模化时 |
典型使用场景
- 本地原型与算法验证,避免依赖外部服务
- 离线评测与消融实验,快速对比不同模型
- 单元测试中构造可控的小型检索数据集
- 数据量很小的内部工具,不值得引入向量库
- 作为基线实现,校验向量库参数配置是否正确
归一化加矩阵乘法
归一化加矩阵乘法
import numpy as np
def l2norm(x):
return x / np.linalg.norm(x, axis=1, keepdims=True) # 按行归一化
docs = l2norm(np.random.rand(50000, 384).astype("float32")) # 文档矩阵
docs_norm = np.linalg.norm(docs, axis=1, keepdims=True) # 只算一次并缓存
q = l2norm(np.random.rand(1, 384).astype("float32")) # 查询向量
scores = (docs @ q.T).ravel() # 一次算出全部内积
top = np.argpartition(-scores, 10)[:10] # 线性时间取候选
top = top[np.argsort(-scores[top])] # 只对候选排序
print(top, scores[top])关键调用读法
| 调用 | 作用 | 注意 |
|---|---|---|
| np.linalg.norm(x, keepdims=True) | 按行求模长 | keepdims 保证广播维度对齐 |
| docs 与 q 的矩阵乘法 | 一次算出全部内积 | float32 可以省一半内存 |
| argpartition 取前 k | 线性时间挑出候选 | 返回结果未排序,需要再排 |
| argsort 对候选排序 | 只对 k 个元素排序 | 避免对全量分数排序的开销 |
数万条以内的原型用内存矩阵即可;规模再大或需要过滤与更新时,迁移到向量库,接口形态基本可以保持一致。
文档矩阵的范数只需计算一次并缓存:每次查询重算是常见的性能浪费,数据量越大越明显。