欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 五. 以聚类和搜图方式清洗图像数据集,采用Pickle和Faiss(百万数据集,ms级响应)快速搜图(附完整代码)

五. 以聚类和搜图方式清洗图像数据集,采用Pickle和Faiss(百万数据集,ms级响应)快速搜图(附完整代码)

2025/4/23 19:46:30 来源:https://blog.csdn.net/boboly186/article/details/147237138  浏览:    关键词:五. 以聚类和搜图方式清洗图像数据集,采用Pickle和Faiss(百万数据集,ms级响应)快速搜图(附完整代码)

文章内容结构:

一. 总结Faiss 和 Pickle 优缺点和适用场景。
二. 将图像特征打包成 pickle 文件(Python 的序列化格式),匹配搜图(附完整代码)。
三. 将图像特征打包成faiss的index索引文件,匹配搜图(附完整代码)。
四. 先用Pickle保存图像特征,再用Faiss构建索引(更灵活)(附示例代码)。

(注: 这里全部是个人经验,能提升样本标注和清洗效率,不是标准的数据处理方式,希望对您有帮助。)


一.总结:

Faiss 和 Pickle 是两种完全不同的工具,“直接用Pickle保存匹配特征” vs 先用“Pickle保存特征+Faiss构建索引” vs “直接用Faiss保存索引”,它们有各自的设计目标、使用场景和底层逻辑有本质区别

1.1 核心区别

Pickle和Faiss性能对比

操作Faiss(1M向量)Pickle + NumPy
最近邻查询(Top10)~1ms(GPU)~100ms(需全量计算)
存储占用紧凑(支持量化)原始数据大小
批量插入速度极快(并行优化)慢(逐对象序列化)
适用阶段生产环境快速部署需要多次调整索引参数或复用原始数据

Pickle+Faiss 和 单独Faiss 性能对比

维度Pickle + Faiss 分步保存Faiss 直接保存
保存内容原始特征向量(all_feats) + 独立构建Faiss索引仅保存Faiss索引(含已处理的向量数据)
灵活性高(可复用原始特征做其他操作)低(索引与向量绑定,无法提取原始特征)
存储空间较大(需存两份数据:原始特征+索引)较小(索引已优化存储结构)
加载速度慢(需重新构建索引)快(直接加载预构建索引,毫秒级加载)
适用场景需要多次调整索引参数或复用原始数据生产环境快速部署

1.2. 为什么推荐先用Pickle保存特征?

场景1:特征需要复用

  • 问题:若直接faiss.write_index保存索引,后续无法获取原始特征向量(如需要重新计算相似度、可视化分析等)。
  • 解决:用Pickle单独保存all_feats,可灵活支持:
    # 加载原始特征做其他分析
    with open("features.pkl", "rb") as f:all_feats = pickle.load(f)  # 形状 [N, d]
    

场景2:索引参数需要调优

  • 问题:Faiss索引类型(如IndexFlatIPIndexIVFPQ)和参数(如nlistm)可能需要多次调整。
  • 解决:保留原始特征可快速重建不同索引,无需重新提取特征:
    # 尝试不同索引类型
    index_ivf = faiss.IndexIVFFlat(quantizer, d, nlist=100)
    index_ivf.train(all_feats)
    index_ivf.add(all_feats)
    

场景3:数据版本控制

  • 问题:直接保存的Faiss索引无法区分不同版本的特征数据。
  • 解决:Pickle保存特征时附加元数据(如提取时间、模型版本):
    metadata = {"extract_time": "2024-01-01", "model": "ResNet50"}
    with open("features_v1.pkl", "wb") as f:pickle.dump({"features": all_feats, "meta": metadata}, f)
    

1.3 为什么直接用faiss.write_index

场景1:生产环境部署

  • 优势:加载速度快,适合线上服务:
    # 保存
    faiss.write_index(index, "prod.index")
    # 加载
    index = faiss.read_index("prod.index")  # 毫秒级加载
    

场景2:索引含量化/压缩

  • 优势:Faiss索引可能包含优化后的量化数据(如PQ压缩),比原始特征更紧凑:
    # 使用PQ压缩节省空间
    index_pq = faiss.IndexIVFPQ(quantizer, d, nlist=100, m=8, bits=8)
    index_pq.train(all_feats)
    index_pq.add(all_feats)
    faiss.write_index(index_pq, "compressed.index")  # 文件远小于原始特征
    

1.4 性能对比

