张量流:TF_SessionRun returns TF_INVALID_ARGUMENT

Tensorflow: TF_SessionRun returns TF_INVALID_ARGUMENT

我是 运行 使用 Tensorflow C API 来自 Deeplabv3 冻结图的会话。当我到达运行与TF_SessionRun的会话部分时,return值为3,表示TF_INVALID_ARGUMENT。我怀疑它可能必须与我离开 NULLTF_Operation* 输入(第 8 个参数又名 "Target Operations" 参数)做一些事情,但我找不到关于这个参数代表什么的任何文档。下面是我对 TF_SessionRun:

的有问题的调用

来自tiny_deeplab_api.cpp:

    // Allocate the input tensor
    TF_Tensor* const input = TF_NewTensor(TF_UINT8, img->dims, 3, img->data_ptr, img->bytes, &free_tensor, NULL);
    TF_Operation* oper_in = TF_GraphOperationByName(graph, "ImageTensor");
    const TF_Output oper_in_ = {oper_in, 0};

    // Allocate the output tensor
    TF_Tensor* output = TF_NewTensor(TF_UINT8, seg->dims, 2, seg->data_ptr, seg->bytes, &free_tensor, NULL);
    TF_Operation* oper_out = TF_GraphOperationByName(graph, "SemanticPredictions");
    const TF_Output oper_out_ = {oper_out, 0};

    // Run the session on the input tensor
    TF_SessionRun(session, NULL, &oper_in_, &input, 1, &oper_out_, &output, 1, NULL, 0, NULL, status);

    return TF_GetCode(status); // https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/tf_status.h#L42 

其中 imgsegimage_tsegmap_t 类型,它们包含指向数据和维度数组的指针,TF_NewTensor() 方法可以用于生成输入和输出张量,然后传递给 TF_SessionRun()。 (来自 tiny_deeplab_api.hpp):

typedef struct segmap {
    const int64_t* dims;
    size_t bytes;
    uint8_t* data_ptr;
} segmap_t;

typedef struct image {
    const int64_t* dims;
    size_t bytes;
    uint8_t* data_ptr;
} image_t;

以下是源代码,以防问题不明显...

test.cpp:

#include <opencv2/opencv.hpp>
#include "tiny_deeplab_api.hpp"
#include <iostream>
#include <algorithm>

int main() {
    using namespace std;
    using namespace cv;

    // Initialize Deeplab object
    Deeplab dl = Deeplab();
    cout << "Successfully constructed Deeplab object" << endl;

    // Read & resize input image
    Mat image = imread("/Users/Daniel/Desktop/cat.jpg"); 
    int orig_height = image.size().height;
    int orig_width = image.size().width;
    double resize_ratio = (double) 513 / max(orig_height, orig_width);
    Size new_size((int)(resize_ratio*orig_width), (int)(resize_ratio*orig_height));
    Mat resized_image;
    resize(image, resized_image, new_size);
    cout << "Image resized (h, w): (" << orig_height << "," << orig_width << ") --> (" << new_size.height << ", " << new_size.width << ")" << endl;
    imshow("Image", resized_image);
    waitKey(0);


    // Allocate input image object
    const int64_t dims_in[3] = {new_size.width, new_size.height, 3};
    image_t* img_in = (image_t*)malloc(sizeof(image_t));
    img_in->dims = &dims_in[0];
    img_in->data_ptr = resized_image.data;
    img_in->bytes = new_size.width*new_size.height*3*sizeof(uint8_t);

    // Allocate output segmentation map object
    const int64_t dims_out[2] = {new_size.width, new_size.height};
    segmap_t* seg_out = (segmap_t*)malloc(sizeof(segmap_t));
    seg_out->dims = &dims_out[0];
    seg_out->data_ptr = (uint8_t*)malloc(new_size.width*new_size.height);
    seg_out->bytes = new_size.width*new_size.height*sizeof(uint8_t);

    // Run Deeplab
    cout << "Running segmentation" << endl;
    int status = dl.run_segmentation(img_in, seg_out);
    if(status != 0) {
        cout << "ERROR RUNNING SEGMENTATION: " << status << endl;
        return 1;
    }

    cout << "Successfully ran segmentation" << endl;

    // Interpret results

    return 0;
}

tiny_deeplab_api.hpp:

#ifndef TINY_DEEPLAB_API_HPP_
#define TINY_DEEPLAB_API_HPP_

#include <tensorflow/c/c_api.h>

TF_Buffer* read_file(const char* file);
void free_buffer(void* data, size_t length);
void free_tensor(void* data, size_t length, void* args);

