Paddle 使用C++预测库对应的Python接口对yolov3物体检测模型预测结果有误

w7t8yxp5  于 2021-11-30  发布在  Java
关注(0)|答案(12)|浏览(363)

   1)PaddlePaddle版本:1.5.2源码编译, -DWITH_GPU=OFF -DON_INFER=ON
   2)CPU:Intel(R) Xeon(R) CPU E5-2650 v4 @ 2.20GHz
   3)GPU:无
   4)系统环境:镜像paddle:1.5.2-gpu-cuda9.0-cudnn7,Python2.7
-预测信息
1)yolov3模型训练方式参考https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/yolov3
2)python API预测代码如下:

import argparse
import numpy as np
import cv2
from paddle.fluid.core import PaddleBuf
from paddle.fluid.core import PaddleDType
from paddle.fluid.core import PaddleTensor
from paddle.fluid.core import AnalysisConfig
from paddle.fluid.core import create_paddle_predictor

def main():
    args = parse_args()

    # Set config
    config = AnalysisConfig(args.prog_file, args.params_file)
    config.disable_gpu()
    config.set_cpu_math_library_num_threads(10)
    config.enable_mkldnn()

    # Create PaddlePredictor
    predictor = create_paddle_predictor(config)

    # Set inputs
    inputs = input_gen(args.image_path)

    # Infer
    outputs = predictor.run(inputs)

    # parse outputs
    print outputs
    output = outputs[0]
    print(output.name)
    output_data = output.data.float_data()
    output = np.array(output_data).reshape((-1, 6))
    output = output[np.flip(output[:,1].argsort())]
    for box in output[:10, :].tolist():
        print box

def input_gen(filename, resize=(800, 800), img_mean=[0.485, 0.456, 0.406], img_std=[0.229, 0.224, 0.225]):
    im = cv2.imread(filename).astype('float32')
    im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
    h, w, _ = im.shape
    out_img = cv2.resize(im, resize, interpolation=3)
    mean = np.array(img_mean).reshape((1, 1, -1))
    std = np.array(img_std).reshape((1, 1, -1))
    out_img = (out_img / 255.0 - mean) / std
    out_img = out_img.transpose((2, 0, 1))

    image = PaddleTensor()
    image.name = "image"
    image.shape = [1, out_img.shape[0], out_img.shape[1], out_img.shape[2]]
    image.dtype = PaddleDType.FLOAT32
    image.data = PaddleBuf(
        out_img.flatten().astype("float32").tolist())

    image_info = PaddleTensor()
    image_info.name = "im_shape"
    image_info.shape = [1, 2]
    image_info.dtype = PaddleDType.INT32
    image_info.data = PaddleBuf(
        np.array([h, w]).flatten().astype("int32").tolist())
    # return [image, ]
    return [image, image_info]

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("--model_dir", type=str, help="model dir")
    parser.add_argument("--prog_file", type=str, help="program filename")
    parser.add_argument("--params_file", type=str, help="parameter filename")
    parser.add_argument("--image_path", type=str, help="image path")

    return parser.parse_args()

if __name__ == "__main__":
    main()
  • 问题描述:开始使用fluid.Executor(place).run的方式对训练好的yolov3模型进行预测,时间较长,所以选择使用C预测库对应的Python接口来使用多核进行预测(预测代码如上)。通过可视化和对比两种方式的infer结果,发现第一种方式的结果是正确的,但C预测库的预测结果有些问题(没有错误或者警告日志)。两者的top10结果如下,每行是一个物体检测框[label, score, x1, y1, x2, y2]:

fluid.Executor.run:

C++预测库python API:

对比结果可以发现,两种方式的预测结果中,label, score, y1, y2的结果都是非常接近的,只有x1,x2的结果存在异常。

jc3wubiy

jc3wubiy1#

  1. 你是怎么保存模型的?
  2. fluid.Executor.run,是通过fluid.io.load_inference_model加载的该模型吗?
