首页 文章

Tensorflow在C中导出和运行图形的不同方法

提问于
浏览
24

要将训练有素的网络导入C,您需要导出网络才能执行此操作 . 经过大量搜索并几乎找不到有关它的信息后,我们明确表示我们应该使用freeze_graph()来做到这一点 .

感谢Tensorflow的新0.7版本,他们添加了documentation .

在查看文档之后,我发现几乎没有类似的方法,你能说出 freeze_graph() 和: tf.train.export_meta_graph 之间有什么区别,因为它有类似的参数,但它似乎也可以用于将模型导入C(我只是想猜不同的是,对于使用此方法输出的文件,您只能使用 import_graph_def() 或者其他的东西?)

还有一个关于如何使用 write_graph() 的问题:在文档中 graph_defsess.graph_def 给出,但在 freeze_graph() 中的示例中它是 sess.graph.as_graph_def() . 这两者有什么区别?

这个问题与this issue.有关

谢谢!

2 回答

  • 33

    这是我使用TF 0.12中引入的V2检查点的解决方案 .

    无需将所有变量转换为常量或freeze the graph .

    为了清楚起见,V2检查点在我的目录_2512720中看起来像这样:

    checkpoint  # some information on the name of the files in the checkpoint
    my-model.data-00000-of-00001  # the saved weights
    my-model.index  # probably definition of data layout in the previous file
    my-model.meta  # protobuf of the graph (nodes and topology info)
    

    Python part (saving)

    with tf.Session() as sess:
        tf.train.Saver(tf.trainable_variables()).save(sess, 'models/my-model')
    

    如果使用 tf.trainable_variables() 创建 Saver ,则可以节省一些头痛和存储空间 . 但也许一些更复杂的模型需要保存所有数据,然后将此参数删除到 Saver ,只需确保您创建的图形已创建 Saver after . 给所有变量/图层赋予唯一名称也是非常明智的,否则你可以在different problems中运行 .

    Python part (inference)

    with tf.Session() as sess:
        saver = tf.train.import_meta_graph('models/my-model.meta')
        saver.restore(sess, tf.train.latest_checkpoint('models/'))
        outputTensors = sess.run(outputOps, feed_dict=feedDict)
    

    C++ part (inference)

    请注意, checkpointPath 不是任何现有文件的路径,只是它们的公共前缀 . 如果您错误地将路径放到了 .index 文件中,TF将不会告诉您这是错误的,但是由于未初始化的变量,它会在推理期间死亡 .

    #include <tensorflow/core/public/session.h>
    #include <tensorflow/core/protobuf/meta_graph.pb.h>
    
    using namespace std;
    using namespace tensorflow;
    
    ...
    // set up your input paths
    const string pathToGraph = "models/my-model.meta"
    const string checkpointPath = "models/my-model";
    ...
    
    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());
    }
    
    // and run the inference to your liking
    auto feedDict = ...
    auto outputOps = ...
    std::vector<tensorflow::Tensor> outputTensors;
    status = session->Run(feedDict, outputOps, {}, &outputTensors);
    
  • 17

    对于预测(以及所有其他操作),您可以执行以下操作:

    首先在python中你应该 name 你的变量或操作以供将来使用

    self.init = tf.initialize_variables(tf.all_variables(), name="nInit")
    

    训练之后,如果你已经分配了变量,那么计算得到了所有这些变量并将其作为常量保存到图表中 . (几乎可以使用该冻结工具完成相同的操作,但我通常自己做,请在py和cpp下面检查“name = nWeights”)

    def save(self, filename):
        for variable in tf.trainable_variables():
            tensor = tf.constant(variable.eval())
            tf.assign(variable, tensor, name="nWeights")
    
        tf.train.write_graph(self.sess.graph_def, 'graph/', 'my_graph.pb', as_text=False)
    

    现在去c并加载我们的图并从保存的常量中加载变量:

    void load(std::string my_model) {
            auto load_graph_status =
                    ReadBinaryProto(tensorflow::Env::Default(), my_model, &graph_def);
    
            auto session_status = session->Create(graph_def);
    
            std::vector<tensorflow::Tensor> out;
            std::vector<string> vNames;
    
            int node_count = graph_def.node_size();
            for (int i = 0; i < node_count; i++) {
                auto n = graph_def.node(i);
    
                if (n.name().find("nWeights") != std::string::npos) {
                    vNames.push_back(n.name());
                }
            }
    
            session->Run({}, vNames, {}, &out);
    

    现在你已经加载了所有的神经净重或其他变量 .

    同样,您可以执行其他操作(记住名称?);制作适当大小的输入和输出张量,用数据填充输入张量并运行会话,如下所示:

    auto operationStatus = session->Run(input, {"put_your_operation_here"}, {}, &out);
    

相关问题