typedef struct segmap {
    const int64_t* dims;
    size_t bytes;
    uint8_t* data_ptr;
} segmap_t;

typedef struct image {
    const int64_t* dims;
    size_t bytes;
    uint8_t* data_ptr;
} image_t;


class Deeplab {
   private:
    TF_Session* session;
    TF_Graph* graph;
    TF_Output output_oper;
    TF_Output input_oper;
    TF_Status* status;

   public:
    Deeplab(); // Constructor 
    ~Deeplab();
    int run_segmentation(image_t*, segmap_t*);
};

#endif // TINY_DEEPLAB_API_HPP_

tiny_deeplab_api.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <tensorflow/c/c_api.h>
#include "tiny_deeplab_api.hpp"

Deeplab::Deeplab() {
    using namespace std;
    cout << "Hello from TensorFlow C library version" << TF_Version() << endl;

    // Import Deeplab graph (as a frozen graph, it has the weights hard-coded in as constants, so no need to restore the checkpoint)
    TF_Buffer* graph_def = read_file("../Models/Deeplab_model_unpacked/deeplabv3_mnv2_cityscapes_train/frozen_inference_graph.pb");
    graph = TF_NewGraph();
    status = TF_NewStatus();
    TF_ImportGraphDefOptions* opts = TF_NewImportGraphDefOptions();
    TF_GraphImportGraphDef(graph, graph_def, opts, status);
    TF_DeleteImportGraphDefOptions(opts);
    if (TF_GetCode(status) != TF_OK) {
        fprintf(stderr, "ERROR: Unable to import graph %s", TF_Message(status));
        return;
    }
    cout << "Successfully loaded Deeplab graph" << endl;
    TF_DeleteBuffer(graph_def);

    // Initialize Session
    TF_SessionOptions* sess_opts = TF_NewSessionOptions();
    session = TF_NewSession(graph, sess_opts, status);
}

Deeplab::~Deeplab() {
    using namespace std;
    TF_CloseSession(session, status);
    TF_DeleteSession(session, status);
    TF_DeleteStatus(status);
    TF_DeleteGraph(graph);
    cout << "Destroyed Deeplab object" << endl;
}

int Deeplab::run_segmentation(image_t* img, segmap_t* seg) {
    //TODO: Delete old TF_Tensor, TF_Operation, and TF_Output 

    // Allocate the input tensor
    TF_Tensor* const input = TF_NewTensor(TF_UINT8, img->dims, 3, img->data_ptr, img->bytes, &free_tensor, NULL);
    TF_Operation* oper_in = TF_GraphOperationByName(graph, "ImageTensor");
    const TF_Output oper_in_ = {oper_in, 0};

    // Allocate the output tensor
    TF_Tensor* output = TF_NewTensor(TF_UINT8, seg->dims, 2, seg->data_ptr, seg->bytes, &free_tensor, NULL);
    TF_Operation* oper_out = TF_GraphOperationByName(graph, "SemanticPredictions");
    const TF_Output oper_out_ = {oper_out, 0};

    // Run the session on the input tensor
    TF_SessionRun(session, NULL, &oper_in_, &input, 1, &oper_out_, &output, 1, NULL, 0, NULL, status);

    return TF_GetCode(status); // https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/tf_status.h#L42 
}

TF_Buffer* read_file(const char* file) {
    FILE *f = fopen(file, "rb");
    fseek(f, 0, SEEK_END);
    long fsize = ftell(f);
    fseek(f, 0, SEEK_SET);  //same as rewind(f);

    void* data = malloc(fsize);
    fread(data, fsize, 1, f);
    fclose(f);

    TF_Buffer* buf = TF_NewBuffer();
    buf->data = data;
    buf->length = fsize;
    buf->data_deallocator = free_buffer;
    return buf;
}

void free_buffer(void* data, size_t length) { 
        free(data);
}

void free_tensor(void* data, size_t length, void* args) { 
        free(data);
}

和运行./test的输出:

Hello from TensorFlow C library version1.14.0
Successfully loaded Deeplab graph
2019-08-25 13:40:06.947965: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
Successfully constructed Deeplab object
Image resized (h, w): (1680,2987) --> (288, 513)
Running segmentation
ERROR RUNNING SEGMENTATION: 3
Destroyed Deeplab object

答案是,出于某种原因(为什么?)Deeplab 输入和输出张量的维度不是 {width, height, 3} 和 {width, height},而是 {1, width, height, 3 } 和 {1,宽度,高度}。制作成这种形式的维数数组后,TF_SessionRun运行没有报错。