Python 如何将 Keras .h5 导出到 tensorflow .pb?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/45466020/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to export Keras .h5 to tensorflow .pb?
提问by Solix
I have fine-tuned inception model with a new dataset and saved it as ".h5" model in Keras. now my goal is to run my model on android Tensorflow which accepts ".pb" extension only. question is that is there any library in Keras or tensorflow to do this conversion? I have seen this post so far : https://blog.keras.io/keras-as-a-simplified-interface-to-tensorflow-tutorial.htmlbut can't figure out yet.
我使用新数据集对初始模型进行了微调,并将其保存为 Keras 中的“.h5”模型。现在我的目标是在仅接受“.pb”扩展名的 android Tensorflow 上运行我的模型。问题是 Keras 或 tensorflow 中是否有任何库可以进行这种转换?到目前为止,我已经看过这篇文章:https: //blog.keras.io/keras-as-a-simplified-interface-to-tensorflow-tutorial.html,但还想不通。
回答by jdehesa
Keras does not include by itself any means to export a TensorFlow graph as a protocol buffers file, but you can do it using regular TensorFlow utilities. Hereis a blog post explaining how to do it using the utility script freeze_graph.py
included in TensorFlow, which is the "typical" way it is done.
Keras 本身不包含任何将 TensorFlow 图导出为协议缓冲区文件的方法,但您可以使用常规的 TensorFlow 实用程序来实现。这是一篇博客文章,解释了如何使用freeze_graph.py
TensorFlow 中包含的实用程序脚本来执行此操作,这是完成此操作的“典型”方式。
However, I personally find a nuisance having to make a checkpoint and then run an external script to obtain a model, and instead prefer to do it from my own Python code, so I use a function like this:
但是,我个人觉得必须创建检查点然后运行外部脚本来获取模型很麻烦,而更喜欢从我自己的 Python 代码中执行此操作,因此我使用了这样的函数:
def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
"""
Freezes the state of a session into a pruned computation graph.
Creates a new computation graph where variable nodes are replaced by
constants taking their current value in the session. The new graph will be
pruned so subgraphs that are not necessary to compute the requested
outputs are removed.
@param session The TensorFlow session to be frozen.
@param keep_var_names A list of variable names that should not be frozen,
or None to freeze all the variables in the graph.
@param output_names Names of the relevant graph outputs.
@param clear_devices Remove the device directives from the graph for better portability.
@return The frozen graph definition.
"""
graph = session.graph
with graph.as_default():
freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
output_names = output_names or []
output_names += [v.op.name for v in tf.global_variables()]
input_graph_def = graph.as_graph_def()
if clear_devices:
for node in input_graph_def.node:
node.device = ""
frozen_graph = tf.graph_util.convert_variables_to_constants(
session, input_graph_def, output_names, freeze_var_names)
return frozen_graph
Which is inspired in the implementation of freeze_graph.py
. The parameters are similar to the script too. session
is the TensorFlow session object. keep_var_names
is only needed if you want to keep some variable not frozen (e.g. for stateful models), so generally not. output_names
is a list with the names of the operations that produce the outputs that you want. clear_devices
just removes any device directives to make the graph more portable. So, for a typical Keras model
with one output, you would do something like:
这是在freeze_graph.py
. 参数也与脚本类似。session
是 TensorFlow 会话对象。keep_var_names
仅当您想保持某些变量不被冻结时才需要(例如对于有状态模型),所以通常不需要。output_names
是一个列表,其中包含产生您想要的输出的操作的名称。clear_devices
只是删除任何设备指令,使图形更便携。因此,对于model
具有一个输出的典型 Keras ,您可以执行以下操作:
from keras import backend as K
# Create, compile and train model...
frozen_graph = freeze_session(K.get_session(),
output_names=[out.op.name for out in model.outputs])
Then you can write the graph to a file as usual with tf.train.write_graph
:
然后您可以像往常一样将图形写入文件tf.train.write_graph
:
tf.train.write_graph(frozen_graph, "some_directory", "my_model.pb", as_text=False)
回答by Jeff Tang
The freeze_session method works fine. But compared to saving to a checkpoint file then using the freeze_graph tool that comes with TensorFlow seems simpler to me, as it's easier to maintain. All you need to do is the following two steps:
freeze_session 方法工作正常。但是与保存到检查点文件相比,然后使用 TensorFlow 附带的 freeze_graph 工具对我来说似乎更简单,因为它更易于维护。您需要做的就是以下两个步骤:
First, add after your Keras code model.fit(...)
and train your model:
首先,在您的 Keras 代码之后添加model.fit(...)
并训练您的模型:
from keras import backend as K
import tensorflow as tf
print(model.output.op.name)
saver = tf.train.Saver()
saver.save(K.get_session(), '/tmp/keras_model.ckpt')
Then cd to your TensorFlow root directory, run:
然后 cd 到你的 TensorFlow 根目录,运行:
python tensorflow/python/tools/freeze_graph.py \
--input_meta_graph=/tmp/keras_model.ckpt.meta \
--input_checkpoint=/tmp/keras_model.ckpt \
--output_graph=/tmp/keras_frozen.pb \
--output_node_names="<output_node_name_printed_in_step_1>" \
--input_binary=true
回答by Amir Saniyan
The following simple example (XOR example) shows how to export Keras models (in both h5
format and pb
format), and using the model in Python and C++:
以下简单示例(XOR 示例)展示了如何导出 Keras 模型(h5
格式和pb
格式),以及在 Python 和 C++ 中使用模型:
train.py:
火车.py:
import numpy as np
import tensorflow as tf
def freeze_session(session, keep_var_names=None, output_names=None, clear_devices=True):
"""
Freezes the state of a session into a pruned computation graph.
Creates a new computation graph where variable nodes are replaced by
constants taking their current value in the session. The new graph will be
pruned so subgraphs that are not necessary to compute the requested
outputs are removed.
@param session The TensorFlow session to be frozen.
@param keep_var_names A list of variable names that should not be frozen,
or None to freeze all the variables in the graph.
@param output_names Names of the relevant graph outputs.
@param clear_devices Remove the device directives from the graph for better portability.
@return The frozen graph definition.
"""
graph = session.graph
with graph.as_default():
freeze_var_names = list(set(v.op.name for v in tf.global_variables()).difference(keep_var_names or []))
output_names = output_names or []
output_names += [v.op.name for v in tf.global_variables()]
input_graph_def = graph.as_graph_def()
if clear_devices:
for node in input_graph_def.node:
node.device = ''
frozen_graph = tf.graph_util.convert_variables_to_constants(
session, input_graph_def, output_names, freeze_var_names)
return frozen_graph
X = np.array([[0,0], [0,1], [1,0], [1,1]], 'float32')
Y = np.array([[0], [1], [1], [0]], 'float32')
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(64, input_dim=2, activation='relu'))
model.add(tf.keras.layers.Dense(64, activation='relu'))
model.add(tf.keras.layers.Dense(64, activation='relu'))
model.add(tf.keras.layers.Dense(64, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
model.compile(loss='mean_squared_error', optimizer='adam', metrics=['binary_accuracy'])
model.fit(X, Y, batch_size=1, nb_epoch=100, verbose=0)
# inputs: ['dense_input']
print('inputs: ', [input.op.name for input in model.inputs])
# outputs: ['dense_4/Sigmoid']
print('outputs: ', [output.op.name for output in model.outputs])
model.save('./xor.h5')
frozen_graph = freeze_session(tf.keras.backend.get_session(), output_names=[out.op.name for out in model.outputs])
tf.train.write_graph(frozen_graph, './', 'xor.pbtxt', as_text=True)
tf.train.write_graph(frozen_graph, './', 'xor.pb', as_text=False)
predict.py:
预测.py:
import numpy as np
import tensorflow as tf
model = tf.keras.models.load_model('./xor.h5')
# 0 ^ 0 = [[0.01974997]]
print('0 ^ 0 = ', model.predict(np.array([[0, 0]])))
# 0 ^ 1 = [[0.99141496]]
print('0 ^ 1 = ', model.predict(np.array([[0, 1]])))
# 1 ^ 0 = [[0.9897714]]
print('1 ^ 0 = ', model.predict(np.array([[1, 0]])))
# 1 ^ 1 = [[0.00406971]]
print('1 ^ 1 = ', model.predict(np.array([[1, 1]])))
opencv-predict.py:
opencv-predict.py:
import numpy as np
import cv2 as cv
model = cv.dnn.readNetFromTensorflow('./xor.pb')
# 0 ^ 0 = [[0.01974997]]
model.setInput(np.array([[0, 0]]), name='dense_input')
print('0 ^ 0 = ', model.forward(outputName='dense_4/Sigmoid'))
# 0 ^ 1 = [[0.99141496]]
model.setInput(np.array([[0, 1]]), name='dense_input')
print('0 ^ 1 = ', model.forward(outputName='dense_4/Sigmoid'))
# 1 ^ 0 = [[0.9897714]]
model.setInput(np.array([[1, 0]]), name='dense_input')
print('1 ^ 0 = ', model.forward(outputName='dense_4/Sigmoid'))
# 1 ^ 1 = [[0.00406971]]
model.setInput(np.array([[1, 1]]), name='dense_input')
print('1 ^ 1 = ', model.forward(outputName='dense_4/Sigmoid'))
predict.cpp:
预测.cpp:
#include <cstdlib>
#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, char **argv)
{
cv::dnn::Net net;
net = cv::dnn::readNetFromTensorflow("./xor.pb");
// 0 ^ 0 = [0.018541215]
float x0[] = { 0, 0 };
net.setInput(cv::Mat(1, 2, CV_32F, x0), "dense_input");
std::cout << "0 ^ 0 = " << net.forward("dense_4/Sigmoid") << std::endl;
// 0 ^ 1 = [0.98295897]
float x1[] = { 0, 1 };
net.setInput(cv::Mat(1, 2, CV_32F, x1), "dense_input");
std::cout << "0 ^ 1 = " << net.forward("dense_4/Sigmoid") << std::endl;
// 1 ^ 0 = [0.98810625]
float x2[] = { 1, 0 };
net.setInput(cv::Mat(1, 2, CV_32F, x2), "dense_input");
std::cout << "1 ^ 0 = " << net.forward("dense_4/Sigmoid") << std::endl;
// 1 ^ 1 = [0.010002014]
float x3[] = { 1, 1 };
net.setInput(cv::Mat(1, 2, CV_32F, x3), "dense_input");
std::cout << "1 ^ 1 = " << net.forward("dense_4/Sigmoid") << std::endl;
return EXIT_SUCCESS;
}
回答by Hazarapet Tunanyan
There is a very important point when you want to convert to tensorflow. If you use dropout, batch normalization or any other layers like these (which have not trainable but calculating values), you should change the learning phase of keras backend. Here is a discussionabout it.
当您想转换为 tensorflow 时,有一个非常重要的点。如果您使用 dropout、batch normalization 或任何其他类似的层(它们不可训练但计算值),您应该更改 keras backend 的学习阶段。这是关于它的讨论。
import keras.backend as K
k.set_learning_phase(0) # 0 testing, 1 training mode
回答by Tarik GUELZIM
This solution worked for me. Courtesy to https://medium.com/tensorflow/training-and-serving-ml-models-with-tf-keras-fd975cc0fa27
这个解决方案对我有用。感谢https://medium.com/tensorflow/training-and-serving-ml-models-with-tf-keras-fd975cc0fa27
import tensorflow as tf
# The export path contains the name and the version of the model
tf.keras.backend.set_learning_phase(0) # Ignore dropout at inference
model = tf.keras.models.load_model('./model.h5')
export_path = './PlanetModel/1'
# Fetch the Keras session and save the model
# The signature definition is defined by the input and output tensors
# And stored with the default serving key
with tf.keras.backend.get_session() as sess:
tf.saved_model.simple_save(
sess,
export_path,
inputs={'input_image': model.input},
outputs={t.name:t for t in model.outputs})
回答by lasclocker
Please use tf.saved_model.simple_save, some example codes:
请使用tf.saved_model.simple_save,一些示例代码:
with tf.keras.backend.get_session() as sess:
tf.saved_model.simple_save(
sess,
export_path,
inputs={'input': keras_model.input},
outputs={'output': keras_model.output})
===update====
===更新====
You can use as_a_saved_model, example codes:
您可以使用as_a_saved_model,示例代码:
saved_model_path = tf.contrib.saved_model.save_keras_model(model, "./saved_models")
回答by AHA
If you want the model only for inference, you should first freeze the graph and then write it as a .pb
file. The code snippet looks like this (code borrowed from here):
如果您希望模型仅用于推理,则应先冻结图形,然后将其写入.pb
文件。代码片段看起来像这样(从这里借用的代码):
import tensorflow as tf
from tensorflow.python.framework import graph_util
from tensorflow.python.framework import graph_io
import keras
from keras import backend as K
sess = K.get_session()
constant_graph = graph_util.convert_variables_to_constants(
sess,
sess.graph.as_graph_def(),
["name_of_the_output_graph_node"])
graph_io.write_graph(constant_graph, "path/to/output/folder",
"output_model_name", as_text=False)
You can do the above using the keras_to_tensorflowtool: https://github.com/amir-abdi/keras_to_tensorflow
您可以使用keras_to_tensorflow工具执行上述操作:https: //github.com/amir-abdi/keras_to_tensorflow
The keras_to_tensorflowtool takes care of the above operations, with some extra features for a more diverse solution. Just call it with the correct input arguments (e.g. input_model
and output_model
flags).
该keras_to_tensorflow工具负责上述业务的,有一些额外的功能,为一个更加多样化的解决方案。只需使用正确的输入参数(例如input_model
和output_model
标志)调用它。
If you want to retrain the model in tensorflow, use the above tool with the output_meta_ckpt
flag to export checkpoints and meta graphs.
如果要在 tensorflow 中重新训练模型,请使用带有output_meta_ckpt
标志的上述工具导出检查点和元图。
回答by Aashish Dahiya
using estimator.export_savedmodel we can easily convert h5 model to saved model. check doc here https://www.tensorflow.org/api_docs/python/tf/estimator/Estimator
使用 estimator.export_savedmodel 我们可以轻松地将 h5 模型转换为保存的模型。在此处查看文档https://www.tensorflow.org/api_docs/python/tf/estimator/Estimator
def prepare_image(image_str_tensor):
image_contents = tf.read_file(image_str_tensor)
image = tf.image.decode_jpeg(image_contents, channels=3)
image = tf.image.resize_images(image, [224, 224])
image = tf.cast(image, tf.float32)
return preprocess_input(image)
def serving_input_receiver_fn():
input_ph = tf.placeholder(tf.string, shape=[None])
images_tensor = tf.map_fn(
prepare_image, input_ph, back_prop=False, dtype=tf.float32)
images_tensor = tf.image.convert_image_dtype(images_tensor,
dtype=tf.float32)
return tf.estimator.export.ServingInputReceiver({"input": images_tensor},
{'image_url': input_ph})
estimator = tf.keras.estimator.model_to_estimator(
keras_model_path=h5_model_path
)
estimator.export_savedmodel(saved_model_path, serving_input_receiver_fn=serving_input_receiver_fn)
回答by WurmD
At this time, all above older answers are outdated. As of Tensorflow 2.1
目前,以上所有较旧的答案都已过时。从 Tensorflow 2.1 开始
from tensorflow.keras.models import Model, load_model
model = load_model(MODEL_FULLPATH)
model.save(MODEL_FULLPATH_MINUS_TERMINATION)
will create a folder with a 'saved_model.pb' inside
将创建一个包含“saved_model.pb”的文件夹
回答by satya prakash patel
Tensorflow tf.saved_modelapi is best for generating pb model
Tensorflow tf.saved_modelapi 最适合生成 pb 模型
If you have h5 model then load it through keras load_model
如果您有 h5 模型,则通过 keras load_model 加载它
from tensorflow import keras
model = keras.models.load_model("model.h5")
Save tensorflow model through saved_model api, It will save the model in pb format. This model will have required meta data for serving it through Google Ai Platform. So you can upload the directory to Ai Platform for serving your model.
通过saved_model api 保存tensorflow 模型,它会以pb 格式保存模型。此模型需要元数据才能通过 Google Ai Platform 提供服务。因此,您可以将目录上传到 Ai Platform 来为您的模型提供服务。
import tensorflow as tf
tf.saved_model.save(model, './directory-to-save-file/')