在 C/C++ 中使用 TensorFlow 预训练好的模型—— 直接调用 C++ 接口实现

栏目: C++ · 发布时间: 7年前

内容简介:现在的深度学习框架一般都是基于 Python 来实现,构建、训练、保存和调用模型都可以很容易地在 Python 下完成。但有时候,我们在实际应用这些模型的时候可能需要在其他编程语言下进行,本文将通过直接调用 TensorFlow 的 C/C++ 接口来导入 TensorFlow 预训练好的模型。获取更多精彩,请关注「seniusen」!

现在的深度学习框架一般都是基于 Python 来实现,构建、训练、保存和调用模型都可以很容易地在 Python 下完成。但有时候,我们在实际应用这些模型的时候可能需要在其他编程语言下进行,本文将通过直接调用 TensorFlow 的 C/C++ 接口来导入 TensorFlow 预训练好的模型。

2. 导入预定义的图和训练好的参数值

// set up your input paths
    const string pathToGraph = "/home/senius/python/c_python/test/model-10.meta";
    const string checkpointPath = "/home/senius/python/c_python/test/model-10";

    auto session = NewSession(SessionOptions()); // 创建会话
    if (session == nullptr)
    {
        throw runtime_error("Could not create Tensorflow session.");
    }

    Status status;

    // Read in the protobuf graph we exported
    MetaGraphDef graph_def;
    status = ReadBinaryProto(Env::Default(), pathToGraph, &graph_def);  // 导入图模型
    if (!status.ok())
    {
        throw runtime_error("Error reading graph definition from " + pathToGraph + ": " + status.ToString());
    }

    // Add the graph to the session
    status = session->Create(graph_def.graph_def());  // 将图模型加入到会话中
    if (!status.ok())
    {
        throw runtime_error("Error creating graph: " + status.ToString());
    }

    // Read weights from the saved checkpoint
    Tensor checkpointPathTensor(DT_STRING, TensorShape());
    checkpointPathTensor.scalar<std::string>()() = checkpointPath; // 读取预训练好的权重
    status = session->Run({{graph_def.saver_def().filename_tensor_name(), checkpointPathTensor},}, {},
                          {graph_def.saver_def().restore_op_name()}, nullptr);
    if (!status.ok())
    {
        throw runtime_error("Error loading checkpoint from " + checkpointPath + ": " + status.ToString());
    }
复制代码
在 C/C++ 中使用 TensorFlow 预训练好的模型—— 直接调用 C++ 接口实现

3. 准备测试数据

const string filename = "/home/senius/python/c_python/test/04t30t00.npy";

    //Read TXT data to array
    float Array[1681*41];
    ifstream is(filename);
    for (int i = 0; i < 1681*41; i++){
        is >> Array[i];
    }
    is.close();

    tensorflow::Tensor input_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({1, 41, 41, 41, 1}));
    auto input_tensor_mapped = input_tensor.tensor<float, 5>();

    float *pdata = Array;

    // copying the data into the corresponding tensor
    for (int x = 0; x < 41; ++x)//depth
    {
        for (int y = 0; y < 41; ++y) {
            for (int z = 0; z < 41; ++z) {
                const float *source_value = pdata + x * 1681 + y * 41 + z;
                input_tensor_mapped(0, x, y, z, 0) = *source_value;
            }
        }
    }
复制代码
  • 本例中输入数据是一个 [None, 41, 41, 41, 1] 的张量,我们需要先从 TXT 文件中读出测试数据,然后正确地填充到张量中去。

4. 前向传播得到预测值

std::vector<tensorflow::Tensor> finalOutput;
    std::string InputName = "X"; // Your input placeholder's name
    std::string OutputName = "sigmoid"; // Your output tensor's name
    vector<std::pair<string, Tensor> > inputs;
    inputs.push_back(std::make_pair(InputName, input_tensor));

    // Fill input tensor with your input data
    session->Run(inputs, {OutputName}, {}, &finalOutput);

    auto output_y = finalOutput[0].scalar<float>();
    std::cout << output_y() << "\n";
复制代码
  • 通过给定输入和输出张量的名字,我们可以将测试数据传入到模型中,然后进行前向传播得到预测值。

5. 一些问题

  • 本模型是在 TensorFlow 1.4 下训练的,然后编译 TensorFlow 1.4 的 C++ 接口可以正常调用模型,但若是想调用更高版本训练好的模型,则会报错,据出错信息猜测可能是高版本的 TensorFlow 中添加了一些低版本没有的函数,所以不能正常运行。
  • 若是编译高版本的 TensorFlow ,比如最新的 TensorFlow 1.11 的 C++ 接口,则无论是调用旧版本训练的模型还是新版本训练的模型都不能正常运行。出错信息如下:Error loading checkpoint from /media/lab/data/yongsen/Tensorflow_test/test/model-40: Invalid argument: Session was not created with a graph before Run()!,网上暂时也查不到解决办法,姑且先放在这里。

6. 完整代码

#include </home/senius/tensorflow-r1.4/bazel-genfiles/tensorflow/cc/ops/io_ops.h>
#include </home/senius/tensorflow-r1.4/bazel-genfiles/tensorflow/cc/ops/parsing_ops.h>
#include </home/senius/tensorflow-r1.4/bazel-genfiles/tensorflow/cc/ops/array_ops.h>
#include </home/senius/tensorflow-r1.4/bazel-genfiles/tensorflow/cc/ops/math_ops.h>
#include </home/senius/tensorflow-r1.4/bazel-genfiles/tensorflow/cc/ops/data_flow_ops.h>


