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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 17:02:53  来源:igfitidea点击:

How to export Keras .h5 to tensorflow .pb?

pythontensorflowkeras

提问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.pyincluded in TensorFlow, which is the "typical" way it is done.

Keras 本身不包含任何将 TensorFlow 图导出为协议缓冲区文件的方法,但您可以使用常规的 TensorFlow 实用程序来实现。是一篇博客文章,解释了如何使用freeze_graph.pyTensorFlow 中包含的实用程序脚本来执行此操作,这是完成此操作的“典型”方式。

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. sessionis the TensorFlow session object. keep_var_namesis only needed if you want to keep some variable not frozen (e.g. for stateful models), so generally not. output_namesis a list with the names of the operations that produce the outputs that you want. clear_devicesjust removes any device directives to make the graph more portable. So, for a typical Keras modelwith 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 h5format and pbformat), 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 .pbfile. 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_modeland output_modelflags).

keras_to_tensorflow工具负责上述业务的,有一些额外的功能,为一个更加多样化的解决方案。只需使用正确的输入参数(例如input_modeloutput_model标志)调用它。

If you want to retrain the model in tensorflow, use the above tool with the output_meta_ckptflag 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/')