指标Pickle + Faiss仅Faiss索引
文件大小例如features.pkl(12MB) + index_flat.index(12MB)index_only.index(12MB)
加载后能否获取原始特征是(通过pickle.load
重建索引灵活性高(可换参数/类型)低(需重新提取特征)

1.5 如何选择?

  • Pickle + Faiss 如果
    • 需要调试索引参数或复用原始特征。
    • 数据需版本管理或后续分析。
  • faiss.write_index 如果
    • 生产环境要求快速加载。
    • 索引含量化压缩且无需原始数据。


二. 将图像特征打包成 pickle 文件,匹配搜图(Python 的序列化格式):

2.1代码实现pickle打包和相似度计算

2.1.1 记录易犯错,易混淆的知识点:

(1)ONNX Runtime 某些优化在GPU上会导致细微的浮点数值差异。
比如同一张图经过GPU多次推理,得到的特征图存在浮点误差,也就是它们不是完全相同。但同一张图经过CPU多次推理,得到的特征图是完全相同的。虽然用GPU推理有差异,但差异很小,不影响相似度计算。

(2)以余弦相似度计算为例,使用的cosine和np.dot(两个向量的点积):
1> cosine可以直接计算两个特征向量的相似度,但np.dot不能。
2> 使用np.dot需要对提取图像特征后的特征向量先做归一化,再使用np.dot计算相似度,未作归一化,就是在计算两个特征向量的模长,模长影响内积计算。会出现一种常见情况,完全相同的两个向量(feature_test 和 all_feats[0])的内积(np.dot)结果比不相同的向量(feature_test 和 all_feats[5])更小。


原因: 核心问题:内积 vs 余弦相似度

  • 内积(np.dot
    直接计算两个向量的点积,结果受向量**模长(长度)**影响。

    • 如果向量未归一化(模长不为1),内积的值可能非常大,且无法直接反映相似性。
  • 余弦相似度(consine)
    通过归一化剔除模长影响,仅衡量方向相似性。

指标all_feats[0](相同)all_feats[5](不同)
向量差值0≠0
内积(np.dot569.4159更大(因模长影响)
余弦相似度1.0<1.0(正确反映差异)

归一化后使用np.dot计算两个特征向量的相似度:

     # 归一化特征向量(余弦相似度等于点积当向量归一化后)feature_test_norm = feature_test / np.linalg.norm(feature_test)all_feats_norm = all_feats / np.linalg.norm(all_feats, axis=1, keepdims=True)# 计算点积(即余弦相似度)similarities = np.dot(all_feats_norm, feature_test_norm)# 获取相似度最高的top_n个索引top_indices = np.argsort(similarities)[-top_n:][::-1]top_similarities = similarities[top_indices]

2.2 完整代码(pickle方式)

  1. 所有图像标准化,归一化,并提取图像特征(提取后的图像特征不做归一化,为了pickle能还原图像的原始特征。
  2. 把所有图像特征打包生成pickle文件。
  3. 对一张要搜索的图像提取特征,对图像特征做归一化,记为A。
  4. 取出pickle文件里面所有图像特征,全部做归一化,计为集合BB。
  5. 用A计算BB里面每张图像的特征,并计算余弦相似度,找到topN的相似图。
import os
import cv2
import numpy as np
from PIL import Image
import onnxruntime as ort
import shutil
from sklearn.cluster import KMeans
from sklearn.preprocessing import Normalizer
from  tqdm import tqdm
import math
import matplotlib.pyplot as plt
# 写入文件
import pickle
# 使用faiss向量库(在数据库里面实现向量的搜索)
import faiss
from scipy.spatial.distance import cosine# 图像预处理函数
def preprocess_image(image_path):roi_frame= cv2.imread(image_path)width = roi_frame.shape[1]height = roi_frame.shape[0]if (width != CLASSIFY_SIZE) or (height != CLASSIFY_SIZE) :if width > height:# 将图像逆时针旋转90度roi_frame = cv2.rotate(roi_frame, cv2.ROTATE_90_COUNTERCLOCKWISE)new_height = CLASSIFY_SIZEnew_width = int(roi_frame.shape[1] * (CLASSIFY_SIZE / roi_frame.shape[0]))roi_frame = cv2.resize(roi_frame, (new_width, new_height))# 计算上下左右漂移量y_offset = (CLASSIFY_SIZE - roi_frame.shape[0]) // 2x_offset = (CLASSIFY_SIZE - roi_frame.shape[1]) // 2gray_image = np.full((CLASSIFY_SIZE, CLASSIFY_SIZE, 3), 128, dtype=np.uint8)# 将调整大小后的目标图像放置到灰度图上gray_image[y_offset:y_offset + roi_frame.shape[0], x_offset:x_offset + roi_frame.shape[1]] = roi_frame# # 显示结果# cv2.imshow("gray_image", gray_image)# cv2.waitKey(1)# 将图像转为 rgbgray_image =  cv2.cvtColor(gray_image, cv2.COLOR_BGR2RGB)else:gray_image = cv2.cvtColor(roi_frame, cv2.COLOR_BGR2RGB)img_np = np.array(gray_image).transpose(2, 0, 1).astype(np.float32)# 假设模型需要[0,1]归一化img_np = img_np / 255.0# 均值 方差mean = np.array([0.485, 0.456, 0.406],dtype=np.float32).reshape(3, 1, 1)std = np.array([0.229, 0.224, 0.225],dtype=np.float32).reshape(3, 1, 1)img_np= (img_np - mean)/stdreturn np.expand_dims(img_np, axis=0)# todo
# 卸载 onnxruntime
# 安装  pip install onnxruntime-gpu
def get_onnx_providers():# 检查是否安装了GPU版本的ONNX Runtimeall_provider = ort.get_available_providers()if "CUDAExecutionProvider" in all_provider:providers = [("CUDAExecutionProvider", {"device_id": 0,"arena_extend_strategy": "kNextPowerOfTwo","gpu_mem_limit": 6 * 1024 * 1024 * 1024,  # 限制GPU内存使用为2GB"cudnn_conv_algo_search": "EXHAUSTIVE","do_copy_in_default_stream": True,}),"CPUExecutionProvider"]print("检测到NVIDIA GPU,使用CUDA加速")return providerselse:print("未检测到NVIDIA GPU,使用CPU")return ["CPUExecutionProvider"]if __name__ =="__main__":root_path =  "xxxx"# ONNX模型路径MODEL_PATH = os.path.join(root_path, "08以图搜图_找相似度/98_weights/classify_modified_model_224.onnx")# 图像文件夹路径IMAGE_DIR = os.path.join(root_path, "08以图搜图_找相似度/99_test_datasets/8_bcd已验收/1")# 分类结果输出路径OUTPUT_DIR = os.path.join(root_path, "08以图搜图_找相似度/99_test_datasets/8_bcd已验收/1_faiss_besk_k_classify")# 保存pickle文件路径PICKLE_PATH = os.path.join(root_path,"08以图搜图_找相似度/03_faiss/weights/all_features.pickle")# 图像特征提取后的向量维度FEATURE_DIM = 190  # 根据自己的模型输出维度修改# 推断图像尺寸CLASSIFY_SIZE = 224# 创建输出文件夹os.makedirs(OUTPUT_DIR, exist_ok=True)print("ONNX Runtime版本:", ort.__version__)print("可用执行器:", ort.get_available_providers())#   可用执行器: ['TensorrtExecutionProvider', 'CUDAExecutionProvider', 'AzureExecutionProvider', 'CPUExecutionProvider']################################################# GPU推理和CPU推理, ONNX Runtime 的某些优化会导致细微数值差异(尤其是 GPU 推理),GPU 计算存在浮点误差# 加载ONNX模型(动态获取输入/输出名称)ort_session = ort.InferenceSession(MODEL_PATH,providers=get_onnx_providers())# 加载ONNX模型进行CPU推理,CPU推理不会存在浮点误差(已验证)# ort_session = ort.InferenceSession(MODEL_PATH, providers=["CPUExecutionProvider"])################################################# 确保输出名称正确input_name = ort_session.get_inputs()[0].nameoutput_name = ort_session.get_outputs()[0].name# 提取特征向量features = []image_paths = []if not os.path.exists(PICKLE_PATH):print("====开始对所有图像推理, 提取特征====")for index, filename in tqdm(enumerate(os.listdir(IMAGE_DIR))):if filename.lower().endswith((".png", ".jpg", ".jpeg")):path = os.path.join(IMAGE_DIR, filename)try:# 前处理input_tensor = preprocess_image(path)# 推断feature = ort_session.run([output_name], {input_name: input_tensor})[0]features.append(feature)   # (1张图, 190维度)image_paths.append(path)except Exception as e:print(f"Error processing {filename}: {str(e)}")print("+++++提取特征结束+++++")print("====开始pickle向量文件保存====")# 需要转为numpy格式all_feats = np.concatenate(features, axis=0) # 将所有特征拼接起来  ( N张图, 190维度))print("all_feats维度:",all_feats.shape)# 写入到pickle文件with open(PICKLE_PATH, "wb") as f:pickle.dump({'all_feats': all_feats, 'imgs': image_paths}, f)print("+++++pickle向量文件保存结束+++++++++")# 如果存在,直接读取文件,不用再次计算图像特征else:with open(PICKLE_PATH, "rb") as f:data = pickle.load(f)all_feats = data['all_feats']image_paths = data['imgs']   print("====开始特征比对====")# 获取一张图像进行测试query_img = image_paths[0]# 计算query_img的特征# 前处理input_tensor = preprocess_image(query_img)# 推断获取图像特征feature_test = ort_session.run([output_name], {input_name: input_tensor})[0]print("计算图像特征维度:", feature_test.shape)# 和所有图片计算余弦相似度A_similarity = [1 - cosine(feature_test[0], feat) for feat in all_feats]print("计算余弦相似度维度:", len(A_similarity))print("计算余弦相似度:", A_similarity[0])# 获取相似度最高的topN张图片topN = 10# 获取相似度最高的topN张图片的索引A_ranked_results = np.argsort(A_similarity)[-topN:][::-1]  # 从高到低排序print(A_ranked_results)print("+++++特征比对结束+++++++++")


三. 将图像特征打包成faiss的index索引文件,匹配搜图。

(faiss有很多相似度度量方式,下面暂时只介绍IndexFlatIP 和 IndexFlatL2两种度量方式,若想查询其他度量方式,请查询 Faiss 的 GitHub Wiki )

特性IndexFlatL2IndexFlatIP
距离度量欧氏距离(L2距离)内积(Inner Product)
相似性方向距离越小越相似内积越大越相似
是否需要归一化不需要必须L2归一化(否则结果无意义)
内存占用相同相同
典型应用通用向量搜索(如图像特征匹配)方向敏感的相似度(如余弦相似度)
应用场景需要绝对距离度量(如地理位置)需要方向相似性(如NLP、文本相似、人脸))

3.1 使用 faiss.IndexFlatIP

在构建Faiss的 IndexFlatIP(内积索引)前,图像特征必须L2归一化,否则相似度结果不准确。
自己编写归一化,或者使用faiss内置的归一化.

# 特征图像L2归一化
def normalize_features(features):norms = np.linalg.norm(features, axis=1, keepdims=True) # 计算每个向量的L2范数return features / norms   # 每个向量除以其范数,归一化# 创建索引,参数:特征维度512
index = faiss.IndexFlatIP(FEATURE_DIM)   # 根据自己模型的输出维度 # 下面归一化 二选一
feature_test = normalize_features(all_feats) # L2 归一化
faiss.normalize_L2(all_feats)  # Faiss 内置L2归一化# 特征保存到faiss的index
index.add(all_feats)
faiss.write_index(index, FAISS_INDEX_PATH) # 保存index

3.2 使用 faiss.IndexFlatL2

直接计算特征图像与特征图像之间的距离,无需对特征图像做归一化。

# 创建索引,参数:特征维度512
index = faiss.IndexFlatL2(FEATURE_DIM)   # 根据自己模型的输出维度 # 特征保存到faiss的index
index.add(all_feats)
faiss.write_index(index, FAISS_INDEX_PATH) # 保存index

3.3 完整代码

以下代码是用IndexFlatIP度量方式, 若要用IndexFlatL2简单修改一下代码即可。

import os
import cv2
import numpy as np
from PIL import Image
import onnxruntime as ort
import shutil
from sklearn.cluster import KMeans
from sklearn.preprocessing import Normalizer
from  tqdm import tqdm
import math
import matplotlib.pyplot as plt
# 写入文件
import pickle
# 使用faiss向量库(在数据库里面实现向量的搜索)
import faiss
from scipy.spatial.distance import cosine# 特征图像L2归一化
def normalize_features(features):norms = np.linalg.norm(features, axis=1, keepdims=True) # 计算每个向量的L2范数, np.linalg.norm用于检查向量模长return features / norms   # 每个向量除以其范数,归一化# 图像预处理函数
def preprocess_image(image_path):roi_frame= cv2.imread(image_path)width = roi_frame.shape[1]height = roi_frame.shape[0]if (width != CLASSIFY_SIZE) or (height != CLASSIFY_SIZE) :if width > height:# 将图像逆时针旋转90度roi_frame = cv2.rotate(roi_frame, cv2.ROTATE_90_COUNTERCLOCKWISE)new_height = CLASSIFY_SIZEnew_width = int(roi_frame.shape[1] * (CLASSIFY_SIZE / roi_frame.shape[0]))roi_frame = cv2.resize(roi_frame, (new_width, new_height))# 计算上下左右漂移量y_offset = (CLASSIFY_SIZE - roi_frame.shape[0]) // 2x_offset = (CLASSIFY_SIZE - roi_frame.shape[1]) // 2gray_image = np.full((CLASSIFY_SIZE, CLASSIFY_SIZE, 3), 128, dtype=np.uint8)# 将调整大小后的目标图像放置到灰度图上gray_image[y_offset:y_offset + roi_frame.shape[0], x_offset:x_offset + roi_frame.shape[1]] = roi_frame# # 显示结果# cv2.imshow("gray_image", gray_image)# cv2.waitKey(1)# 将图像转为 rgbgray_image =  cv2.cvtColor(gray_image, cv2.COLOR_BGR2RGB)else:gray_image = cv2.cvtColor(roi_frame, cv2.COLOR_BGR2RGB)img_np = np.array(gray_image).transpose(2, 0, 1).astype(np.float32)# 假设模型需要[0,1]归一化img_np = img_np / 255.0# 均值 方差mean = np.array([0.485, 0.456, 0.406],dtype=np.float32).reshape(3, 1, 1)std = np.array([0.229, 0.224, 0.225],dtype=np.float32).reshape(3, 1, 1)img_np= (img_np - mean)/stdreturn np.expand_dims(img_np, axis=0)# todo
# 卸载 onnxruntime
# 安装  pip install onnxruntime-gpu
def get_onnx_providers():# 检查是否安装了GPU版本的ONNX Runtimeall_provider = ort.get_available_providers()if "CUDAExecutionProvider" in all_provider:providers = [("CUDAExecutionProvider", {"device_id": 0,"arena_extend_strategy": "kNextPowerOfTwo","gpu_mem_limit": 6 * 1024 * 1024 * 1024,  # 限制GPU内存使用为2GB"cudnn_conv_algo_search": "EXHAUSTIVE","do_copy_in_default_stream": True,}),"CPUExecutionProvider"]print("检测到NVIDIA GPU,使用CUDA加速")return providerselse:print("未检测到NVIDIA GPU,使用CPU")return ["CPUExecutionProvider"]if __name__ =="__main__":root_path =  "xxx"# ONNX模型路径MODEL_PATH = os.path.join(root_path, "08以图搜图_找相似度/98_weights/classify_modified_model_224.onnx")# 图像文件夹路径IMAGE_DIR = os.path.join(root_path, "08以图搜图_找相似度/99_test_datasets/8_bcd已验收/1")# 分类结果输出路径OUTPUT_DIR = os.path.join(root_path, "08以图搜图_找相似度/99_test_datasets/8_bcd已验收/1_faiss_besk_k_classify")# 保存faiss的index索引文件路径FAISS_INDEX_PATH = os.path.join(root_path,"08以图搜图_找相似度/03_faiss/weights/all_features_faiss.index")# 最佳聚类类别数量(用kmeans和inner找到的)BEST_NUM_CLUSTERS = 2501# 图像特征提取后的向量维度FEATURE_DIM = 190  # 根据自己的模型输出维度修改# 推断图像尺寸CLASSIFY_SIZE = 224# 手动划分分类数量# NUM_CLUSTERS = 3000# 创建输出文件夹os.makedirs(OUTPUT_DIR, exist_ok=True)print("ONNX Runtime版本:", ort.__version__)print("可用执行器:", ort.get_available_providers())#   可用执行器: ['TensorrtExecutionProvider', 'CUDAExecutionProvider', 'AzureExecutionProvider', 'CPUExecutionProvider']################################################# GPU推理和CPU推理, ONNX Runtime 的某些优化会导致细微数值差异(尤其是 GPU 推理),GPU 计算存在浮点误差# 加载ONNX模型(动态获取输入/输出名称)ort_session = ort.InferenceSession(MODEL_PATH,providers=get_onnx_providers())# 加载ONNX模型进行CPU推理# ort_session = ort.InferenceSession(MODEL_PATH, providers=["CPUExecutionProvider"])################################################# 确保输出名称正确input_name = ort_session.get_inputs()[0].nameoutput_name = ort_session.get_outputs()[0].name# 提取特征向量features = []image_paths = []if not os.path.exists(FAISS_INDEX_PATH):print("====开始对所有图像推理, 提取特征====")for index, filename in tqdm(enumerate(os.listdir(IMAGE_DIR))):if filename.lower().endswith((".png", ".jpg", ".jpeg")):path = os.path.join(IMAGE_DIR, filename)try:# 前处理input_tensor = preprocess_image(path)# 推断feature = ort_session.run([output_name], {input_name: input_tensor})[0]features.append(feature)   # (1张图, 190维度)image_paths.append(path)except Exception as e:print(f"Error processing {filename}: {str(e)}")print("+++++提取特征结束+++++")print("====开始faiss的index索引文件保存====")# 需要转为numpy格式all_feats = np.concatenate(features, axis=0) # 将所有特征拼接起来  ( N张图, 190维度))print("all_feats维度:",all_feats.shape)# 写入到faiss的index文件#(IndexFlatIP(需归一化,计算余弦相似度)  IndexFlatL2(无需归一化,直接计算距离))index = faiss.IndexFlatIP(FEATURE_DIM)   # 根据自己模型的输出维度   # all_feats = normalize_features(all_feats)faiss.normalize_L2(all_feats)  # Faiss 内置归一化# 添加数据index.add(all_feats)print(index.ntotal)# save indexfaiss.write_index(index, FAISS_INDEX_PATH)print("+++++faiss的index索引文件保存结束+++++++++")# 如果存在,直接读取文件,不用再次计算图像特征else:# read indexindex = faiss.read_index(FAISS_INDEX_PATH)print("====开始特征比对====")# 获取一张图像进行测试query_img = image_paths[0]# 计算query_img的特征# 前处理input_tensor = preprocess_image(query_img)# 推断获取图像特征feature_test = ort_session.run([output_name], {input_name: input_tensor})[0]# feature_test = normalize_features(feature_test) # L2 归一化faiss.normalize_L2(feature_test)  # Faiss 内置归一化print("计算图像特征维度:", feature_test.shape)# 获取相似度最高的topN张图片topN = 10D, I = index.search(feature_test, topN) # 默认使用的距离度量是内积,所以这里查询的是余弦相似度最高的topN张图片print(D.shape, I.shape)print("相似度最高的topN张图片索引:", I)print("相似度最高的topN张图片距离:",D)print("+++++特征比对结束+++++++++")


四. 先用Pickle保存图像特征,再用Faiss构建索引(更灵活)。

(1)能从pickle中复用最原始的图像特征,不用再重新计算图像特征,且随时查看和分析特征图像,也能结合faiss的快速查询搜索匹配。
(2)开发阶段用Pickle保存特征+Faiss索引,生产环境部署时直接保存优化后的Faiss索引。

示例代码

Pickle + Faiss

import pickle
import faiss
import numpy as np# features是每一张图像提取出来的图像特征(图像特征暂未归一化)
# img_path是每张图像的路径# 保存所有图像路径
image_paths.append(img_path)
# 需要转为numpy格式,将所有特征拼接起来  ( N张图, 190维度))
all_feats = np.concatenate(features, axis=0) 
print("all_feats维度:",all_feats.shape)
# 写入到pickle文件
with open(features.pkl, "wb") as f:pickle.dump({'all_feats': all_feats, 'imgs': image_paths}, f)  #把图像特征和图像路径一起保存# 2. 加载特征并用Faiss索引
with open("all_features.pickle", "rb") as f:all_feats = pickle.load(f)
# 利用all_feats[N]能取出第N张图像的原始图像特征
# 利用image_paths[N]能取出第N张图像的原始图像路径
# 构建并保存索引
index = faiss.IndexFlatIP(FEATURE_DIM)   # 根据自己模型的输出维度
faiss.normalize_L2(all_feats)  # Faiss 内置归一化
index.add(all_feats)
faiss.write_index(index, "index_flat.index")

仅Faiss索引

index = faiss.IndexFlatIP(FEATURE_DIM)   # 根据自己模型的输出维度
faiss.normalize_L2(all_feats)  # Faiss 内置归一化
index.add(all_feats)
faiss.write_index(index, "index_only.index")

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词