本来是想先写如何在C++上调用X64和X86的tensorflow的,但是写着写着发现,应该先准备一下C++上可用的forzen graph即.pb文件。
对于我这种深度学习的Starter(试着把自己提升这Practitioner)来说,几乎都是直接通过Keras保存model,而出来的格式一般都是.model或者.h5。
在C++上可用的则是.pb,然后发现.pb文件是无法读取里面的layer信息,我想这也是为什么要使用.pb吧!毕竟一个深度学习应用,最值钱最有价值的就是layer的排序以及hyper-parameter了。(注:关于不可读取这点,如果我理解错误了,还请纠正我,十分感谢)
我本来是尝试把.model转换成.pb,先是在x64上测试,正常工作,乐呵呵的继续尝试x86,一直失败,最后自己怀疑起来了是不是x86和x64在使用.pb上是不一样,结果确实如此。我这个从.model转换来的.pb无法在x86上无法使用。(或许有其他方法,但是我没继续深究)。
所以呢,重新训练了一下,现在在model.fit之后增加了:
print("[INFO] saving to model ckpt...")
tag = "the_tga_you_want"
from keras import backend as K
import tensorflow as tf
print(model.output.op.name) #The output is going to be used later
saver = tf.train.Saver()
saver.save(K.get_session(), 'files_holder_ckpt/{}.ckpt'.format(tag))
这样子你就可以保存出来.ckpt的文件,注意这里还会print一个output_node_name的信息,这个要记下来,待会儿转换到.pb的时候是需要的。
[INFO] saving to model ckpt...
dense_6/Softmax #例子
在这个步骤后,你将拥有下面的文件
checkpoint
keras_model.ckpt.data-00000-of-00001
keras_model.ckpt.index
keras_model.ckpt.meta
接下来呢,再把这个.ckpt转换成.pb就行了,这个时候output_nodel_name就可以用上了。
#%% if you wish to know more about this function, please viast the tensorflow.
def freeze_graph(input_checkpoint,output_graph):
'''
:param input_checkpoint: full path to your .ckpt file
:param output_graph: full path to save your .pb file
:return:
'''
#what you get from second step
output_node_names = "dense_3/Softmax"
saver = tf.train.import_meta_graph(input_checkpoint + '.meta', clear_devices=True)
graph = tf.get_default_graph()
input_graph_def = graph.as_graph_def()
with tf.Session() as sess:
saver.restore(sess, input_checkpoint)
output_graph_def = graph_util.convert_variables_to_constants( #
sess=sess,
input_graph_def=input_graph_def,
output_node_names=output_node_names.split(","))
#saving out the model
with tf.gfile.GFile(output_graph, "wb") as f:
f.write(output_graph_def.SerializeToString())
print("%d ops in the final graph." % len(output_graph_def.node))
# for op in graph.get_operations():
# print(op.name, op.values())
tag = "tag"
input_checkpoint='files_holder_ckpt/{}.ckpt'.format(tag) #full path to your .ckpt file
out_pb_path="files_holder_pb/{}.pb".format(tag) #full path to save your .pb file
graph = tf.get_default_graph()
input_graph_def = graph.as_graph_def()
freeze_graph(input_checkpoint,out_pb_path)
这个时候呢,你就拥有了.pb文件了,还没完,既然我们知道了output_node_name,这个时候就需要知道input_node_name。通过以下代码检查:
import tensorflow as tf
gf = tf.GraphDef()
gf.ParseFromString(open('/your/path/to/graphname.pb','rb').read())
[n.name + '=>' + n.op for n in gf.node if n.op in ( 'Softmax','Placeholder')]
输出:
>>> 'input_2=>Placeholder', 'dense_3/Softmax=>Softmax
现在你有用了C++所需要的模型,以及对应的接口信息了,当然你需要准备对应的label.txt文件。
string graph = "pb/frozen_model.pb";
string label = "pb/forzen_model_label.txt";
string input_layer = "input_2:0";
string output_layer = "dense_3/Softmax:0";