如何将TensorFlow模型导出为.tflite文件? [英] How do I export a TensorFlow model as a .tflite file?

查看:173
本文介绍了如何将TensorFlow模型导出为.tflite文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景信息:

我编写了一个TensorFlow模型,该模型与TensorFlow提供的预制虹膜分类模型非常相似.差异相对较小:

I have written a TensorFlow model very similar to the premade iris classification model provided by TensorFlow. The differences are relatively minor:

  • 我要对足球运动进行分类,而不是虹膜种类.
  • 我有10个功能和一个标签,而不是4个功能和一个标签.
  • 我有5种不同的锻炼方式,而不是3种虹膜.
  • 我的trainData包含大约3500行,而不仅仅是120行.
  • 我的testData包含约330行,而不仅仅是30行.
  • 我正在使用n_classes = 6而不是3的DNN分类器.

我现在想将模型导出为.tflite文件.但是根据 TensorFlow开发人员指南,我需要先将模型导出到tf.GraphDef文件,然后冻结它,只有这样我才能将其转换.但是,TensorFlow提供的教程可以创建一个自定义模型中的.pb文件似乎仅针对图像分类模型进行了优化.

I now want to export the model as a .tflite file. But according to the TensorFlow Developer Guide, I need to first export the model to a tf.GraphDef file, then freeze it and only then will I be able to convert it. However, the tutorial provided by TensorFlow to create a .pb file from a custom model only seems to be optimized for image classification models.

问题:

那么如何将虹膜分类示例模型之类的模型转换为.tflite文件?有没有更简单,更直接的方法来执行此操作,而不必将其导出到.pb文件,然后将其冻结,依此类推?一个基于虹膜分类代码的示例或指向更明确的教程的链接将非常有用!

So how do I convert a model like the iris classification example model into a .tflite file? Is there an easier, more direct way to do it, without having to export it to a .pb file, then freeze it and so on? An example based on the iris classification code or a link to a more explicit tutorial would be very useful!

其他信息:

  • OS:macOS 10.13.4 High Sierra
  • TensorFlow版本:1.8.0
  • Python版本:3.6.4
  • 使用PyCharm社区2018.1.3

代码:

可以通过输入以下命令来克隆虹膜分类代码:

The iris classification code can be cloned by entering the following command:

git clone https://github.com/tensorflow/models

但是,如果您不想下载整个软件包,则为:

But in case you don't want to download the whole package, here it is:

这是名为 premade_estimator.py 的分类器文件:

This is the classifier file called premade_estimator.py:

    #  Copyright 2016 The TensorFlow Authors. All Rights Reserved.
    #
    #  Licensed under the Apache License, Version 2.0 (the "License");
    #  you may not use this file except in compliance with the License.
    #  You may obtain a copy of the License at
    #
    #  http://www.apache.org/licenses/LICENSE-2.0
    #
    #  Unless required by applicable law or agreed to in writing,                         software
    #  distributed under the License is distributed on an "AS IS" BASIS,
    #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    #  See the License for the specific language governing permissions and
    #  limitations under the License.
    """An Example of a DNNClassifier for the Iris dataset."""
    from __future__ import absolute_import
    from __future__ import division
    from __future__ import print_function

    import argparse
    import tensorflow as tf

    import iris_data

    parser = argparse.ArgumentParser()
    parser.add_argument('--batch_size', default=100, type=int, help='batch size')
    parser.add_argument('--train_steps', default=1000, type=int,
                help='number of training steps')


    def main(argv):
        args = parser.parse_args(argv[1:])

        # Fetch the data
        (train_x, train_y), (test_x, test_y) = iris_data.load_data()

        # Feature columns describe how to use the input.
        my_feature_columns = []
        for key in train_x.keys():
                    my_feature_columns.append(tf.feature_column.numeric_column(key=key))

        # Build 2 hidden layer DNN with 10, 10 units respectively.
        classifier = tf.estimator.DNNClassifier(
            feature_columns=my_feature_columns,
            # Two hidden layers of 10 nodes each.
            hidden_units=[10, 10],
            # The model must choose between 3 classes.
            n_classes=3)

        # Train the Model.
        classifier.train(
            input_fn=lambda: iris_data.train_input_fn(train_x, train_y,
                                              args.batch_size),
            steps=args.train_steps)

        # Evaluate the model.
        eval_result = classifier.evaluate(
            input_fn=lambda: iris_data.eval_input_fn(test_x, test_y,
                                             args.batch_size))

        print('\nTest set accuracy:         {accuracy:0.3f}\n'.format(**eval_result))

        # Generate predictions from the model
        expected = ['Setosa', 'Versicolor', 'Virginica']
        predict_x = {
            'SepalLength': [5.1, 5.9, 6.9],
            'SepalWidth': [3.3, 3.0, 3.1],
            'PetalLength': [1.7, 4.2, 5.4],
            'PetalWidth': [0.5, 1.5, 2.1],
        }

        predictions = classifier.predict(
            input_fn=lambda: iris_data.eval_input_fn(predict_x,
                                                     labels=None,
                                                     batch_size=args.batch_size))

        template = '\nPrediction is "{}" ({:.1f}%), expected "{}"'

        for pred_dict, expec in zip(predictions, expected):
            class_id = pred_dict['class_ids'][0]
            probability = pred_dict['probabilities'][class_id]

            print(template.format(iris_data.SPECIES[class_id],
                          100 * probability, expec))


    if __name__ == '__main__':
        # tf.logging.set_verbosity(tf.logging.INFO)
        tf.app.run(main)

