python - 如何使用 C++ 正确使用 tensorflow 从 YOLO 模型获取输出?

标签 python c++ tensorflow keras yolo

我正在尝试用 C++ 编写一个使用 YOLO 模型的推理程序。我搜索了一些关于darknet的信息,但是它必须使用.cfg文件来导入模型结构(这对我来说有点太复杂了......),因此我想用tensorflow来做程序。

(我的模型权重从.hdf5(在Python中使用)转换为.pb(在C++中使用))

我发现了一些用python编写的示例,看起来他们在推理过程之前做了一些工作... Source

def yolo_eval(yolo_outputs,
              anchors,
              num_classes,
              image_shape,
              max_boxes=50,
              score_threshold=.6,
              iou_threshold=.5):

    """Evaluate YOLO model on given input and return filtered boxes."""
    num_layers = len(yolo_outputs)
    anchor_mask = [[6,7,8], [3,4,5], [0,1,2]] if num_layers==3 else [[3,4,5], [1,2,3]] # default setting
    input_shape = K.shape(yolo_outputs[0])[1:3] * 32
    boxes = []
    box_scores = []
    for l in range(num_layers):
        _boxes, _box_scores = yolo_boxes_and_scores(yolo_outputs[l],
            anchors[anchor_mask[l]], num_classes, input_shape, image_shape)
        boxes.append(_boxes)
        box_scores.append(_box_scores)
    boxes = K.concatenate(boxes, axis=0)
    box_scores = K.concatenate(box_scores, axis=0)

    mask = box_scores >= score_threshold
    max_boxes_tensor = K.constant(max_boxes, dtype='int32')
    boxes_ = []
    scores_ = []
    classes_ = []
    for c in range(num_classes):
        # TODO: use keras backend instead of tf.
        class_boxes = tf.boolean_mask(boxes, mask[:, c])
        class_box_scores = tf.boolean_mask(box_scores[:, c], mask[:, c])
        nms_index = tf.image.non_max_suppression(
            class_boxes, class_box_scores, max_boxes_tensor, iou_threshold=iou_threshold)
        class_boxes = K.gather(class_boxes, nms_index)
        class_box_scores = K.gather(class_box_scores, nms_index)
        classes = K.ones_like(class_box_scores, 'int32') * c
        boxes_.append(class_boxes)
        scores_.append(class_box_scores)
        classes_.append(classes)
    boxes_ = K.concatenate(boxes_, axis=0)
    scores_ = K.concatenate(scores_, axis=0)
    classes_ = K.concatenate(classes_, axis=0)

    return boxes_, scores_, classes_

我已经打印出了返回值 它看起来像这样

boxes-> Tensor("concat_11:0", shape=(?, 4), dtype=float32)

scores-> Tensor("concat_12:0", shape=(?,), dtype=float32)

classes-> Tensor("concat_13:0", shape=(?,), dtype=int32)

我的YOLO模型(.hdf5)的原始输出是(我通过打印model.output得到这个)

tf.Tensor 'conv2d_59_1/BiasAdd:0' shape=(?, ?, ?, 21) dtype=float32

tf.Tensor 'conv2d_67_1/BiasAdd:0' shape=(?, ?, ?, 21) dtype=float32

tf.Tensor 'conv2d_75_1/BiasAdd:0' shape=(?, ?, ?, 21) dtype=float32

Python代码的推理部分是

out_boxes, out_scores, out_classes = sess.run(
                                    [boxes, scores, classes],
                                    feed_dict={
                                        yolo_model.input: image_data,
                                        input_image_shape: [image.size[1], image.size[0]],
                                        K.learning_phase(): 0
                                    })

与Python版本的推理代码相比, C++ 部分是... ( Reference )

