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

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

1.环境配置 点此查看 C/C++ 接口的编译

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());
    }

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」!

原文地址:https://www.cnblogs.com/seniusen/p/9756481.html

时间: 2025-01-11 01:12:42

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

【猫狗数据集】使用预训练的resnet18模型

数据集下载地址: 链接:https://pan.baidu.com/s/1l1AnBgkAAEhh0vI5_loWKw提取码:2xq4 创建数据集:https://www.cnblogs.com/xiximayou/p/12398285.html 读取数据集:https://www.cnblogs.com/xiximayou/p/12422827.html 进行训练:https://www.cnblogs.com/xiximayou/p/12448300.html 保存模型并继续进行训练:htt

转载:tensorflow保存训练后的模型

训练完一个模型后,为了以后重复使用,通常我们需要对模型的结果进行保存.如果用Tensorflow去实现神经网络,所要保存的就是神经网络中的各项权重值.建议可以使用Saver类保存和加载模型的结果. 1.使用tf.train.Saver.save()方法保存模型 tf.train.Saver.save(sess, save_path, global_step=None, latest_filename=None, meta_graph_suffix='meta', write_meta_graph

BERT论文翻译:用于语言理解的深度双向Transformer的预训练

Jacob Devlin Ming-Wei Chang Kenton Lee kristina Toutanova Google AI Language {jacobdevlin, mingweichang, kentonl, kristout}@google.com 摘要 本文介绍了一种新的语言表示模型BERT,意为“来自transformer的双向编码器表示”(Bidirectional Encoder Representations from Transformers).与最近的语言表示模

深度双向Transformer预训练【BERT第一作者分享】

目录 NLP中的预训练 语境表示 语境表示相关研究 存在的问题 BERT的解决方案 任务一:Masked LM 任务二:预测下一句 BERT 输入表示 模型结构--Transformer编码器 Transformer vs. LSTM 模型细节 在不同任务上进行微调 GLUE SQuAD 1.1 SQuAD 2.0 SWAG 分析 预训练的影响 方向与训练时间的影响 模型规模的影响 遮罩策略的影响 多语言BERT(机器翻译) 生成训练数据(机器阅读理解) 常见问题 结论 翻译自Jacob Dev

预训练中Word2vec,ELMO,GPT与BERT对比

预训练 先在某个任务(训练集A或者B)进行预先训练,即先在这个任务(训练集A或者B)学习网络参数,然后存起来以备后用.当我们在面临第三个任务时,网络可以采取相同的结构,在较浅的几层,网络参数可以直接加载训练集A或者B训练好的参数,其他高层仍然随机初始化.底层参数有两种方式:frozen,即预训练的参数固定不变,fine-tuning,即根据现在的任务调整预训练的参数. 优势: 1.当前任务数据量少,难以训练更多的网络参数,可以加载预训练的模型,然后根据当前的任务对参数进行fine-tuning,

fine-tuning:预训练中的迁移

什么是fine-tuning? 概述 在实践中,由于数据集不够大,很少有人从头开始训练网络.常见的做法是使用预训练的网络(例如在ImageNet上训练的分类1000类的网络)来重新fine-tuning(也叫微调),或者当做特征提取器. 以下是常见的两类迁移学习场景: 卷积网络当做特征提取器.使用在ImageNet上预训练的网络,去掉最后的全连接层,剩余部分当做特征提取器(例如AlexNet在最后分类器前,是4096维的特征向量).这样提取的特征叫做CNN codes.得到这样的特征后,可以使用

[转] 轻松使用多种预训练卷积网络抽取图像特征

选自GitHub,机器之心整理. 最近 GitHub 有一个非常有意思的项目,它可以使用多种预训练 TensorFLow 模型计算图像特征.对于每一个模型,它们都会输出最后的全连接层,即 AlexNet 的第七个全连接层.VGG_19 的第 8 个全连接层等.这些层级将最终抽取出图像的特征,并能进一步用于图像分类和聚类等.机器之心简要地介绍了该项目,并测试了使用Inception_V1预训练模型抽取图像特征. 项目地址:https://github.com/cameronfabbri/Compu

深度学习(五十五)tensorflow分布式训练

tensorflow分布式训练 博客:http://blog.csdn.net/hjimce 微博:黄锦池-hjimce   qq:1393852684 情况一.单机单卡 单机单卡是最普通的情况,当然也是最简单的,示例代码如下: #coding=utf-8 #单机单卡 #对于单机单卡,可以把参数和计算都定义再gpu上,不过如果参数模型比较大,显存不足等情况,就得放在cpu上 import tensorflow as tf with tf.device('/cpu:0'):#也可以放在gpu上 w

解决tensorflow在训练的时候权重是nan问题

搭建普通的卷积CNN网络. nan表示的是无穷或者是非数值,比如说你在tensorflow中使用一个数除以0,那么得到的结果就是nan. 在一个matrix中,如果其中的值都为nan很有可能是因为采用的cost function不合理导致的. 当使用tensorflow构建一个最简单的神经网络的时候,按照tensorflow官方给出的教程: https://www.tensorflow.org/get_started/mnist/beginners http://wiki.jikexueyuan