这是名为 iris_data.py 的数据文件:

And this is the data file called iris_data.py:

    import pandas as pd
    import tensorflow as tf

    TRAIN_URL = "http://download.tensorflow.org/data/iris_training.csv"
    TEST_URL = "http://download.tensorflow.org/data/iris_test.csv"

    CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth',
                        'PetalLength', 'PetalWidth', 'Species']
    SPECIES = ['Setosa', 'Versicolor', 'Virginica']


    def maybe_download():
        train_path = tf.keras.utils.get_file(TRAIN_URL.split('/')[-1], TRAIN_URL)
        test_path = tf.keras.utils.get_file(TEST_URL.split('/')[-1], TEST_URL)

        return train_path, test_path


    def load_data(y_name='Species'):
        """Returns the iris dataset as (train_x, train_y), (test_x, test_y)."""
        train_path, test_path = maybe_download()

        train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0)
        train_x, train_y = train, train.pop(y_name)

        test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)
        test_x, test_y = test, test.pop(y_name)

        return (train_x, train_y), (test_x, test_y)


    def train_input_fn(features, labels, batch_size):
        """An input function for training"""
        # Convert the inputs to a Dataset.
        dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))

        # Shuffle, repeat, and batch the examples.
        dataset = dataset.shuffle(1000).repeat().batch(batch_size)

        # Return the dataset.
        return dataset


    def eval_input_fn(features, labels, batch_size):
        """An input function for evaluation or prediction"""
        features = dict(features)
        if labels is None:
            # No labels, use only features.
            inputs = features
        else:
            inputs = (features, labels)

        # Convert the inputs to a Dataset.
        dataset = tf.data.Dataset.from_tensor_slices(inputs)

        # Batch the examples
        assert batch_size is not None, "batch_size must not be None"
        dataset = dataset.batch(batch_size)

        # Return the dataset.
        return dataset

** 更新 **

好,所以我发现了一段看似非常有用的代码在此页面上:

Ok so I have found a seemingly very useful piece of code on this page:

    import tensorflow as tf

    img = tf.placeholder(name="img", dtype=tf.float32, shape=(1, 64, 64, 3))
    val = img + tf.constant([1., 2., 3.]) + tf.constant([1., 4., 4.])
    out = tf.identity(val, name="out")
    with tf.Session() as sess:
      tflite_model = tf.contrib.lite.toco_convert(sess.graph_def, [img], [out])
      open("test.tflite", "wb").write(tflite_model)

这个小家伙直接将简单模型转换为TensorFlow Lite模型.现在,我要做的就是找到一种使它适应虹膜分类模型的方法.有什么建议吗?