#include <tensorflow/core/public/session.h>
#include <tensorflow/core/protobuf/meta_graph.pb.h>
#include <fstream>

using namespace std;
using namespace tensorflow;
using namespace tensorflow::ops;

int main()
{
    // set up your input paths
    const string pathToGraph = "/home/senius/python/c_python/test/model-10.meta";
    const string checkpointPath = "/home/senius/python/c_python/test/model-10";

    auto session = NewSession(SessionOptions());
    if (session == nullptr)
    {
        throw runtime_error("Could not create Tensorflow session.");
    }

    Status status;

    // Read in the protobuf graph we exported
    MetaGraphDef graph_def;
    status = ReadBinaryProto(Env::Default(), pathToGraph, &graph_def);
    if (!status.ok())
    {
        throw runtime_error("Error reading graph definition from " + pathToGraph + ": " + status.ToString());
    }

    // Add the graph to the session
    status = session->Create(graph_def.graph_def());
    if (!status.ok())
    {
        throw runtime_error("Error creating graph: " + status.ToString());
    }

    // Read weights from the saved checkpoint
    Tensor checkpointPathTensor(DT_STRING, TensorShape());
    checkpointPathTensor.scalar<std::string>()() = checkpointPath;
    status = session->Run({{graph_def.saver_def().filename_tensor_name(), checkpointPathTensor},}, {},
                          {graph_def.saver_def().restore_op_name()}, nullptr);
    if (!status.ok())
    {
        throw runtime_error("Error loading checkpoint from " + checkpointPath + ": " + status.ToString());
    }

    cout << 1 << endl;

    const string filename = "/home/senius/python/c_python/test/04t30t00.npy";

    //Read TXT data to array
    float Array[1681*41];
    ifstream is(filename);
    for (int i = 0; i < 1681*41; i++){
        is >> Array[i];
    }
    is.close();

    tensorflow::Tensor input_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({1, 41, 41, 41, 1}));
    auto input_tensor_mapped = input_tensor.tensor<float, 5>();

    float *pdata = Array;

    // copying the data into the corresponding tensor
    for (int x = 0; x < 41; ++x)//depth
    {
        for (int y = 0; y < 41; ++y) {
            for (int z = 0; z < 41; ++z) {
                const float *source_value = pdata + x * 1681 + y * 41 + z;
//                input_tensor_mapped(0, x, y, z, 0) = *source_value;
                input_tensor_mapped(0, x, y, z, 0) = 1;
            }
        }
    }

    std::vector<tensorflow::Tensor> finalOutput;
    std::string InputName = "X"; // Your input placeholder's name
    std::string OutputName = "sigmoid"; // Your output placeholder's name
    vector<std::pair<string, Tensor> > inputs;
    inputs.push_back(std::make_pair(InputName, input_tensor));

    // Fill input tensor with your input data
    session->Run(inputs, {OutputName}, {}, &finalOutput);

    auto output_y = finalOutput[0].scalar<float>();
    std::cout << output_y() << "\n";


    return 0;
}
复制代码
  • Cmakelist 文件如下
cmake_minimum_required(VERSION 3.8)
project(Tensorflow_test)

set(CMAKE_CXX_STANDARD 11)

set(SOURCE_FILES main.cpp)


include_directories(
        /home/senius/tensorflow-r1.4
        /home/senius/tensorflow-r1.4/tensorflow/bazel-genfiles
        /home/senius/tensorflow-r1.4/tensorflow/contrib/makefile/gen/protobuf/include
        /home/senius/tensorflow-r1.4/tensorflow/contrib/makefile/gen/host_obj
        /home/senius/tensorflow-r1.4/tensorflow/contrib/makefile/gen/proto
        /home/senius/tensorflow-r1.4/tensorflow/contrib/makefile/downloads/nsync/public
        /home/senius/tensorflow-r1.4/tensorflow/contrib/makefile/downloads/eigen
        /home/senius/tensorflow-r1.4/bazel-out/local_linux-py3-opt/genfiles
)

add_executable(Tensorflow_test ${SOURCE_FILES})

target_link_libraries(Tensorflow_test
        /home/senius/tensorflow-r1.4/bazel-bin/tensorflow/libtensorflow_cc.so
        /home/senius/tensorflow-r1.4/bazel-bin/tensorflow/libtensorflow_framework.so
        )
复制代码

获取更多精彩,请关注「seniusen」!

在 C/C++ 中使用 TensorFlow 预训练好的模型—— 直接调用 C++ 接口实现

以上所述就是小编给大家介绍的《在 C/C++ 中使用 TensorFlow 预训练好的模型—— 直接调用 C++ 接口实现》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Design and Analysis of Distributed Algorithms (Wiley Series on P

Design and Analysis of Distributed Algorithms (Wiley Series on P

Nicola Santoro / Wiley-Interscience / 2006-10-27 / USD 140.95

This text is based on a simple and fully reactive computational model that allows for intuitive comprehension and logical designs. The principles and techniques presented can be applied to any distrib......一起来看看 《Design and Analysis of Distributed Algorithms (Wiley Series on P》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具