下記のような、VGG16をファインチューニングしたものをc++（推論部分はc）で作成したく考えています。  
opancvで画像を読み込み、（1,224,224,3)へ変換したものを用いています。  
出力部分は、６個への分類になります。

pythonを用いてファインチューニングしたグラフはpb化しています。  
（tensorflow1.5使用」)  
その際の学習画像は下記です。

```

    temp_img_array=img_to_array(temp_img)
    temp_img_array=temp_img_array.astype('float32')/255.0
    temp_img_array=temp_img_array.reshape((1,224,224,3))
    
```

どこをどうすればいいのか教えていただきたくお願いします。

```

    Hello from TensorFlow C library version 2.3.0
    image > 224 x 224 x 3
    --- graph info ---
    input_1
    block1_conv1/kernel
    block1_conv1/kernel/read
    block1_conv1/bias
    ；
    ；
    dense_1/bias
    dense_1/bias/read
    dense_2/MatMul
    dense_2/BiasAdd
    dense_2/Softmax
    --- graph info ---
    
```

入力のテンソルの形がおかしいと思うのですが、

```

    #include <stdio.h>
    #include <opencv2/opencv.hpp>
    #include <tensorflow/c/c_api.h>
    #include "tf_utils.hpp"
    
    #define MODEL_FILENAME  "ep_156_ls_0.1.pb"
    #define INPUTIMAGEPATH  "Valid_pic/"
    #define INPUTIMAGENAME  "Valid_pic/ten__146.bmp"
    #define IMAGE_BATCH     1
    #define IMAGE_SIZE      224
    #define IMAGE_CH        3
    
    #define LAYERNAME_INPUT  "input_1"
    #define LAYERNAME_OUTPUT "dense_2/Softmax"
    
    static int displayGraphInfo()
    {
        TF_Graph* graph = tf_utils::LoadGraph(MODEL_FILENAME);
        if (graph == nullptr) {
            std::cout << "Can't load graph" << std::endl;
            return 1;
        }
    
        size_t pos = 0;
        TF_Operation* oper;
        printf("--- graph info ---\n");
        while ((oper = TF_GraphNextOperation(graph, &pos)) != nullptr) {
            printf("%s\n", TF_OperationName(oper));
        }
        printf("--- graph info ---\n");
    
        TF_DeleteGraph(graph);
        return 0;
    }
    
    int main()
    {
        printf("Hello from TensorFlow C library version %s\n", TF_Version());
    
        /* read input image data */
        cv::Mat image = cv::imread(INPUTIMAGENAME);
        cv::imshow("InputImage", image);
    
        /* convert to 224 x 224 RGB image (normalized: 0 ~ 1.0) */
        cv::cvtColor(image, image, cv::COLOR_RGB2BGR);
        cv::resize(image, image, cv::Size(IMAGE_SIZE, IMAGE_SIZE));
        cv::imshow("InputImage for CNN", image);
        image.convertTo(image, CV_32FC1, 1.0 / 255);
    
        std::cout << "image > " << image.rows << " x " << image.cols << " x " << image.channels() << std::endl;
     //   std::cout <<  image.data << std::endl;
    
        /* get graph info */
        displayGraphInfo();
    
        TF_Graph* graph = tf_utils::LoadGraph(MODEL_FILENAME);
        if (graph == nullptr) {
            std::cout << "Can't load graph" << std::endl;
            return 1;
        }
    
        /* prepare input tensor */
        std::vector<TF_Output> inputs;
        TF_Output input_op = { TF_GraphOperationByName(graph, LAYERNAME_INPUT), 0 };
        if (input_op.oper == nullptr) {
            std::cout << "Can't init input_op" << std::endl;
            return 2;
        }
        inputs.push_back(input_op);
    
        const std::vector<std::int64_t> input_dims = { IMAGE_BATCH, IMAGE_SIZE, IMAGE_SIZE, IMAGE_CH };      // こことデータ次元あっていないと例外がスローされる
        const std::vector<std::int64_t> output_dims = {  1, 6 };
    
        std::vector<std::vector<float>> input_vals(IMAGE_BATCH);
        for (int b = 0; b < IMAGE_BATCH; b++)
        {
            input_vals[b].reserve(IMAGE_SIZE * IMAGE_SIZE * IMAGE_CH);
            std::cout << "OK" << std::endl;
            for (int r = 0; r < image.rows; r++)
            {
                input_vals[b].insert(input_vals[b].end(), image.ptr<float>(r), image.ptr<float>(r) + IMAGE_CH);
            }
        }
    
        std::cout << "OK)" << std::endl;
        std::cout << "input_vals (size)" << input_vals.size() << std::endl;
    
        for (int i = 0; i < 20; i++)
        {
            std::cout << i << " > " << input_vals[0][i] << " , ";
    
        }
    
        std::vector<TF_Tensor*> input_values;
        TF_Tensor* input_tensor = tf_utils::CreateTensor(TF_FLOAT,
            input_dims.data(), input_dims.size(),
            image.data, image.rows *image.cols*image.channels()  * sizeof(float));
        input_values.push_back(input_tensor);
    
        std::cout << "------------------------------------------------------" << std::endl;
        std::cout << "type of tensor element > " << TF_TensorType(input_tensor) << std::endl;
        std::cout << "number of Dimensions   > " << TF_NumDims(input_tensor) << std::endl;
        for (int i = 0; i < TF_NumDims(input_tensor); i++)
        {
            std::cout << "   dimension "<< i << "> " << TF_Dim(input_tensor,i) << std::endl;
        }
        std::cout << "size of type           > " << TF_TensorByteSize(input_tensor) << std::endl;
        std::cout << "pointer                > " << TF_TensorData(input_tensor) << std::endl;
        std::cout << "No of element          > " << TF_TensorElementCount(input_tensor) << std::endl;
        std::cout << "input_values.size()    > " << input_values.size() << std::endl;
        std::cout << "------------------------------------------------------" << std::endl;
    
    
        /* prepare output tensor */
        std::vector<TF_Output> outputs;
        TF_Output out_op = { TF_GraphOperationByName(graph, LAYERNAME_OUTPUT), 0 };
        if (out_op.oper == nullptr) {
            std::cout << "Can't init out_op" << std::endl;
            return 3;
        }
        outputs.push_back(out_op);
    
        std::vector<TF_Tensor*> output_values(outputs.size(), nullptr);
        TF_Tensor* output_tensor = TF_AllocateTensor(TF_FLOAT, output_dims.data(), output_dims.size(), 6 * sizeof(float));
        output_values.push_back(output_tensor);
    
        /* prepare session */
        TF_Status* status = TF_NewStatus();
        TF_SessionOptions* options = TF_NewSessionOptions();
        TF_Session* sess = TF_NewSession(graph, options, status);
        TF_DeleteSessionOptions(options);
    
        if (TF_GetCode(status) != TF_OK) {
            TF_DeleteStatus(status);
            return 4;
        }
    
        /* run session */
        TF_SessionRun(sess,
            nullptr, // Run options.
            &inputs[0], &input_values[0], inputs.size(), // Input tensors, input tensor values, number of inputs.
            &outputs[0], &output_values[0], outputs.size(), // Output tensors, output tensor values, number of outputs.
            nullptr, 0, // Target operations, number of targets.
            nullptr, // Run metadata.
            status // Output status.
        );
    
        if (TF_GetCode(status) != TF_OK) {
            std::cout << "Error run session (status=" << TF_GetCode(status) ;
            TF_DeleteStatus(status);
            return 5;
        }
    
        TF_CloseSession(sess, status);
        if (TF_GetCode(status) != TF_OK) {
            std::cout << "Error close session";
            TF_DeleteStatus(status);
            return 6;
        }
    
        TF_DeleteSession(sess, status);
        if (TF_GetCode(status) != TF_OK) {
            std::cout << "Error delete session";
            TF_DeleteStatus(status);
            return 7;
        }
    
        // Assign the values from the output tensor to a variable and iterate over them
        float* out_vals = static_cast<float*>(TF_TensorData(output_values[0]));
        for (int i = 0; i < 6; ++i)
        {
            std::cout << "Output values info: " << *out_vals++ << "\n";
        }
    
        TF_DeleteTensor(input_tensor);
        TF_DeleteTensor(output_tensor);
        TF_DeleteGraph(graph);
        TF_DeleteStatus(status);
    
        cv::waitKey(0);
        return 0;
    }
    
```
CC BY-SA 4.0
2020-12-18T01:33:58.693
72729
2022-10-24T01:04:40.573
2020-12-18T01:54:07.457
3060
43183
question
c tensorflow
Tensorflowのc_api.hにて画像を推論（VGG16のファインチューニング）したいのですが、TF_SessionRunが成功しません。どこを直せばいいでしょうか？
なんとなくできましたので、自己解決にて回答しておきます。

