组合图:C 是否有TensorFlow Import_graph_def当量
Combining graphs: is there a TensorFlow import_graph_def equivalent for C++?
我需要使用自定义输入和输出层扩展导出的模型。我发现这可以很容易地完成:
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 中的两个图形/模型?
感谢您的建议
它不像python那样容易。
您可以用类似的东西加载GraphDef
:
#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... */ }
然后您可以使用它来创建一个会话:
#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... */ }
或扩展现有图的图:
status = session->Extend(graph);
if (!status.ok()) { /* Error... */ }
这样,您可以将几个GraphDef
S放入同一图。但是,没有其他设施可以提取特定的节点,也没有避免名称碰撞 - 您必须自己找到节点,并且必须确保GraphDef
S没有冲突的OP名称。例如,我使用此函数查找所有与给定正则表达式匹配的名称的节点,并按名称排序:
#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 ®ex)
{
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;
}
可以通过直接操纵要组合的两个图的graphDefs中的nodedefs来实现这一点。基本算法是定义两个GraphDef,使用占位符将输入到第二个GraphDef,然后将其重定向到第一个GraphDef的输出。这将类似于通过将第二电路的输入连接到第一电路的输出来串联的两个电路。
首先,定义了示例GraphDef,以及观察GraphDefs内部的实用程序。重要的是要注意,两个GraphDefs的所有节点都必须具有唯一的名称。
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;
}
}
}
现在创建了两个GraphDef,第二个GraphDef的输入连接到第一个GraphDef的输出。这是通过在节点上迭代并识别第一个操作节点来完成的,该节点的输入是占位符,并将这些输入重定向到第一个GraphDef的输出。然后将节点添加到第一个GraphDef以及所有后续节点。结果是第二个GraphDef。
附加的第一个GraphDefStatus 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 = 4 = 28。
- Boost Graph Library,修复节点大小
- 在具有全局类型def的类中使用成员函数指针
- 这是 basic.def.odr 部分的缺陷吗?
- 在使用 Clang 编译 DLL 时指定 DEF 文件
- 函数模板签名中忽略的成员类型def 的访问说明符
- 删除unicode def后,无法将QString转换为TCHAR
- C++ 如何在 def 文件中指定命名空间
- 如何在 LLVM 后端的机器级别找到 def-use 链
- Paths.get( "abc/def.jpg" ) 在 C 和 C++ 中获取与操作系统无关的路径的等价物是什么?
- 如何从TBB :: Flow :: Graph中删除/取消消息
- 无法键入 def std::chrono::microseconds 以覆盖其定义以更改其基础类型
- Boost Graph库,depth_first_search未在MSVC中调用finish_edge
- 使用 .def 文件的优缺点
- 如何在Boost Graph库中的Grid_graph的边缘添加自定义属性
- 根据 [basic.def.odr]/2,'A::a[0]' 的潜在结果集为空.为什么它是空的?
- TensorFlow从C 中的Graph Def获得形状
- 在Boost Graph库中选择给定顶点的随机进出邻居的有效方法
- 如何使用Boost Graph库使用循环中的循环设置相同的边缘重量
- Boost Graph库示例不编译
- 访问使用 def 文件导出的静态变量时崩溃