当前位置: 首页 > article >正文

Faiss 实战指南:从基础索引到高级应用

1. 初识Faiss向量搜索的“超级引擎”如果你正在处理海量的图片、文本或者音频数据并且想快速找到其中相似的内容那么你很可能已经遇到了“向量相似性搜索”这个难题。简单来说就是把一段内容比如一张猫的图片转换成一串数字也就是向量然后在一大堆数字里快速找到和它最像的那几串。这听起来简单但当数据量达到百万、千万甚至上亿级别时传统的遍历比对方法就慢得像蜗牛了。这时候Faiss就该登场了。它是由Facebook AI ResearchFAIR团队开源的一个专门用于高效相似性搜索和密集向量聚类的库。你可以把它想象成一个为向量数据量身定做的“超级搜索引擎”。我最早接触Faiss是在处理一个千万级别的商品图片推荐项目当时用传统方法跑一次查询要好几秒用户体验极差。换上Faiss之后毫秒级返回结果那种性能提升带来的畅快感至今记忆犹新。Faiss的核心优势在于它针对现代CPU的架构做了极致优化并且提供了从最基础的精确搜索到各种高级的近似搜索算法。无论你的数据是几百维的小向量还是上千维的大模型嵌入无论你追求的是100%的准确率还是愿意用一点点精度换取百倍的搜索速度Faiss都能找到合适的“武器”给你。它就像一个丰富的工具箱里面从螺丝刀基础索引到冲击钻高级索引一应俱全。接下来我会带你从零开始一步步深入这个工具箱。我们会从最基础的安装和环境配置讲起然后构建第一个索引接着探索各种不同的索引类型及其适用场景最后还会分享一些我在实战中踩过的坑和调优经验。无论你是刚入门的新手还是想深入了解原理的开发者相信都能有所收获。2. 环境搭建与第一个Faiss程序工欲善其事必先利其器。使用Faiss的第一步就是把它正确地安装到你的工作环境中。Faiss主要支持Linux和macOS系统对Windows的支持需要通过WSL或conda来实现。这里我强烈推荐使用Anaconda来管理环境它能帮你省去很多依赖库编译的麻烦。2.1 安装Faiss最省心的安装方式就是使用conda。Faiss为不同版本的CUDA提供了预编译包你可以根据自己是否有GPU以及CUDA版本来选择。打开你的终端或Anaconda Prompt执行以下命令之一# 安装CPU版本最通用适合所有机器 conda install -c conda-forge faiss-cpu # 安装支持CUDA 11.x的GPU版本如果你有NVIDIA显卡且安装了CUDA 11 conda install -c conda-forge faiss-gpu cudatoolkit11.0 # 安装支持CUDA 12.x的GPU版本 conda install -c conda-forge faiss-gpu cudatoolkit12.0安装完成后在Python中导入一下验证是否成功import faiss print(faiss.__version__)如果没报错并且能打印出版本号比如1.7.4那么恭喜你环境搭建成功了我建议初学者先从CPU版本开始因为GPU版本虽然快但涉及到显存管理会稍微复杂一些。2.2 准备你的第一批向量数据Faiss处理的数据必须是二维的numpy数组且数据类型为float32。我们先用一个简单的例子来生成一些模拟数据。假设我们有一批维度为128的向量比如来自某个图像特征提取模型。import numpy as np # 设定向量维度 d 128 # 生成10000个随机向量作为数据库模拟真实数据 np.random.seed(1234) # 固定随机种子确保结果可复现 database_vectors np.random.random((10000, d)).astype(float32) # 生成5个查询向量 query_vectors np.random.random((5, d)).astype(float32) print(f数据库向量形状{database_vectors.shape}) # 应输出 (10000, 128) print(f查询向量形状{query_vectors.shape}) # 应输出 (5, 128)这里我们生成了10000个128维的向量作为数据库以及5个查询向量。astype(float32)这一步至关重要Faiss内部计算大量使用32位浮点数使用float64会报错。2.3 构建第一个索引并进行搜索现在我们来创建最简单的索引类型——IndexFlatL2。L2代表欧几里得距离也就是我们常说的直线距离。这种索引不做任何预处理它会在搜索时暴力计算查询向量与数据库中每一个向量的距离。所以它的搜索结果是最精确的但速度也最慢适合数据量不大比如几万以内或者对精度要求100%的场景。# 1. 创建索引传入向量维度 index faiss.IndexFlatL2(d) print(f索引是否需要训练{index.is_trained}) # Flat索引不需要训练直接返回True # 2. 向索引中添加数据库向量 index.add(database_vectors) print(f索引中的向量总数{index.ntotal}) # 应输出 10000 # 3. 执行搜索寻找每个查询向量的前4个最近邻 k 4 # 返回最相似的4个结果 distances, indices index.search(query_vectors, k) # 4. 查看结果 print(查询结果索引indices:) print(indices) # 形状为 (5, 4)每一行对应一个查询向量的4个最近邻在数据库中的位置 print(\n对应的距离distances:) print(distances) # 形状为 (5, 4)距离越小表示越相似运行这段代码你会看到indices是一个5行4列的数组。比如第一行[312, 5852, 1023, 9011]就表示对于第一个查询向量数据库中第312、5852、1023、9011个向量与它最相似L2距离最小。distances数组则记录了具体的距离值。注意IndexFlatL2搜索返回的距离是平方后的L2距离而不是开方后的欧氏距离。例如两个完全相同的向量距离为0两个相差为1的向量距离为1。这并不影响排序结果但如果你需要精确的欧氏距离记得对结果开方。第一次成功运行是不是很有成就感你已经完成了最核心的“建库”和“查询”操作。不过当你的数据量从1万变成100万时IndexFlatL2就会力不从心了。别急Faiss的强大之处在于它提供了多种“加速”索引让我们继续探索。3. 核心索引类型详解与选型指南Faiss的索引类型繁多初学者很容易看花眼。其实我们可以根据两个核心问题来选择合适的索引1. 你有多在意搜索速度 2. 你有多在意内存占用不同的索引就是在这两个维度上进行权衡的艺术。3.1 追求极致速度倒排索引 (IVFFlat)当数据量太大暴力搜索太慢时我们就要用点“巧劲”。IVFFlatInverted File with Flat storage的思路非常直观先把数据库里的所有向量用K-Means算法聚成很多个类我们叫“维诺单元”每个类有一个中心点。搜索时先找到距离查询向量最近的nprobe个类中心然后只在这几个类内部的向量中进行精确的暴力搜索。这就像你在一个大型图书馆找一本书。暴力搜索Flat是把每本书都翻一遍。而IVFFlat是先根据书的类别历史、文学、科技等把书分到不同的书架上找书时你先判断这本书大概属于哪几个类别然后只去这几个书架上找大大缩小了搜索范围。# 继续使用之前的数据库向量 database_vectors nlist 100 # 将数据库聚成100个类 quantizer faiss.IndexFlatL2(d) # 需要一个“量化器”来计算距离这里用Flat index_ivf faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2) print(fIVF索引是否需要训练{index_ivf.is_trained}) # 此时为False需要训练 # 训练索引需要用一部分数据来学习聚类中心 # 注意训练数据分布应和数据库数据分布一致这里我们直接用全部数据训练 index_ivf.train(database_vectors) print(f训练后索引是否需要训练{index_ivf.is_trained}) # 此时应为True # 添加数据 index_ivf.add(database_vectors) # 设置搜索时探查的类数量。这是IVF索引最重要的参数 index_ivf.nprobe 10 # 只探查距离最近的10个类 # 执行搜索 distances_ivf, indices_ivf index_ivf.search(query_vectors, k) print(IVFFlat 搜索结果索引:, indices_ivf[0]) # 查看第一个查询的结果关键参数解析nlist聚类中心的个数。值越大每个类里的向量越少搜索越快但训练时间越长且需要更多的内存来存储中心点。通常设置为sqrt(N)N是数据库向量总数的4到16倍。对于100万数据nlist设为1000到4000比较常见。nprobe搜索时探查的类数量。这是平衡速度与精度的核心旋钮。nprobe1时最快但精度最低可能漏掉真正相似的结果。nprobenlist时就退化成了在所有类中搜索相当于暴力搜索。通常从nlist的1%到10%开始调整。我个人的经验是对于100万量级的数据设置nlist1000,nprobe10到20可以在保证95%以上召回率的同时获得数十倍于Flat索引的搜索速度。3.2 应对海量数据与内存限制乘积量化索引 (IVFPQ)IVFFlat虽然快但它依然存储了原始的完整向量。当向量维度很高比如1024维数据量极大比如上亿条时内存可能就不够用了。这时候我们就需要“有损压缩”向量这就是乘积量化Product Quantization, PQ干的事情。PQ的思想是把一个高维向量切分成多个子段对每个子段分别进行聚类量化。比如把一个128维向量切成8段每段16维。为每一段学习一个包含256个“码字”的码本。这样每个原始向量就可以用8个整数每个整数0-255代表其子段所属的聚类编号来表示极大地压缩了存储空间。IVFPQ就是将IVF和PQ结合起来先聚类IVF再压缩PQ。m 8 # 将向量分割成8个子段 nbits 8 # 每个子段用8bits编码即每个子段有2^8256个聚类中心 nlist 100 # 依然是聚类中心数 quantizer faiss.IndexFlatL2(d) # 量化器 # 创建 IVFPQ 索引 index_ivfpq faiss.IndexIVFPQ(quantizer, d, nlist, m, nbits) # 训练和添加数据 index_ivfpq.train(database_vectors) index_ivfpq.add(database_vectors) index_ivfpq.nprobe 10 # 搜索 distances_pq, indices_pq index_ivfpq.search(query_vectors, k) print(IVFPQ 搜索结果索引:, indices_pq[0]) print(IVFPQ 搜索距离注意是近似距离:, distances_pq[0])重要提示使用PQ后计算的距离是近似距离并不是真实的L2距离。返回的距离值通常比真实距离小并且绝对值意义不大主要用于排序。IVFPQ在内存占用和搜索速度上取得了非常好的平衡是处理十亿级别数据的标配方案但会损失一些精度。3.3 索引选型速查表为了帮你快速做出选择我整理了一个索引选型决策表基于我多年的实战经验索引类型核心特点适用场景优点缺点内存占用IndexFlatL2/IP暴力精确搜索数据量小 (10万)要求100%准确率精度最高无需训练使用简单速度慢内存占用大非常高IndexIVFFlat倒排索引原始向量数据量大 (百万级)追求高精度和较快速度速度比Flat快很多精度损失可控需要训练有精度损失内存占用仍高高IndexIVFPQ倒排索引乘积量化数据量巨大 (千万到亿级)内存受限内存占用极低速度非常快需要训练精度损失较大低IndexHNSW基于图导航的近似搜索中等数据量追求高召回率和快速度单次搜索快精度高无需训练构建索引慢内存占用高不支持增量添加高IndexLSH局部敏感哈希对精度要求不高需要极快速度构建和搜索都快适合高维精度较低内存占用随参数增大中等一句话建议新手从IndexFlatL2和IndexIVFFlat开始理解原理处理百万级以上数据且内存足够就用IndexIVFFlat并调优nprobe内存是瓶颈就上IndexIVFPQ如果数据量不大但想要又快又好可以试试IndexHNSW。4. 实战进阶Index Factory与性能调优当你熟悉了基本索引后Faiss还提供了一个更强大、更灵活的功能Index Factory。它允许你用一个简单的字符串来配置复杂的索引管道这个字符串描述了从原始向量到最终索引的完整处理流程。4.1 使用Index Factory一站式构建索引Index Factory的配置字符串通常由三部分组成用逗号分隔预处理,倒排聚类,细化编码。# 示例1PCA降维后做精确搜索 # 将128维向量用PCA降到64维然后进行Flat精确搜索 index_pca faiss.index_factory(128, PCA64,Flat) index_pca.train(database_vectors) # PCA需要训练 index_pca.add(database_vectors) # 示例2经典的IVF100 Flat组合 # 先聚成100类然后存储原始向量 index_ivf100 faiss.index_factory(d, IVF100,Flat) index_ivf100.train(database_vectors) index_ivf100.add(database_vectors) index_ivf100.nprobe 10 # 示例3更复杂的组合 - OPQ预处理 IVF聚类 PQ量化 # OPQ32_128: 使用OPQ将128维向量转换为32个子空间更优的量化 # IVF100: 聚成100类 # PQ16: 每个子向量用16字节编码 index_complex faiss.index_factory(d, OPQ32_128,IVF100,PQ16) index_complex.train(database_vectors) index_complex.add(database_vectors) index_complex.nprobe 10预处理部分常见选项PCA64通过PCA将维度降至64。PCAR64PCA降维后加一个随机旋转有时能提升量化效果。OPQ16使用优化乘积量化进行预处理通常能显著提升后续PQ的精度OPQ16_64表示输出64维分成16段。使用Index Factory的好处是代码简洁并且能轻松组合各种技术。很多论文和竞赛中的最佳实践都是用Factory字符串表达的。4.2 性能调优实战找到你的“甜蜜点”选择了索引类型只是第一步让它在你的数据和硬件上跑出最佳性能还需要精细调优。调优的核心目标是在可接受的精度损失下获得最快的搜索速度和最小的内存占用。第一步量化评估指标在调优前你必须定义如何衡量“好坏”。通常需要两个指标召回率 (RecallK)搜索返回的前K个结果中有多少是真正的Top-K近邻。这是衡量精度的核心指标。查询延迟 (Query Latency)单次搜索花费的时间通常取多次查询的平均值。你需要一个验证集从数据库中随机抽取一小部分比如1000个向量作为查询并用暴力搜索IndexFlatL2得到它们真实的Top-K近邻作为“标准答案”。# 假设 validation_queries 是验证查询向量true_indices 是暴力搜索得到的真实近邻索引 def evaluate_recall(found_indices, true_indices, k): 计算召回率 recall_sum 0 for i in range(len(found_indices)): # 计算交集数量 intersection len(set(found_indices[i, :k]) set(true_indices[i, :k])) recall_sum intersection / k return recall_sum / len(found_indices) # 测试IVF索引在不同nprobe下的表现 nprobe_values [1, 5, 10, 20, 50, 100] recalls [] times [] for nprobe in nprobe_values: index_ivf.nprobe nprobe start time.time() found_indices, _ index_ivf.search(validation_queries, k) elapsed time.time() - start recalls.append(evaluate_recall(found_indices, true_indices, k)) times.append(elapsed / len(validation_queries) * 1000) # 单次查询毫秒数 print(fnprobe{nprobe:3d}, Recall{recalls[-1]:.4f}, Time{times[-1]:.2f} ms)第二步关键参数调优对于IVF类索引主要调nlist和nprobe。nlist通常设为4*sqrt(N)到16*sqrt(N)。nprobe根据你绘制的“召回率-时间”曲线来选择拐点。例如当nprobe从10增加到20时召回率提升不足1%但时间增加了50%那么10可能就是最佳点。对于PQ类索引主要调m子段数和nbits每段编码位数。m通常取4, 8, 16等必须是向量维度的约数。m越大、nbits越大精度越高但内存和速度开销也越大。一个经验是保证m * nbits总编码位数在64到128之间是一个不错的起点。训练数据量训练IVF或PQ索引时不需要用全部数据。通常用100万到1000万条数据训练就足够了关键是训练数据的分布要和全量数据一致。第三步内存与速度的权衡有时你需要将索引部署到内存有限的服务器上。Faiss提供了faiss.get_mem_usage()函数来估算索引内存占用。对于IVFPQ你可以通过减少nlist、降低m或nbits来减少内存但这会牺牲精度和速度。务必在测试集上验证调整后的效果。我在一个实际项目中将nlist从4096降到1024nprobe从32降到8内存减少了75%搜索速度提升了3倍而召回率仅从98.5%下降到97.2%完全符合业务要求。这个权衡的过程就是Faiss实战中最有魅力的部分。5. 高级技巧与避坑指南掌握了基本操作和调优后我们来看看一些能让你用得更顺手、更稳健的高级功能和常见陷阱。5.1 为向量赋予ID与按ID删除默认情况下index.add()添加的向量会按顺序获得从0开始的内部ID。但有时我们希望自定义ID或者后续能按ID删除向量。import numpy as np # 1. 创建索引 index faiss.IndexFlatL2(d) # 2. 准备自定义ID必须是int64类型 ids np.array([100, 101, 102, 10000, 10001], dtypenp.int64) # 3. 添加数据和ID index.add_with_ids(database_vectors[:5], ids) print(f索引中的向量ID: {index.id_map.at(1, 5)}) # 查看前5个ID # 4. 按ID搜索 (需要先构建一个映射) # Faiss本身不直接支持按ID搜索但我们可以通过维护外部映射来实现 # 假设我们有一个字典自定义ID - 向量 id_to_vector {ids[i]: database_vectors[i] for i in range(len(ids))} target_id 10000 if target_id in id_to_vector: target_vec id_to_vector[target_id].reshape(1, -1) distances, found_ids index.search(target_vec, k3) print(f搜索ID {target_id} 附近的结果: {found_ids}) # 5. 按ID删除向量 remove_ids np.array([101, 10000], dtypenp.int64) index.remove_ids(remove_ids) print(f删除后索引向量总数: {index.ntotal})注意remove_ids操作对于IndexIVF等索引效率较低因为它需要重建倒排列表。如果频繁删除建议考虑定期重建整个索引。5.2 处理GPU加速如果你的机器有NVIDIA GPUFaiss的GPU版本可以带来惊人的速度提升。使用GPU的核心是将索引转移到GPU显存中。# 确保安装了 faiss-gpu import faiss # 1. 在CPU上创建并训练一个索引 cpu_index faiss.IndexFlatL2(d) cpu_index.add(database_vectors) # 2. 获取GPU资源 res faiss.StandardGpuResources() # 创建一个GPU资源对象 # 3. 将CPU索引转移到GPU # 使用 DefaultGpuResources 和索引配置 gpu_index faiss.index_cpu_to_gpu(res, 0, cpu_index) # 0 代表第0块GPU # 4. 在GPU上进行搜索 (速度会快很多) distances_gpu, indices_gpu gpu_index.search(query_vectors, k) # 5. 操作完成后可以将索引移回CPU (可选) # cpu_index_2 faiss.index_gpu_to_cpu(gpu_index)GPU使用注意事项显存限制GPU显存通常比系统内存小得多。确保你的索引包括向量数据和索引结构能放入显存。数据传输开销将数据从CPU内存复制到GPU显存有开销。对于单次查询这个开销可能抵消GPU计算的优势。批量查询才能最大化GPU效益。多GPU对于超大规模索引Faiss支持将索引分割到多块GPU上并行搜索这需要更复杂的配置。5.3 我踩过的那些“坑”数据类型错误这是最常见的问题。务必确保所有numpy数组都是np.float32类型。float64会直接导致崩溃或错误结果。维度不匹配创建索引时指定的维度d必须和实际添加的向量维度完全一致。不一致会报Inconsistent array dimensions错误。忘记训练IndexIVF和IndexPQ等索引在add数据前必须先train。忘记训练会导致搜索结果完全随机。一个良好的习惯是每次创建索引后都检查index.is_trained。nprobe设置过小这是精度不达标的头号原因。尤其是在数据分布不均匀或聚类效果不好时需要设置较大的nprobe才能保证召回率。一定要在验证集上测试不同nprobe下的召回率。训练数据不足或不具代表性用1万条数据训练出的聚类中心去索引1000万条分布不同的数据效果会很差。训练数据量至少应有数万条且最好是从全量数据中随机采样。内存泄漏长时间运行服务在Web服务中长时间运行Faiss如果频繁创建和销毁大型索引可能会遇到内存增长问题。建议将索引对象设为全局单例并监控进程内存使用情况。Faiss是一个功能强大但细节繁多的工具。最好的学习方式就是动手实践用你自己的数据从一个简单的Flat索引开始逐步尝试IVF、PQ调整参数观察性能变化。过程中遇到问题多查阅官方文档和GitHub上的Issue社区里有很多宝贵的经验。希望这篇指南能帮你少走弯路更快地将Faiss的强大能力应用到你的项目中去。

