faiss库中ivf-sq(ScalarQuantizer,标量量化)代码解读-5
训练过程
通过gdb调试得到这个ivfsq的训练过程,我尝试对这个内容具体训练过程进行解析,对每个调用栈里面的逻辑和代码进行解读。
| 步骤 | 函数名称 | 调用位置 | 说明 |
|---|---|---|---|
| 1 | faiss::IndexIVF::train | /faiss/IndexIVF.cpp:1143 | 开始训练,判断是否需要训练第一级量化器,调用 train_q1。 |
| 2 | faiss::Level1Quantizer::train_q1 | /faiss/IndexIVF.cpp:56 | 训练第一级量化器,创建聚类器 Clustering,并调用其 train 方法进行训练。 |
| 3 | faiss::Clustering::train | /faiss/Clustering.cpp:81 | 使用输入数据 x 和聚类索引进行聚类训练,生成聚类中心。 |
| 4 | faiss::IndexIVF::train_residual | /faiss/IndexScalarQuantizer.cpp:139 | 训练残差部分,调用 ScalarQuantizer::train_residual 计算残差向量并训练标量量化器。 |
| 5 | faiss::ScalarQuantizer::train_residual | /faiss/impl/ScalarQuantizer.cpp:1124 | 对输入数据进行预处理(如采样),计算残差向量后调用 train 方法完成训练。 |
| 6 | faiss::ScalarQuantizer::train | /faiss/impl/ScalarQuantizer.cpp:1081 | 根据量化器类型调用 train_NonUniform 或其他方法,完成具体量化器的训练。 |
| 7 | train_NonUniform | /faiss/impl/ScalarQuantizer.cpp:572 | 为每个维度的量化器计算范围(如 vmin 和 vmax),根据指定的范围统计方法(如 RS_meanstd)完成训练。 |
| 8 | std::vector::resize | /usr/include/c++/14/bits/stl_vector.h:1015 | 为量化器的训练结果分配内存,调整 std::vector 的大小以容纳训练结果。 |
| 9 | train_NonUniform | /faiss/impl/ScalarQuantizer.cpp:1097 | 计算每个维度的最小值 vmin 和最大值 vmax,并将训练结果存储在 trained 向量中。 |
具体的流程如下:

解析IndexIVF.cpp:1143文件中的train函数
作为IndexIVFScalarQuantizer数据结构的第一个变脸index1所调用的函数train,需要去了解其如何去训练所存在的数据,查看具体的流程是什么样子的:
faiss::IndexFlatL2 quantizer1(d); // the other indexfaiss::IndexIVFScalarQuantizer index1(&quantizer1, d, nlist, faiss::ScalarQuantizer::QT_8bit);index1.sq.rangestat = faiss::ScalarQuantizer::RS_meanstd;index1.train(nb, xb); //调用的第一个函数
从gdb的调用栈里面发现,其首先调用的就是IndexIVF.cpp文件里面的第1143行的train函数,代码如下:
void IndexIVF::train(idx_t n, const float* x) {if (verbose) {printf("Training level-1 quantizer\n");}train_q1(n, x, verbose, metric_type);if (verbose) {printf("Training IVF residual\n");}// optional subsamplingidx_t max_nt = train_encoder_num_vectors();if (max_nt <= 0) {max_nt = (size_t)1 << 35;}TransformedVectors tv(x, fvecs_maybe_subsample(d, (size_t*)&n, max_nt, x, verbose));if (by_residual) {std::vector<idx_t> assign(n);quantizer->assign(n, tv.x, assign.data());std::vector<float> residuals(n * d);quantizer->compute_residual_n(n, tv.x, residuals.data(), assign.data());train_encoder(n, residuals.data(), assign.data());} else {train_encoder(n, tv.x, nullptr);}is_trained = true;
}
现在对这里面的内容进行解读:
- 打印训练状态
if (verbose) {printf("Training level-1 quantizer\n");
}
train_q1(n, x, verbose, metric_type);
- 作用:检查是否开启 verbose(调试输出),如果是,打印量化器训练的信息。verbose的来自于Index数据结构,然后IndexIVF继承了Index,IndexIVFInterface两个类(
IndexIVF : Index, IndexIVFInterface) - 核心函数:train_q1,训练一级量化器。
- n:训练数据的数量。
- x:训练数据(float 指针,表示数据的起始地址)。
- verbose:控制是否输出详细信息。
- metric_type:度量类型(可能决定了用什么距离计算方法,比如欧几里得或余弦距离)。
- 训练 IVF 残差
if (verbose) {printf("Training IVF residual\n");
}
- 作用:如果启用了调试模式,打印残差训练的日志信息。
- 可选的下采样
idx_t max_nt = train_encoder_num_vectors();
if (max_nt <= 0) {max_nt = (size_t)1 << 35;
}
TransformedVectors tv(x, fvecs_maybe_subsample(d, (size_t*)&n, max_nt, x, verbose));
- train_encoder_num_vectors:获取训练数据的最大数量 max_nt。如果返回值小于等于 0,则默认设置为一个非常大的值(2^35,也就是34,359,738,368)。
- fvecs_maybe_subsample:对输入数据 x 进行采样,可能会减少训练数据的数量(根据 max_nt)。
- 参数 d:特征的维度。
- 参数 (size_t*)&n:更新后的训练样本数量指针。
- 参数 verbose:控制是否输出调试信息。
- TransformedVectors: 是一个简单的 RAII 类型资源管理器,专注于浮点数组的管理。它通过成员变量
own_x确定是否需要释放 x 的内存,构造函数和析构函数一起保证资源管理的安全性。适合用于数据变换或动态内存场景,帮助减少显式的delete[]调用,降低内存管理的复杂性。如果这里面fvecs_maybe_subsample返回的结果和TransformedVectors数据结构上的x相同,那么就会释放原来多余的内存;如果构建采取的数据样本大于max_nt,那么就会选择里面的随机采样的数据。fvecs_maybe_subsample:对输入数据集进行可选的下采样,并返回下采样后的数据。如果输入数据集的大小超过了指定的最大数量 (nmax),它会随机选择一部分数据(nmax个样本)进行下采样;如果数据集大小在范围内,则直接返回原始数据。- size_t d, // 数据的维度(每个样本的特征数)
- size_t* n, // 输入数据的样本数量(指针,函数可能会修改该值)
- size_t nmax, // 数据集允许的最大样本数量
- const float* x, // 输入数据(样本集,每个样本有 d 个 float 特征)
- bool verbose, // 是否打印详细信息
- int64_t seed // 随机数种子(用于确保采样结果可重复)
- 根据模式处理残差或原始数据
if (by_residual) {std::vector<idx_t> assign(n);quantizer->assign(n, tv.x, assign.data());
- by_residual:一个布尔值,表示是否使用残差训练。如果为 true,执行残差计算流程:
1. assign里面就是按照n的大小进行分配,大概分配的大小就是k*n,k为邻居的数量。quantizer->assign:为每个训练样本分配一个量化器中心点(即将每个点分配到一个簇)。- n:训练样本数量(10w个)。- tv.x:训练数据。- assign.data():分配结果的存储位置(一个大小为 n 的向量)。assign 向量存储每个输入向量的分配结果(例如所属簇的索引)。
std::vector<float> residuals(n * d);quantizer->compute_residual_n(n, tv.x, residuals.data(), assign.data());
2. quantizer->compute_residual_n:计算残差。
- 残差是样本和分配中心点之间的差值。
- 存储在 residuals 数组中。
train_encoder(n, residuals.data(), assign.data());
3. train_encoder:使用残差数据和分配结果训练编码器。
- 原始数据训练
} else {train_encoder(n, tv.x, nullptr);
}
- 如果 by_residual 为 false,直接用原始数据进行编码器训练,不使用分配结果。
- 标记训练完成
is_trained = true;
- 将 is_trained 标记为 true,表示训练已经完成。
核心逻辑总结
- 函数接收高维训练数据 x,并根据配置(by_residual)选择:
- 使用残差方法,训练量化器和编码器。
- 或直接对原始数据进行训练。
- 支持下采样、量化器分配、残差计算等多种预处理。
- 用途广泛,适用于构建高效的倒排文件索引以加速高维数据的检索。
函数调用流程图
train
├── train_q1
├── fvecs_maybe_subsample
│ └── TransformedVectors
├── by_residual ?
│ ├── quantizer->assign
│ ├── quantizer->compute_residual_n
│ └── train_encoder (using residuals)
└── train_encoder (using original data)
相关文章:
faiss库中ivf-sq(ScalarQuantizer,标量量化)代码解读-5
训练过程 通过gdb调试得到这个ivfsq的训练过程,我尝试对这个内容具体训练过程进行解析,对每个调用栈里面的逻辑和代码进行解读。 步骤函数名称调用位置说明1faiss::IndexIVF::train/faiss/IndexIVF.cpp:1143开始训练,判断是否需要训练第一级…...
代码随想录算法训练营第六十天|Day60 图论
Bellman_ford 队列优化算法(又名SPFA) https://www.programmercarl.com/kamacoder/0094.%E5%9F%8E%E5%B8%82%E9%97%B4%E8%B4%A7%E7%89%A9%E8%BF%90%E8%BE%93I-SPFA.html 本题我们来系统讲解 Bellman_ford 队列优化算法 ,也叫SPFA算法…...
在嵌入式Linux下如何用QT开发UI
在嵌入式 Linux 环境下使用 Qt 开发用户界面 (UI) 是一个常见的选择。Qt 提供了丰富的功能、跨平台支持以及优秀的图形界面开发能力,非常适合用于嵌入式系统。以下是开发流程的详细步骤: 1. 准备开发环境 硬件环境 一块运行嵌入式 Linux 的开发板&…...
【JavaScript】Promise详解
Promise 是 JavaScript 中处理异步操作的一种强大机制。它提供了一种更清晰、更可控的方式来处理异步代码,避免了回调地狱(callback hell)和复杂的错误处理。 基本概念 状态: Pending:初始状态,既不是成功…...
1062 Talent and Virtue
About 900 years ago, a Chinese philosopher Sima Guang wrote a history book in which he talked about peoples talent and virtue. According to his theory, a man being outstanding in both talent and virtue must be a "sage(圣人)"…...
C++《二叉搜索树》
在初阶数据结构中我学习了树基础的概念以及了解了顺序结构的二叉树——堆和链式结构二叉树该如何实现,那么接下来我们将进一步的学习二叉树,在此会先后学习到二叉搜索树、AVL树、红黑树;通过这些的学习将让我们更易于理解后面set、map、哈希等…...
机器学习-神经网络(BP神经网络前向和反向传播推导)
1.1 神经元模型 神经网络(neural networks)方面的研究很早就已出现,今天“神经网络”已是一个相当大的、多学科交叉的学科领域.各相关学科对神经网络的定义多种多样,本书采用目前使用得最广泛的一种,即“神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够…...
基于智能物联网关的车辆超重AI检测应用
超重超载是严重的交通违法行为,超重超载车辆的交通安全风险极高,像是一颗行走的“不定时炸弹”,威胁着社会公众的安全。但总有一些人受到利益驱使,使超重超载的违法违规行为时有发生。 随着物联网和AI技术的发展,针对预…...
记录pbootcms提示:登录失败:表单提交校验失败,请刷新后重试的解决办法
问题描述 pbootcms后台登录的时候提示“登录失败:表单提交校验失败,请刷新后重试!” 解决办法 删除runtime目录,或尝试切换PHP版本,选择7.3或5.6一般就能解决了。...
【JavaScript】同步异步详解
同步和异步是编程中处理任务执行顺序的两种不同方式。理解这两种概念对于编写高效和响应式的应用程序至关重要。 同步(Synchronous) 定义:同步操作是指一个任务必须在下一个任务开始之前完成。换句话说,代码按顺序执行ÿ…...
vue 使用el-button 如何实现多个button 单选
在 Vue 中,如果你想要实现多个 el-button 按钮的 单选(即只能选择一个按钮),可以通过绑定 v-model 或使用事件来处理按钮的选中状态。 下面是两种实现方式,分别使用 v-model 和事件监听来实现单选按钮效果:…...
HarmonyOS-初级(二)
文章目录 应用程序框架UIAbilityArkUI框架 🏡作者主页:点击! 🤖HarmonyOS专栏:点击! ⏰️创作时间:2024年11月28日13点10分 应用程序框架 应用程序框架可以被看做是应用模型的一种实现方式。 …...
Unity开启外部EXE程序
Unity开启外部EXE using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading.Tasks; using UnityEditor; using UnityEngine;public class Unity_OpenExe : Mono…...
CTF之密码学(埃特巴什码 )
一、基本原理 埃特巴什码的原理是:字母表中的最后一个字母代表第一个字母,倒数第二个字母代表第二个字母,以此类推。在罗马字母表中,对应关系如下: 常文(明文):A B C D E F G H I …...
深入解析 PyTorch 的 torch.load() 函数:用法、参数与实际应用示例
深入解析 PyTorch 的 torch.load() 函数:用法、参数与实际应用示例 函数 torch.load() 是一个在PyTorch中用于加载通过 torch.save() 保存的序列化对象的核心功能。这个函数广泛应用于加载预训练模型、模型的状态字典(state dictionaries)、…...
ros2键盘实现车辆: 简单的油门_刹车_挡位_前后左右移动控制
参考: ROS python 实现键盘控制 底盘移动 https://blog.csdn.net/u011326325/article/details/131609340游戏手柄控制 1.背景与需求 1.之前实现过 键盘控制 底盘移动的程序, 底盘是线速度控制, 效果还不错. 2.新的底盘 只支持油门控制, 使用线速度控制问题比较多, 和底盘适配…...
ubuntu安装chrome无法打开问题
如果在ubuntu安装chrome后,点击chrome打开没反应,可以先试着在terminal上用命令打开 google-chrome 如果运行命令显示 Chrome has locked the profile so that it doesnt get corrupted. If you are sure no other processes are using this profile…...
CTF-RE 从0到N:Chacha20逆向实战 2024 强网杯青少年专项赛 EnterGame WP (END)
只想解题的看最后就好了,前面是算法分析 Chacha20 c语言是如何利用逻辑运算符拆分变量和合并的 通过百度网盘分享的文件:EnterGame_9acdc7c33f85832082adc6a4e... 链接:https://pan.baidu.com/s/182SRj2Xemo63PCoaLNUsRQ?pwd1111 提取码:1…...
vue3 ajax获取json数组排序举例
使用axios获取接口数据 可以在代码中安装axios包,并写入到package.json文件: npm install axios -S接口调用代码举例如下: const fetchScore async () > {try {const res await axios.get(http://127.0.0.1:8000/score/${userInput.v…...
web安全之信息收集
在信息收集中,最主要是就是收集服务器的配置信息和网站的敏感信息,其中包括域名及子域名信息,目标网站系统,CMS指纹,目标网站真实IP,开放端口等。换句话说,只要是与目标网站相关的信息,我们都应该去尽量搜集。 1.1收集域名信息 知道目标的域名之后,获取域名的注册信…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