This little guy directly converts a simple model to a TensorFlow Lite Model. Now all I have to do is find a way to adapt this to the iris classification model. Any suggestions?

推荐答案

是否有一种更简单,更直接的方法,而不必将其导出到.pb文件,然后将其冻结,依此类推?

Is there an easier, more direct way to do it, without having to export it to a .pb file, then freeze it and so on?

是的,正如您在更新的问题中指出的那样,可以

Yes, as you pointed out in the updated question, it is possible to freeze the graph and use toco_convert in python api directly. It needs the graph to be frozen and the input and output shapes to be determined. In your question, there is no freeze graph step since there are no variables. If you have variables and run toco without converting those to constants first, toco will complain!

现在我所要做的就是找到一种方法使之适应虹膜分类模型.有什么建议吗?

Now all I have to do is find a way to adapt this to the iris classification model. Any suggestions?

这是一个比较棘手的问题,需要更多的工作.基本上,您需要加载图并找出输入和输出张量名称,然后冻结图并调用toco_convert.为了在这种情况下(未定义图形)查找输入和输出张量名称,必须在生成的图形周围进行戳记,并根据输入形状,名称等确定它们.这是可以在以下位置附加的代码在这种情况下,premade_estimator.py中主要函数的末尾将生成tflite图.

This one is slightly trickier and needs more work. Basically, you need to load the graph and figure out the input and output tensor names and then freeze the graph and call toco_convert. For finding the input and output tensor names in this case (where you have not defined the graph), you have to poke around the graph generated and determine them based on input shapes, names, etc. Here is the code that you can append at the end of your main function in premade_estimator.py to generate the tflite graph in this case.

print("\n====== classifier model_dir, latest_checkpoint ===========")
print(classifier.model_dir)
print(classifier.latest_checkpoint())
debug = False

with tf.Session() as sess:
    # First let's load meta graph and restore weights
    latest_checkpoint_path = classifier.latest_checkpoint()
    saver = tf.train.import_meta_graph(latest_checkpoint_path + '.meta')
    saver.restore(sess, latest_checkpoint_path)

    # Get the input and output tensors needed for toco.
    # These were determined based on the debugging info printed / saved below.
    input_tensor = sess.graph.get_tensor_by_name("dnn/input_from_feature_columns/input_layer/concat:0")
    input_tensor.set_shape([1, 4])
    out_tensor = sess.graph.get_tensor_by_name("dnn/logits/BiasAdd:0")
    out_tensor.set_shape([1, 3])

    # Pass the output node name we are interested in.
    # Based on the debugging info printed / saved below, pulled out the
    # name of the node for the logits (before the softmax is applied).
    frozen_graph_def = tf.graph_util.convert_variables_to_constants(
        sess, sess.graph_def, output_node_names=["dnn/logits/BiasAdd"])

    if debug is True:
        print("\nORIGINAL GRAPH DEF Ops ===========================================")
        ops = sess.graph.get_operations()
        for op in ops:
            if "BiasAdd" in op.name or "input_layer" in op.name:
                print([op.name, op.values()])
        # save original graphdef to text file
        with open("estimator_graph.pbtxt", "w") as fp:
            fp.write(str(sess.graph_def))

        print("\nFROZEN GRAPH DEF Nodes ===========================================")
        for node in frozen_graph_def.node:
            print(node.name)
        # save frozen graph def to text file
        with open("estimator_frozen_graph.pbtxt", "w") as fp:
            fp.write(str(frozen_graph_def))

tflite_model = tf.contrib.lite.toco_convert(frozen_graph_def, [input_tensor], [out_tensor])
open("estimator_model.tflite", "wb").write(tflite_model)

注意:我假设来自最后一层(应用Softmax之前)的logits作为输出,与节点 dnn/logits/BiasAdd .如果您需要概率,我相信它是 dnn/head/predictions/probability .

Note: I am assuming the logits from the final layer (before the Softmax is applied) as the output, corresponding to the node dnn/logits/BiasAdd. If you want the probabilities, I believe it is dnn/head/predictions/probabilities.

这篇关于如何将TensorFlow模型导出为.tflite文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