# pbファイルがうまくできていなかった件

* * *

まず、h5 ファイルから pb ファイルの作成が、tensorflownoバージョンで  
一見できてるように見えて使用できないようでした。  
見た目ではわからないので要注意でした。

変換過程で下記バージョンにすると使用可能なpbファイルができました。

# tensorflow 1.15

# keras 2.2.4

別バージョンでトレーニングしたh5ファイルを、上記バージョンにて読み込み→保存  
model.save('changevarsion.h5')

同じ、tensorflow 1.15 環境下にて、pbファイルへ変更。  
\------------------------- google colab 使うと簡単にバージョン変えれるのが便利ですね。

下記でできること確認しました。

```

    #include <stdio.h>
    #include <opencv2/opencv.hpp>
    #include <tensorflow/c/c_api.h>
    #include "tf_utils.hpp"
    
    //#define MODEL_FILENAME  "ep_156_ls_0.1.pb"
    //#define INPUTIMAGEPATH  "Valid_pic/"
    //#define INPUTIMAGENAME  "Valid_pic/ten__146.bmp"
    //#define IMAGE_BATCH     1
    //#define IMAGE_SIZE      224
    //#define IMAGE_CH        3
    //#define LAYERNAME_INPUT  "input_1"
    //#define LAYERNAME_OUTPUT "dense_2/Softmax"
    //#define ELEM_OUT     6
    //#define NUM_DISP_OUTPUT     3
    //#define ZERO_ONE     1
    
    
    // MNIST CNN
    //#define MODEL_FILENAME  "201229_conv_mnist.pb"
    //#define INPUTIMAGEPATH  "/"
    //#define INPUTIMAGENAME  "6.jpg"
    //#define IMAGE_BATCH     1
    //#define IMAGE_SIZE      28
    //#define IMAGE_CH        1
    //#define LAYERNAME_INPUT  "input_1"
    //#define LAYERNAME_OUTPUT "dense/Softmax"
    //#define ELEM_OUT     10
    //#define NUM_DISP_OUTPUT     3
    //#define ZERO_ONE     1
    
    
    // VGG16
    #define MODEL_FILENAME  "201229_conv_VGG16_.pb"
    #define INPUTIMAGEPATH  "/"
    #define INPUTIMAGENAME  "lion-768x512.jpg"
    #define IMAGE_BATCH     1
    #define IMAGE_SIZE      224
    #define IMAGE_CH        3
    #define LAYERNAME_INPUT  "input_2"
    #define LAYERNAME_OUTPUT "predictions/Softmax"
    #define ELEM_OUT     1000
    #define NUM_DISP_OUTPUT     5
    #define ZERO_ONE     0
    
    
    
    static int displayGraphInfo()
    {
        TF_Graph* graph = tf_utils::LoadGraph(MODEL_FILENAME);
        if (graph == nullptr) {
            std::cout << "Can't load graph" << std::endl;
            return 1;
        }
    
        size_t pos = 0;
        TF_Operation* oper;
        printf("--- graph info ---\n");
        while ((oper = TF_GraphNextOperation(graph, &pos)) != nullptr) {
            printf("%s\n", TF_OperationName(oper));
        }
        printf("--- graph info ---\n");
    
        TF_DeleteGraph(graph);
        return 0;
    }
    
    int main()
    {
        printf("Hello from TensorFlow C library version %s\n", TF_Version());
    
        /* read input image data */
        cv::Mat image = cv::imread(INPUTIMAGENAME);
        cv::imshow("InputImage", image);
    
        /* convert to 224 x 224 RGB image (normalized: 0 ~ 1.0) */
        cv::cvtColor(image, image, cv::COLOR_BGR2RGB);
        if (MODEL_FILENAME == "201229_conv_mnist.pb") { cv::cvtColor(image, image, cv::COLOR_RGB2GRAY); }
        cv::resize(image, image, cv::Size(IMAGE_SIZE, IMAGE_SIZE));
        if (MODEL_FILENAME == "201229_conv_mnist.pb") { image = ~image; }
        cv::imshow("InputImage for CNN", image);
        if (ZERO_ONE == 1) { image.convertTo(image, CV_32FC1, 1.0 / 255); }
        if (ZERO_ONE == 0) { image.convertTo(image, CV_32FC1, 1.0); }
    
        std::cout << "image > " << image.rows << " x " << image.cols << " x " << image.channels() << std::endl;
    //    std::cout << cv::format(image, cv::Formatter::FMT_NUMPY) << std::endl;
    //   std::cout <<  image.data << std::endl;
    
    
    
        /* get graph info */
        displayGraphInfo();
    
        TF_Graph* graph = tf_utils::LoadGraph(MODEL_FILENAME);
        if (graph == nullptr) {
            std::cout << "Can't load graph" << std::endl;
            return 1;
        }
    
        /* prepare input tensor */
        std::vector<TF_Output> inputs;
        TF_Output input_op = { TF_GraphOperationByName(graph, LAYERNAME_INPUT), 0 };
        if (input_op.oper == nullptr) {
            std::cout << "Can't init input_op" << std::endl;
            return 2;
        }
        inputs.push_back(input_op);
    
        const std::vector<std::int64_t> input_dims = { IMAGE_BATCH, IMAGE_SIZE, IMAGE_SIZE, IMAGE_CH };      // こことデータ次元あっていないと例外がスローされる
        const std::vector<std::int64_t> output_dims = {  1, ELEM_OUT };
    
        std::vector<float> input_vals;
        if (ZERO_ONE == 0) { std::vector<int> input_vals; }
    
        input_vals.reserve(IMAGE_SIZE * IMAGE_SIZE * IMAGE_CH);
    //    for (int i = 0; i < IMAGE_SIZE * IMAGE_SIZE * IMAGE_CH; ++i) {
    //        input_vals.insert(input_vals.end() , 0.5);
    //    }
    
    //    image.reshape(0, 1).copyTo(input_vals); // Mat to vector
    
        for (int i = 0; i < IMAGE_SIZE; ++i) {
            input_vals.insert(input_vals.end(), image.ptr<float>(i),  image.ptr<float>(i) + IMAGE_CH  * IMAGE_SIZE );
        }
    
    
    //    image = image.reshape(0, 1);
    //   image.copyTo(input_vals);
    //    for (int b = 0; b < IMAGE_BATCH; b++)
    //   {
    //        input_vals[b].reserve(IMAGE_SIZE * IMAGE_SIZE * IMAGE_CH);
    //        std::cout << "OK" << std::endl;
    //        for (int r = 0; r < image.rows; r++)
    //        {
    //            input_vals[b].insert(input_vals[b].end(), image.ptr<float>(r), image.ptr<float>(r) + IMAGE_CH);
    //        }
    //    }
    
        std::cout << "OK)" << std::endl;
        std::cout << "input_vals (size)" << input_vals.size() << std::endl;
    
        for (int i = 0; i < 10; i++)
        {
            std::cout << i << " > " << input_vals.at(i) << " , ";
    
        }
        std::cout << "---" << std::endl;
        std::cout << "Min. " << *std::min_element(input_vals.begin(), input_vals.end());
        std::cout << "  Max. " << *std::max_element(input_vals.begin(), input_vals.end()) << std::endl;
    
    
        std::vector<TF_Tensor*> input_values;
        TF_Tensor* input_tensor = tf_utils::CreateTensor(TF_FLOAT,
            input_dims.data(), input_dims.size(),
            input_vals.data(), image.rows *image.cols*image.channels()  * sizeof(float));
    
        input_values.push_back(input_tensor);
    
        std::cout << "------------------------------------------------------" << std::endl;
        std::cout << "type of tensor element > " << TF_TensorType(input_tensor) << std::endl;
        std::cout << "number of Dimensions   > " << TF_NumDims(input_tensor) << std::endl;
        for (int i = 0; i < TF_NumDims(input_tensor); i++)
        {
            std::cout << "   dimension "<< i << "> " << TF_Dim(input_tensor,i) << std::endl;
        }
        std::cout << "size of type           > " << TF_TensorByteSize(input_tensor) << std::endl;
        std::cout << "pointer                > " << TF_TensorData(input_tensor) << std::endl;
        std::cout << "No of element          > " << TF_TensorElementCount(input_tensor) << std::endl;
        std::cout << "input_values.size()    > " << input_values.size() << std::endl;
        std::cout << "------------------------------------------------------" << std::endl;
        std::cout << input_tensor << std::endl;
    
        // Optionally, you can check that your input_op and input tensors are correct 
        // by using some of the functions provided by the C API. 
        std::cout << "Input op info(OperationNumInputs): " << TF_OperationNumInputs(TF_GraphOperationByName(graph, LAYERNAME_INPUT)) << "\n";
        std::cout << "Input op info(OperationNumOutputs): " << TF_OperationNumOutputs(TF_GraphOperationByName(graph, LAYERNAME_INPUT)) << "\n";
    
    
        /* prepare output tensor */
        std::vector<TF_Output> outputs;
        TF_Output out_op = { TF_GraphOperationByName(graph, LAYERNAME_OUTPUT), 0 };
        if (out_op.oper == nullptr) {
            std::cout << "Can't init out_op" << std::endl;
            return 3;
        }
        outputs.push_back(out_op);
    
        std::cout << "TFoutput: " << TF_OperationOutputNumConsumers(out_op) << "\n";
        std::cout << "Output op info: " << TF_OperationNumOutputs(TF_GraphOperationByName(graph, LAYERNAME_OUTPUT)) << "\n";
    
        std::vector<TF_Tensor*> output_values(outputs.size(), nullptr);
        TF_Tensor* output_tensor = TF_AllocateTensor(TF_FLOAT, output_dims.data(), output_dims.size(), ELEM_OUT * sizeof(float));
        output_values.push_back(output_tensor);
    
        // As with inputs, check the values for the output operation and output tensor 
        std::cout << "Output: " << TF_OperationName(TF_GraphOperationByName(graph, LAYERNAME_OUTPUT)) << "\n";
        std::cout << "Output: " << TF_OperationOpType(TF_GraphOperationByName(graph, LAYERNAME_OUTPUT)) << "\n";
        std::cout << "Output: " << TF_OperationDevice(TF_GraphOperationByName(graph, LAYERNAME_OUTPUT)) << "\n";
        std::cout << "Output: " << TF_OperationNumOutputs(TF_GraphOperationByName(graph, LAYERNAME_OUTPUT)) << "\n";
        std::cout << "Output info(NUM_DIMS): " << TF_NumDims(output_tensor) << "\n";
        std::cout << "Output info(0): " << TF_Dim(output_tensor, 0) << "\n";
        std::cout << "Output info(1): " << TF_Dim(output_tensor, 1) << "\n";
    
        std::cout << "inputs size            > " << inputs.size() << std::endl;
        std::cout << "outputs size           > " << outputs.size() << std::endl;
    
    
        /* prepare session */
        TF_Status* status = TF_NewStatus();
        TF_SessionOptions* options = TF_NewSessionOptions();
        TF_Session* sess = TF_NewSession(graph, options, status);
        TF_DeleteSessionOptions(options);
    
        if (TF_GetCode(status) != TF_OK) {
            TF_DeleteStatus(status);
            return 4;
        }
    
    
    
        /* run session */
        TF_SessionRun(sess,
            nullptr, // Run options.
            &inputs[0], &input_values[0], inputs.size(), // Input tensors, input tensor values, number of inputs.
            &outputs[0], &output_values[0], outputs.size(), // Output tensors, output tensor values, number of outputs.
            nullptr, 0, // Target operations, number of targets.
            nullptr, // Run metadata.
            status // Output status.
        );
    
        if (TF_GetCode(status) != TF_OK) {
            std::cout << "Error run session (status=" << TF_GetCode(status) ;
            TF_DeleteStatus(status);
            return 5;
        }
    
        TF_CloseSession(sess, status);
        if (TF_GetCode(status) != TF_OK) {
            std::cout << "Error close session";
            TF_DeleteStatus(status);
            return 6;
        }
    
        TF_DeleteSession(sess, status);
        if (TF_GetCode(status) != TF_OK) {
            std::cout << "Error delete session";
            TF_DeleteStatus(status);
            return 7;
        }
    
        // Assign the values from the output tensor to a variable and iterate over them
        std::vector<int> prediction_index(NUM_DISP_OUTPUT+1 , 0) ;
        std::vector<float> prediction_value(NUM_DISP_OUTPUT+1 , 0) ;
    
        float* out_vals = static_cast<float*>(TF_TensorData(output_values[0]));
        for (int i = 0; i < ELEM_OUT; ++i)
        {
            for (int j = 0; j < NUM_DISP_OUTPUT; ++j)
            {
                if (*out_vals > prediction_value[NUM_DISP_OUTPUT - j]) 
                {
                    prediction_value.insert(prediction_value.begin() + (NUM_DISP_OUTPUT - j), *out_vals);
                    prediction_index.insert(prediction_index.begin() + (NUM_DISP_OUTPUT - j), i);
                }
    
            }
            std::cout << i << " Output values info: " << *out_vals++ << "\n";
        }
    
        std::cout << std::endl;
        std::cout << std::endl;
    
        for (int j = 0; j < NUM_DISP_OUTPUT; ++j)
        {
            std::cout << j << " : " << prediction_index.at(j) << " : " << prediction_value.at(j) << std::endl;
    
        }
    
    
    
        TF_DeleteTensor(input_tensor);
        TF_DeleteTensor(output_tensor);
        TF_DeleteGraph(graph);
        TF_DeleteStatus(status);
    
        cv::waitKey(0);
        return 0;
    }
    
```
CC BY-SA 4.0
2021-01-05T03:44:26.790
73086
2021-01-05T03:44:26.790
43183
72729
answer