有没有关于如何生成保存经过训练的Tensorflow图的protobuf文件的例子

我正在看Google如何在Android上部署和使用预训练的Tensorflowgraphics(模型):

https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android

此示例在以下位置使用.pb文件: [这是到自动下载的文件的链接 ] https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip

该示例显示了如何将.pb文件加载到Tensorflow会话并使用它来执行分类,但是没有(?)提及如何在graphics被训练后(例如在Python中)生成这样的.pb文件。

有没有关于如何做的例子?

编辑:作为TensorFlow存储库的一部分的freeze_graph.py脚本现在用作从现有的TensorFlow GraphDef和保存的检查点生成代表“冻结”训练模型的协议缓冲区的工具。 它使用如下所述的相同步骤,但使用起来更容易。


目前这个过程没有很好的文档logging(并且需要细化),但是大致的步骤如下:

  1. build立和训练您的模型作为一个tf.Graph称为g_1
  2. 获取每个variables的最终值并将它们存储为numpy数组(使用Session.run() )。
  3. 在一个名为g_2 的新的tf.Graph ,使用在步骤2中获取的相应numpy数组的值为每个variables创buildtf.constant()张量。
  4. 使用tf.import_graph_def()g_1节点复制到g_2 ,并使用input_map参数将input_map每个variablesreplace为步骤3中创build的相应tf.constant()张量。您可能还想使用input_map来指定一个新的input张量(例如,用tf.placeholder()replaceinputpipe道 )。 使用return_elements参数指定预测输出张量的名称。

  5. 调用g_2.as_graph_def()来获得graphics的协议缓冲表示。

注意:生成的图将在图中有额外的节点用于训练,尽pipe它不是公共API的一部分,但您可能希望使用内部graph_util.extract_sub_graph()函数从图中graph_util.extract_sub_graph()这些节点。

另外我的以前的答案使用freeze_graph() ,这是只有当你把它称为一个脚本是好的,有一个非常好的function,将为你做所有繁重的工作,适合从你的正常模型训练代码中调用。

convert_variables_to_constants()做两件事:

  • 它通过用常量replacevariables来冻结权重
  • 它删除与前馈预测无关的节点

假设sess是你的tf.Session()"output"是你的预测节点的名字,下面的代码会将你的最小graphics序列化成文本和二进制protobuf。


 from tensorflow.python.framework.graph_util import convert_variables_to_constants minimal_graph = convert_variables_to_constants(sess, sess.graph_def, ["output"]) tf.train.write_graph(minimal_graph, '.', 'minimal_graph.proto', as_text=False) tf.train.write_graph(minimal_graph, '.', 'minimal_graph.txt', as_text=True) 

我无法弄清楚如何实现由mrry描述的方法。 但在这里,我是如何解决它的。 我不确定这是否是解决问题的最好方法,但至less可以解决这个问题。

由于write_graph也可以存储常量的值,所以在用write_graph函数写图之前,我将下面的代码添加到了python中:

 for v in tf.trainable_variables(): vc = tf.constant(v.eval()) tf.assign(v, vc, name="assign_variables") 

这创build了常量,它们在被训练之后存储variables的值,然后创build张量“ assign_variables ”来将它们赋值给variables。 现在,当你调用write_graph的时候,它会把variables的值以常量的forms存储在文件中。

剩余的部分是在c代码中调用这些张量“ assign_variables ”,以确保您的variables被分配了存储在文件中的常量值。 这是一个办法:

  Status status = NewSession(SessionOptions(), &session); std::vector<tensorflow::Tensor> outputs; char name[100]; for(int i = 0;status.ok(); i++) { if (i==0) sprintf(name, "assign_variables"); else sprintf(name, "assign_variables_%d", i); status = session->Run({}, {name}, {}, &outputs); } 

这是另一个@ Mostafa的答案。 运行tf.assign操作的更tf.assign是将它们存储在tf.group 。 这是我的Python代码:

  ops = [] for v in tf.trainable_variables(): vc = tf.constant(v.eval()) ops.append(tf.assign(v, vc)); tf.group(*ops, name="assign_trained_variables") 

而在C ++中:

  std::vector<tensorflow::Tensor> tmp; status = session.Run({}, {}, { "assign_trained_variables" }, &tmp); if (!status.ok()) { // Handle error } 

这样你只有一个命名操作在C ++端运行,所以你不必乱七八糟的迭代节点。

刚刚发现这个post,这是非常有用的谢谢! 我也用@ Mostafa的方法,虽然我的C ++代码有点不同:

  std::vector<string> names; int node_count = graph.node_size(); cout << node_count << " nodes in graph" << endl; // iterate all nodes for(int i=0; i<node_count; i++) { auto n = graph.node(i); cout << i << ":" << n.name() << endl; // if name contains "var_hack", add to vector if(n.name().find("var_hack") != std::string::npos) { names.push_back(n.name()); cout << "......bang" << endl; } } session.Run({}, names, {}, &outputs); 

NB我在python中使用“var_hack”作为我的variables名称

我在Tensorflow代码库中find了一个freeze_graph()函数,这可能会有帮助。 根据我的理解,在序列化GraphDef之前用常量交换variables,所以当你从C ++中加载这个图时,它没有需要设置的variables,你可以直接使用它来进行预测。

还有一个testing和指南中的一些说明。

这似乎是这里最干净的select。