相关文章:

Faiss 实战指南:从基础索引到高级应用

1. 初识Faiss:向量搜索的“超级引擎” 如果你正在处理海量的图片、文本或者音频数据,并且想快速找到其中相似的内容,那么你很可能已经遇到了“向量相似性搜索”这个难题。简单来说,就是把一段内容(比如一张猫的图片&am…...

Hi3861单芯片Wi-Fi智能开关设计与量产实践

1. 项目概述本项目实现了一款基于华为海思Hi3861芯片的Wi-Fi智能开关系统,面向物联网边缘控制场景,支持本地物理按键操作与远程HTTP指令控制双重交互模式。系统采用轻量级鸿蒙(OpenHarmony LiteOS-M内核)作为软件平台,…...

地理空间可视化崩溃频发,R 4.5中rgdal弃用后5步无缝迁移至sf+wk+geoarrow(含完整迁移检查清单)

第一章:地理空间可视化崩溃频发的根源诊断与R 4.5兼容性挑战地理空间可视化在R生态中长期依赖sf、sp、rgdal和mapview等核心包,但自R 4.5发布以来,多起不可恢复的段错误(segmentation fault)和GDAL驱动初始化失败案例集…...

拇指大小的射频功率计设计与宽量程实现原理

1. 项目概述对讲机射频功率计是一款面向业余无线电、应急通信及现场工程调试场景设计的便携式射频功率测量工具。其核心价值在于将传统实验室级功率测量能力压缩至拇指大小的物理封装内,实现从手台、车台到小型基站发射端口的快速、原位功率验证。该设备并非通用频谱…...

基于N32G430的USB供电参数监测终端设计

1. 项目概述本项目是一款基于国民技术N32G430C8L7微控制器的USB供电参数监测终端,集成了高精度电压/电流采集、实时功率计算与本地可视化显示功能。系统采用单板一体化设计,核心为N32G430C8L7——一款内置硬件乘除法器、支持多路高精度ADC与灵活时钟管理…...

快马平台AI助力:一分钟生成CentOS7的LNMP环境自动化部署脚本原型

最近在做一个Web项目的原型验证,需要快速搭建一个LNMP环境来测试一些功能。传统方式从安装系统到配置服务,步骤繁琐,耗时很长。这次我尝试用InsCode(快马)平台的AI能力,直接生成一个CentOS7下的自动化部署脚本,整个过程…...

DeepSeek-R1-Distill-Qwen-7B在新闻摘要生成中的实践

DeepSeek-R1-Distill-Qwen-7B在新闻摘要生成中的实践 1. 新闻摘要生成的痛点与解决方案 每天面对海量的新闻资讯,内容编辑和读者都面临同样的困境:信息过载、时间有限、关键信息难以快速捕捉。传统的人工摘要方式效率低下,一个编辑每小时可…...

老码农和你一起学AI系列:RNN循环神经网络

RNN(Recurrent Neural Network,循环神经网络)最好的方式,是把它和我之前聊过的N-grams以及Transformer放在一起,看成语言模型进化史上的关键中间环节。如果说N-grams是个“记忆力只有7秒的金鱼”(只看局部&…...

进站必看——关于博客内容的规划

你好,我的朋友,欢迎来到我的博客!我写博客的目的是通过博客的写作来沉淀我的技术,但聪明的朋友已经发现我的博客存在着一些问题:第一:博客内容杂乱。一会计网,一会C语言,一会就是一些…...

Kotlin泛型实战:从基础到高阶

Kotlin 泛型基础泛型允许在定义类、接口或函数时使用类型参数&#xff0c;从而提高代码的复用性和类型安全性。Kotlin 的泛型语法与 Java 类似&#xff0c;但提供了更灵活的特性。class Box<T>(val value: T)fun main() {val intBox Box(1) // 类型推断为 Box<…...

jQueryMobile网格

jQuery Mobile 网格系统介绍jQuery Mobile 提供了一套响应式网格系统&#xff0c;允许开发者通过简单的 HTML 结构和 CSS 类创建灵活的布局。网格系统基于百分比宽度&#xff0c;确保在不同屏幕尺寸上表现一致。基本网格结构jQuery Mobile 网格由行和列组成&#xff0c;每行默认…...

jQueryMobile导航栏

jQuery Mobile 导航栏基础导航栏是移动应用中常见的组件&#xff0c;用于在多个视图或页面间切换。jQuery Mobile 提供了 data-role"navbar" 属性来快速创建导航栏。基本结构如下&#xff1a;<div data-role"navbar"><ul><li><a href…...

YOLO 模型 端侧硬件部署 从0到1 完整实战流程

# YOLO 模型 端侧硬件部署 从0到1 完整实战流程 从模型下载 → 优化 → 剪枝 → 量化 → 转换 → 端侧部署 &#xff0c;包含所有命令、工具、采坑点。 适用于&#xff1a;RK3588 / Jetson / Android / ARM Linux / 嵌入式设备 一、整体流程总览-端侧部署标准5步 1. 原始模型获…...

钱币鉴定最全的书

在如今的收藏市场中&#xff0c;钱币收藏因其独特的历史文化价值和潜在的经济价值&#xff0c;受到了越来越多人的关注。然而&#xff0c;钱币鉴定却是一门专业性极强的学问&#xff0c;倘若没有一本好的学习资料&#xff0c;新手很容易在纷繁复杂的信息中迷失方向&#xff0c;…...

无锁队列设计

无锁队列设计 文章目录无锁队列设计1. 为什么需要无锁队列&#xff1f;2. 无锁编程基本概念2.1 阻塞&#xff08;Blocking&#xff09;、无锁&#xff08;Lock-Free&#xff09;与无等待&#xff08;Wait-Free&#xff09;2.2 无锁编程的挑战3. 无锁队列的分类4. SPSC环形缓冲区…...

收藏!2026大模型招聘真相:程序员必看,小白入门不踩坑

近两年来&#xff0c;大模型行业迎来爆发式增长&#xff0c;热度居高不下&#xff0c;无论是深耕传统技术领域的开发者&#xff08;Java、C、前端、数据开发、架构师&#xff09;&#xff0c;还是刚入门的技术小白&#xff0c;都在主动入局、内卷大模型相关技术&#xff0c;生怕…...

收藏!2026春招大厂AI岗位井喷,小白程序员必看的大模型人才机遇

未来是AI的&#xff0c;但归根结底是AI人才的——这句话在2026年春季校园招聘中&#xff0c;体现得淋漓尽致。今年的春招&#xff0c;早已不是简单的岗位竞争&#xff0c;而是一场围绕AI人才的“抢人大战”。截至目前&#xff0c;字节跳动、腾讯、百度、美团、蚂蚁集团等科技大…...

计算机复试上机C语言笔记(浙大第四版编程篇)

实验3-11 求一元二次方程的根运算优先级&#xff0c;注意加括号更改优先级 纯虚部就是只有虚部的&#xff0c;比如说2i&#xff0c;-2i这种&#xff0c;但是要注意题目可能还是需要输出0.002i这种实验4-1-1 统计数字字符和空格&#xff08;用switch&#xff09;switch&#xff…...

openclaw系列 | Windows部署指南

目录1、 系统环境依赖配置2、Windows系统全流程安装与初始化3、飞书配置4、常用命令参考文档1、 系统环境依赖配置 node -v git --version前置准备&#xff1a; 部署前请先确认电脑已安装以下基础工具&#xff1a; Node.js&#xff1a;需22.0及以上版本&#xff0c;用于运行Op…...

电子世界的奇妙冒险:18 动手做一个完整的智能小项目

👉18 动手做一个完整的智能小项目 咱们的电子科普系列从第1章的电阻电容基础,到二极管“三极管”的有源世界、运放的魔术、电源稳压、555定时器、数字逻辑、ADC/DAC、集成电路进化、传感器感知、执行器行动、无线通信、显示交互……一路走来,你已经从“小白”变身“硬件达…...

亚像素以及实现原理、方法

一、什么是亚像素&#xff08;Sub-Pixel&#xff09; 普通图像坐标是 整数像素&#xff1a; (x,y)(120,85) 灰度 255 | █████ 200 | █ 150 | █ 100 | █ 50 |█ ---------------- 1 2 3 4 5 像素 但真实物体边缘不一定刚好落…...

Linux 的 base32 命令

Linux 的 base32 命令 概述 base32 是 Linux 系统中用于 Base32 编码和解码的命令行工具。Base32 是一种用 32 个可打印字符&#xff08;A-Z 和 2-7&#xff09;表示二进制数据的编码方式&#xff0c;常用于在不支持二进制数据的传输环境中安全地传递数据。 基本语法 base3…...

实战:用MATLAB揪出轴承故障的小秘密

MATLAB滚动轴承故障诊断程序:采用西楚凯斯大学数据&#xff0c;首先通过变分模态分解(VMD)算法处理&#xff0c;而后分别通过包络谱分析实现故障诊断 ps.通过尖峰对应的频率与计算出的故障频率比较&#xff0c;实现故障诊断 最近在倒腾滚动轴承故障诊断&#xff0c;发现西楚凯…...

comsol岩层开挖作用下瓦斯渗透运移模型,考虑应力作用下的渗透率变化,流固耦合物理场,使用p...

comsol岩层开挖作用下瓦斯渗透运移模型&#xff0c;考虑应力作用下的渗透率变化&#xff0c;流固耦合物理场&#xff0c;使用pde结构力学模块&#xff0c;参考相关文献建立。地下巷道开挖就像给岩层做了场外科手术。岩体应力重新分布引发的渗透率变化&#xff0c;直接影响着瓦斯…...

ROS系统中基于强化学习算法的移动机器人路径规划策略研究:应用DQN、DDPG、SAC及TD3算法

ROS下的移动机器人路径规划算法&#xff0c;使用的是 强化学习算法 DQN DDPG SAC TD3等最近研究移动机器人的小伙伴肯定绕不开路径规划这个话题。在ROS生态里搞强化学习就像在乐高积木上装火箭发动机——既灵活又带劲。今天咱们不聊传统A*、RRT这些老伙计&#xff0c;重点掰扯掰…...

直流调速系统Simulink仿真:包含参数设置代码、Simulink仿真模型及撰写文档

直流调速系统simulink仿真&#xff0c; 用matlab2016a做的。包含三部分 1.参数设置代码 2.simulink仿真模型 3.撰写的直流调速系统docx打开Matlab2016a的瞬间&#xff0c;电机控制老司机的手就开始痒了。今天咱们要搞的是直流电机双闭环调速系统的仿真&#xff0c;这玩意儿在工…...

57c1-2四轮轮毂电机驱动汽车的DYC直接横摆力矩稳定性控制,上层控制器DYC产生横摆力矩Mz

57c1-2四轮轮毂电机驱动汽车的DYC直接横摆力矩稳定性控制&#xff0c;上层控制器DYC产生横摆力矩Mz&#xff0c;下层基于最优分配理论对附加横摆力矩进行四轮独立分配&#xff0c;控制效果良好&#xff0c;能实现车辆在高低附着系数路面下的稳定性&#xff0c;可应用在高速下高…...

探索 BLDC 无霍尔无感控制的奇妙世界

BLDC。 脉冲注入法&#xff0c;启动低速阶段持续注入&#xff0c;运行过程中注入&#xff0c;力矩保持&#xff0c;无霍尔无感方案&#xff0c;电感法&#xff0c;媲美有霍尔效果。 bldc控制器方案&#xff0c;无刷电机。 提供源码&#xff0c;原理图在电机控制领域&#xff0c…...

基于极限学习机ELM的数据回归预测:多输入单输出实现

基于极限学习机ELM的数据回归预测 多输入单输出 代码含详细注释&#xff0c;不负责 数据存入Excel&#xff0c;替换方便&#xff0c;指标计算有决定系数R2&#xff0c;平均绝对误差MAE&#xff0c;平均相对误差MBE在数据分析与预测领域&#xff0c;极限学习机&#xff08;ELM&a…...

后轮反馈控制算法:高效路径跟踪的利器

后轮反馈控制算法路径跟踪 算法计算快&#xff0c;控制效果好 代码规范&#xff0c;文档详细在自动驾驶和机器人运动控制领域&#xff0c;路径跟踪是一个关键的课题。后轮反馈控制算法凭借其独特的优势&#xff0c;在这一领域崭露头角&#xff0c;成为实现精准路径跟踪的有力工…...