首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >组合图:是否有一个TensorFlow import_graph_def等价于C++?

组合图:是否有一个TensorFlow import_graph_def等价于C++?
EN

Stack Overflow用户
提问于 2018-03-26 11:22:59
回答 2查看 1.9K关注 0票数 4

我需要用自定义输入和输出层扩展导出的模型。我发现这是很容易做到的:

代码语言:javascript
复制
with tf.Graph().as_default() as g1: # actual model
    in1 = tf.placeholder(tf.float32,name="input")
    ou1 = tf.add(in1,2.0,name="output")
with tf.Graph().as_default() as g2: # model for the new output layer
    in2 = tf.placeholder(tf.float32,name="input")
    ou2 = tf.add(in2,2.0,name="output")

gdef_1 = g1.as_graph_def()
gdef_2 = g2.as_graph_def()

with tf.Graph().as_default() as g_combined: #merge together
    x = tf.placeholder(tf.float32, name="actual_input") # the new input layer

    # Import gdef_1, which performs f(x).
    # "input:0" and "output:0" are the names of tensors in gdef_1.
    y, = tf.import_graph_def(gdef_1, input_map={"input:0": x},
                             return_elements=["output:0"])

    # Import gdef_2, which performs g(y)
    z, = tf.import_graph_def(gdef_2, input_map={"input:0": y},
                             return_elements=["output:0"])

sess = tf.Session(graph=g_combined)

print "result is: ", sess.run(z, {"actual_input:0":5}) #result is: 9

这个很好用。

但是,我需要提供一个指针作为网络输入,而不是传递任意形状的数据集。问题是,在python (定义和传递指针)中,我想不出有什么解决方案,而且在用C++ Api开发网络时,我找不到与tf.import_graph_def函数相当的解决方案。

这在C++中有不同的名称,还是有其他方法在C++中合并两个图/模型?

谢谢你的建议

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-03-26 12:07:37

这并不像在Python中那么容易。

您可以使用以下内容加载GraphDef

代码语言:javascript
复制
#include <string>
#include <tensorflow/core/framework/graph.pb.h>
#include <tensorflow/core/platform/env.h>

tensorflow::GraphDef graph;
std::string graphFileName = "...";
auto status = tensorflow::ReadBinaryProto(
    tensorflow::Env::Default(), graphFileName, &graph);
if (!status.ok()) { /* Error... */ }

然后您可以使用它创建一个会话:

代码语言:javascript
复制
#include <tensorflow/core/public/session.h>

tensorflow::Session *newSession;
auto status = tensorflow::NewSession(tensorflow::SessionOptions(), &newSession);
if (!status.ok()) { /* Error... */ }
status = session->Create(graph);
if (!status.ok()) { /* Error... */ }

或扩展现有图:

代码语言:javascript
复制
status = session->Extend(graph);
if (!status.ok()) { /* Error... */ }

这样,您就可以将多个GraphDef放在同一个图中。但是,没有额外的工具来提取特定的节点,或者避免名称冲突--您必须自己查找节点,并且必须确保GraphDefs没有冲突的op名称。例如,我使用这个函数查找所有具有匹配给定正则表达式的名称的节点,并按名称排序:

代码语言:javascript
复制
#include <vector>
#include <regex>
#include <tensorflow/core/framework/node_def.pb.h>

std::vector<const tensorflow::NodeDef *> GetNodes(const tensorflow::GraphDef &graph, const std::regex &regex)
{
    std::vector<const tensorflow::NodeDef *> nodes;
    for (const auto &node : graph.node())
    {
        if (std::regex_match(node.name(), regex))
        {
            nodes.push_back(&node);
        }
    }
    std::sort(nodes.begin(), nodes.end(),
              [](const tensorflow::NodeDef *lhs, const tensorflow::NodeDef *rhs)
              {
                  return lhs->name() < rhs->name();
              });
    return nodes;
}
票数 2
EN

Stack Overflow用户

发布于 2020-05-28 18:13:51

这在C++中可以通过直接操作要组合的两个图的GraphDefs中的NodeDefs来实现。基本算法是定义两个GraphDefs,使用占位符作为第二个GraphDef的输入,并将它们重定向到第一个GraphDef的输出。这类似于通过将第二电路的输入连接到第一电路的输出来串联两个电路。

首先,定义了示例GraphDefs,以及用于观察GraphDefs内部的实用程序。需要注意的是,来自两个GraphDefs的所有节点都必须有唯一的名称。

代码语言:javascript
复制
Status Panel::SampleFirst(GraphDef *graph_def) 
{
    Scope root = Scope::NewRootScope();
    Placeholder p1(root.WithOpName("p1"), DT_INT32);
    Placeholder p2(root.WithOpName("p2"), DT_INT32);
    Add add(root.WithOpName("add"), p1, p2);
    return root.ToGraphDef(graph_def);
}

Status Panel::SampleSecond(GraphDef *graph_def)
{
    Scope root = Scope::NewRootScope();
    Placeholder q1(root.WithOpName("q1"), DT_INT32);
    Placeholder q2(root.WithOpName("q2"), DT_INT32);
    Add sum(root.WithOpName("sum"), q1, q2);
    Multiply multiply(root.WithOpName("multiply"), sum, 4);
    return root.ToGraphDef(graph_def);
}

void Panel::ShowGraphDef(GraphDef &graph_def)
{
    for (int i = 0; i < graph_def.node_size(); i++) {
        NodeDef node_def = graph_def.node(i);
        cout << "NodeDef name is " << node_def.name() << endl;
        cout << "NodeDef op is " << node_def.op() << endl;
        for (const string& input : node_def.input()) {
            cout << "\t input: " << input << endl;
        }
    }
}

现在,创建两个GraphDefs,并将第二个GraphDef的输入连接到第一个GraphDef的输出。这是通过迭代节点和标识第一个操作节点(其输入是占位符)并将这些输入重定向到第一个GraphDef的输出来实现的。然后将该节点添加到第一个GraphDef以及所有后续节点中。结果是第二个GraphDef附加的第一个GraphDef。

代码语言:javascript
复制
Status Panel::Append(vector<Tensor> *outputs)
{
    GraphDef graph_def_first;
    GraphDef graph_def_second;
    TF_RETURN_IF_ERROR(SampleFirst(&graph_def_first));
    TF_RETURN_IF_ERROR(SampleSecond(&graph_def_second));

    for (int i = 0; i < graph_def_second.node_size(); i++) {
        NodeDef node_def = graph_def_second.node(i);
        if (node_def.name() == "sum") {
            node_def.set_input(0, "p1");
            node_def.set_input(1, "add");
        }
        *graph_def_first.add_node() = node_def;
    }

    ShowGraphDef(graph_def_first);

    unique_ptr<Session> session(NewSession(SessionOptions()));
    TF_RETURN_IF_ERROR(session->Create(graph_def_first));

    Tensor t1(2);
    Tensor t2(3);
    vector<pair<string, Tensor>> inputs = {{"p1", t1}, {"p2", t2}};

    TF_RETURN_IF_ERROR(session->Run(inputs, {"multiply"}, {}, outputs));

    return Status::OK();
}

这个特殊的图将接受两个输入,2和3,并将它们相加在一起。然后,该(5)的和将再次添加到第一个输入(2)中,然后乘以4以获得28的结果。((2+3) + 2) *4= 28。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49490262

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档