r1wp621o

r1wp621o2#

问题1. 保存模型是调用的fluid.io.save_inference_model

fluid.io.save_inference_model(dirname=model_path,
                               feeded_var_names=[model_test.image.name, model_test.im_shape.name],
                               target_vars=[nmsed_out],
                               executor=exe,
                               params_filename='params',
                               model_filename='model',
                               main_program=main_prog)

问题2、fluid.Executor.run是通过fluid.io.load_inference_model加载的模型

l7wslrjt

l7wslrjt3#

猜测可能是w设置的不对,但看代码觉得似乎没啥问题。。。

yzuktlbb

yzuktlbb4#

好像发现问题出在定义im_shape的这段代码

image_info = PaddleTensor()
    image_info.name = "im_shape"
    image_info.shape = [1, 2]
    image_info.dtype = PaddleDType.INT32
    image_info.data = PaddleBuf(
        np.array([h, w]).flatten().astype("int32").tolist())
    print "numpy data: ",np.array([h, w]).flatten().astype("int32").tolist()
    print "paddlebuf int32_data: ", image_info.data.int32_data()

打印结果如下:

在预测的结果中,我也输出了im_shape,得到的结果是[288.0, 0.0]。感觉是预测时截取了image_info.data.int32_data()的前两位,导致width为0,最终预测结果的x1,x2为0和-1。
另外打印image_info.data.int64_data()和image_info.data.float_data()都是 [288L, 384L]。
是我定义的有问题么,还是int32_data()就是这么设计的?
如果预测的输入是int类型的话,貌似也只能这么传,把dtype定义为INT64或者FLOAT32回报错。

s71maibg

s71maibg5#

嗯,应该是这个原因。是Python数据传到C++后端时出了错。这是1.5版本里面的bug,develop里面已经修复,请下载最新的whl:https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/beginners_guide/install/Tables.html#whl-release

测试代码:image_info.data = PaddleBuf(np.array([h, w]).flatten().astype("int32"))

mqxuamgl

mqxuamgl6#

用develop分支重新编译paddle以后,确实可以了。

另外,在使用C++预测库对应的Python接口时,遇到两个小问题。
1、之前希望在一个镜像里即支持fluid的GPU和CPU预测,在编译paddle的时候需要把DWITH_GPU设置为ON来支持GPU预测,但是发现这样编的Paddle无法在没有GPU的机器上使用CPU进行预测

2、在一个进程里面,加载完模型可能会占几百兆的内存,然后使用模型预测一张图片时,内存可能会长到几个G,之前跑MaskRCNN时,检测框特别多时甚至占到十几个G,但预测结束后该进程占的内存不会减少,如果把模型封装成服务的话,服务所占的内存可能会占很大,即使是在服务空闲的时候。

kr98yfug

kr98yfug7#

可以打开显存或者内存复用试一下:

config.enable_memory_optim(false, false);
mzaanser

mzaanser8#

运行时设置export CUDA_VISIABLE_DEVICES=""试下?

f0brbegy

f0brbegy9#

应该是 export CUDA_VISIBLE_DEVICES="" 吧,试了下,是可以的,这个CUDA_VISIABLE_DEVICES不行。谢谢!

eufgjt7s

eufgjt7s10#

在CPU预测,会报错?

nkkqxpd9

nkkqxpd911#

先确认一下,好像不只是x1、x2有差别。
fluid.Executor.run结果的第2条,是C++预测Python API结果的第3条。后面几条数据都不一样啊?

wgx48brx

wgx48brx12#

在fluid.Executor.run的正常结果中,应该是被NMS过滤掉了。可以对比一下C预测的第1条和第2条的y1,y2,数值比较接近,但x1和x2的结果存在问题,所以没有被过滤掉,C预测的第4条和第5条数据,以及后面的结果也是类似的情况

相关问题