一、问题1
from PaddleX.paddlex import create_pipeline
pipeline_ = create_pipeline(pipeline="face_recognition", device="gpu")
index_file_path = "./face_index/vector.index"
if os.path.exists(index_file_path):
print("加载已有的索引")
index_data = "face_index
else:
print("索引文件不存在,构建索引")
index_data = pipeline_.build_index(gallery_imgs="face_demo_gallery", gallery_label="face_demo_gallery.txt")
index_data.save("face_index") # 会在face_recognition产生face_index/id_map.yaml
在执行构建索引这一步的时候报错了
Using official model (PP-YOLOE_plus-S_face), the model files will be automatically downloaded and saved in C:\Users\guan.linyi\.paddlex\official_model
信息: 用提供的模式无法找到文件。
Process finished with exit code -1073741819 (0xC0000005)
1.1、问题分析
1、先去把最新版本的PaddleX源码拉下来,截止2025年9月30日,最新版本是3.2
https://github.com/PaddlePaddle/PaddleX/tree/release/3.2?tab=readme-ov-file
这样做的目的是希望新版本的代码已经解决了这个bug
2、拉下来再试了一下。还是报同样的错误。这时候考虑错误产生的原因,原因可能是来自三个方面:系统问题、数据问题、代码问题、环境问题,已经通过拉取最新代码,那么代码问题的可能性很小,看起来也不像是系统问题,数据是用的官网的demo数据,应该不是数据问题。
那大概率是环境问题。
对于环境问题,已经按照下面官网的方式安装了PaddlePaddle和paddlex
python
1.先安装PaddlePaddle:
# https://paddlepaddle.github.io/PaddleX/latest/installation/paddlepaddle_install.html#docker
# CPU 版本
python -m pip install paddlepaddle==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
# GPU 版本,需显卡驱动程序版本 ≥450.80.02(Linux)或 ≥452.39(Windows)
python -m pip install paddlepaddle-gpu==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
# GPU 版本,需显卡驱动程序版本 ≥550.54.14(Linux)或 ≥550.54.14(Windows)
python -m pip install paddlepaddle-gpu==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cu126/
内网环境:
pip install paddlepaddle_gpu-3.0.0rc0-cp310-cp310-win_amd64.whl
2.再安装paddlex
# https://paddlepaddle.github.io/PaddleX/latest/installation/installation.html#1
pip install paddlex
内网环境:
拉取paddlex3.2源码PaddleX,再进入PaddleX目录,pip install -e .
结果还是报错。
3、这种情况下,我们应该想办法追踪到程序是在哪个文件哪行代码报错停止的。于是开启了debug之后发现
paddlex/inference/pipelines/components/faisser.py
python
@class_requires_deps("faiss-cpu")
class FaissBuilder:
@classmethod
def build(
cls,
gallery_imgs,
gallery_label,
predict_func,
metric_type="IP",
index_type="HNSW32",
):
assert (
index_type in cls.SUPPORT_INDEX_TYPE
), f"Supported index types only: {cls.SUPPORT_INDEX_TYPE}!"
assert (
metric_type in cls.SUPPORT_METRIC_TYPE
), f"Supported metric types only: {cls.SUPPORT_METRIC_TYPE}!"
if isinstance(gallery_label, str):
gallery_docs, gallery_list = cls.load_gallery(gallery_label, gallery_imgs)
else:
gallery_docs, gallery_list = gallery_label, gallery_imgs
# 这里获取特征
features = [res["feature"] for res in predict_func(gallery_list)]
dtype = np.uint8 if metric_type in cls.BINARY_METRIC_TYPE else np.float32
features = np.array(features).astype(dtype)
vector_num, vector_dim = features.shape
if metric_type in cls.BINARY_METRIC_TYPE:
index = faiss.index_binary_factory(
vector_dim,
cls._get_index_type(metric_type, index_type, vector_num),
cls._get_metric_type(metric_type),
)
else:
index = faiss.index_factory(
vector_dim,
cls._get_index_type(metric_type, index_type, vector_num),
cls._get_metric_type(metric_type),
)
index = faiss.IndexIDMap2(index)
ids = {}
# calculate id for new data
index, ids = cls._add_gallery(
metric_type, index, ids, features, gallery_docs, mode="new"
)
return IndexData(
index, {"id_map": ids, "metric_type": metric_type, "index_type": index_type}
)
dtype = np.uint8 if metric_type in cls.BINARY_METRIC_TYPE else np.float32
features = np.array(features).astype(dtype)
vector_num, vector_dim = features.shape
这个features是个list,list的长度就是记忆库里面的图片数,比如245,每个特征向量维度是512
然后会变成(245,512)
出错的地方是这里:
python
# calculate id for new data
index, ids = cls._add_gallery(
metric_type, index, ids, features, gallery_docs, mode="new"
)
@classmethod
def _add_gallery(
cls, metric_type, index, ids, gallery_features, gallery_docs, mode
):
start_id = max(ids.keys()) + 1 if ids else 0
ids_now = (np.arange(0, len(gallery_docs)) + start_id).astype(np.int64)
# only train when new index file
if mode == "new":
if metric_type in cls.BINARY_METRIC_TYPE:
index.add(gallery_features)
else:
index.train(gallery_features)
if metric_type not in cls.BINARY_METRIC_TYPE:
index.add_with_ids(gallery_features, ids_now) # 这句报错
# TODO(gaotingquan): how append when using hamming metric type
# else:
# pass
for i, d in zip(list(ids_now), gallery_docs):
ids[i] = d
return index, ids
运行到index.add_with_ids(gallery_features, ids_now) # 这句报错
swig/python detected a memory leak of type 'std::unordered_map< long long,long long > *', no destructor found.
swig/python detected a memory leak of type 'std::unordered_map< long long,long long > *', no destructor found.
index.add_with_ids(gallery_features, ids_now)这句会进入
python
D:\miniforge3\envs\stranger_win_env\Lib\site-packages\faiss
class IndexIDMap2(IndexIDMap):
def add_with_ids(self, n, x, xids):
return _swigfaiss_avx2.IndexIDMap2_add_with_ids(sellf, n, x, xids)
1.2 直接原因分析
不是 Python 本身的问题 ,而是 FAISS 的 Python 接口(SWIG 封装) 在调用 add_with_ids
时,内部使用了 std::unordered_map<long long, long long>
,但 没有正确释放内存 ,导致 内存泄漏警告。
FAISS 的 Index::add_with_ids()
方法在内部会构造一个 id_map
,但 SWIG 没有为这个 map 提供析构函数,所以 Python 无法释放它,导致泄漏警告。
1.3 解决方法
直接去https://pypi.org/project/faiss-cpu/1.12.0/#history ,安装最新版本的
pip install faiss-cpu==1.12.0
这实际上是内网环境导致的坑,内网环境的源比较落后,所以不能安装最新版本的库,这导致如果你某些库去pypi找whl装最新的,就会跟另一些旧的库不兼容,但如果你找旧库去兼容旧库,你最好祈祷那些旧库是没有bug的,如果旧库是有bug的,就会像现在这样,被迫去找最新的库解决旧库的bug,那么这时候你最好祈祷新的库跟你其他旧的库是兼容的,否则你装不了新的库,还好,这个库装最新的是兼容的。或许存在直接手动解决旧库bug的方法,但是这里没有去尝试,因为说实在的,新库常常修复了很多bug,自己修bug太难太麻烦了。
二、问题2
2.1 问题分析
paddlex3.2 居然要联网才能推理,原先是这样推理的:
python
# https://paddlepaddle.github.io/PaddleX/latest/pipeline_usage/tutorials/cv_pipelines/face_recognition.html#222-python
from paddlex import create_pipeline
pipeline = create_pipeline(pipeline="face_recognition")
index_data = pipeline.build_index(gallery_imgs="face_demo_gallery", gallery_label="face_demo_gallery/gallery.txt")
index_data.save("face_index")
output = pipeline.predict("friends1.jpg", index=index_data)
for res in output:
res.print()
res.save_to_img("./output/")
res.save_to_json("./output/")
2.2 解决方法
我们把pipeline改成读取本地的配置文件:
python
# https://paddlepaddle.github.io/PaddleX/latest/pipeline_usage/tutorials/cv_pipelines/face_recognition.html#222-python
from paddlex import create_pipeline
pipeline = create_pipeline(pipeline=r"D:\zero_track\mem_and_mat\PaddleX\paddlex\configs\pipelines\face_recognition.yaml", device="gpu")
index_data = pipeline.build_index(gallery_imgs="face_demo_gallery", gallery_label="face_demo_gallery/gallery.txt")
index_data.save("face_index")
output = pipeline.predict(r"D:\zero_track\mem_and_mat\face_demo_gallery\test_images\friends1.jpg", index=index_data)
for res in output:
res.print()
res.save_to_img("./output/")
res.save_to_json("./output/")
没想到又报了一个读取字体要联网的
Connecting to https://paddle-model-ecology.bj.bc
ebos.com/paddlex/PaddleX3.0/fonts/PingFang-SC-Regular.ttf ...
找到D:\zero_track\mem_and_mat\PaddleX\paddlex\utils\fonts.py
把PINGFANG_FONT那行注释了,改成自己的local_path,自己的字体是Github上找的下载下来的
PINGFANG_FONT = Font(font_name="MSYH.TTC", local_path=r"D:\zero_track\mem_and_mat\fonts\MSYH.TTC")
三、总结
内网装环境是个坑。