int main()
{
    string image = "test.jpg";
    string graph = "yolo_weight.pb";
    string labels = "coco.names";
    int32 input_width = 416;
    int32 input_height = 416;
    float input_mean = 0;
    float input_std = 255;
    string input_layer = "input_1:0";
    std::vector<std::string> output_layer = {"conv2d_59/BiasAdd:0", "conv2d_67/BiasAdd:0", "conv2d_75/BiasAdd:0" };

    std::unique_ptr<tensorflow::Session> session;
    string graph_path = tensorflow::io::JoinPath(root_dir, graph);
    Status load_graph_status = LoadGraph(graph_path, &session);

    std::vector<Tensor> resized_tensors;
    string image_path = tensorflow::io::JoinPath(root_dir, image);
    Status read_tensor_status = ReadTensorFromImageFile(image_path, input_height, input_width, 
    input_mean, input_std, &resized_tensors);

    Tensor inpTensor = Tensor(DT_FLOAT, TensorShape({ 1, input_height, input_width, 3 }));
    std::vector<Tensor> outputs;
    cv::Mat srcImage = cv::imread(image);
    cv::resize(srcImage, srcImage, cv::Size(input_width, input_height));
    srcImage.convertTo(srcImage, CV_32FC3);
    srcImage = srcImage / 255;  
    string ty = type2str(srcImage.type());
    float *p = (&inpTensor)->flat<float>().data();
    cv::Mat tensorMat(input_height, input_width, CV_32FC3, p);
    srcImage.convertTo(tensorMat, CV_32FC3);
    Status run_status = session->Run({{ input_layer, inpTensor }}, { output_layer }, {}, &outputs);
    int cc = 1;
    auto output_detection_class = outputs[0].tensor<float, 4>();
    std::cout << "detection scores" << std::endl;
    std::cout << "typeid(output_detection_scoreclass).name->" << typeid(output_detection_class).name() << std::endl;
    for (int i = 0; i < 13; ++i)
    {
        for (int j = 0; j < 13; ++j)
        {
            for (int k = 0; k < 21; ++k)
            {
                // using (index_1, index_2, index_3) to access the element in a tensor
                printf("i->%d, j->%d, k->%d\t", i, j, k);
                std::cout << output_detection_class(1, i, j, k) << "\t";
                cc += 1;
                if (cc % 4 == 0)
                {
                    std::cout << "\n";
                }
            }
        }
        std::cout << std::endl;
    }
    return 0;
}

C++版本推断部分的输出为

outputs.size()-> 3

outputs[0].shape()-> [1,13,13,21]

outputs[1].shape()-> [1,26,26,21]

outputs[2].shape()-> [1,52,52,21]

但是我得到的输出非常奇怪......

(outputs[0]的输出值看起来不像分数、类别或坐标中的任何一个......) Yolo output result

所以我想知道是不是因为我错过了推理之前用 python 编写的部分?或者我使用了错误的方式来获取输出数据?

我检查了一些相关的问题和答案...

1.Yolo v3 model output clarification with keras

2.Convert YoloV3 output to coordinates of bounding box, label and confidence

3.How to access tensorflow::Tensor C++

但是我还是不知道怎么做:(

我还找到了repo这可能会有所帮助, 我看了一下它的yolo.cpp,但是它的模型输出张量的形状和我的不一样,我不确定是否可以直接修改代码,它的输出张量是

tf.Tensor 'import/output:0' shape=(?, 735) dtype = float32

感谢任何帮助或建议...

最佳答案

如果您仍在为此苦苦挣扎,我不知道您在哪里将 Sigmoid 和 Exp 应用于输出层值。

您可以查看这篇论文,其中描述了如何处理输出。

https://medium.com/analytics-vidhya/yolo-v3-theory-explained-33100f6d193

关于python - 如何使用 C++ 正确使用 tensorflow 从 YOLO 模型获取输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59677170/

相关文章:

python - Azure SDK for Python批量读取blob数据

python - 如何在 Python 中使用 random.shuffle 的可选参数

c++ - 调试 lambda 内存损坏 ||自动监视 GDB 中的对象指针

c++ - 优化器 : replace const reference with const object

python - 在 Keras 中使用 K.eval() 将 Tensor 转换为 np.array 返回 InvalidArgumentError

python - 为什么 TensorFlow WHL 文件不包含所有必需的依赖项?

tensorflow - 如何获取重新训练的 inception-v3 模型的 'checkpoint'?

python - SQLAlchemy 中的 Model.query 和 session.query(Model) 有什么区别?

c++ - 等待条件变量加载 CPU 内核吗?

python - 螺旋图案 : how do I find a number given coordinates?