如何将冻结图转换为 TensorFlow lite

Posted

技术标签:

【中文标题】如何将冻结图转换为 TensorFlow lite【英文标题】:How to convert frozen graph to TensorFlow lite 【发布时间】:2022-01-11 22:55:23 【问题描述】:

我一直在努力追随, https://www.tensorflow.org/lite/examples/object_detection/overview#model_customization 整天将任何 tensorflow Zoo 模型转换为 TensorFlow Lite 模型以便在 android 上运行,但没有成功。

我从这里下载了几个模型, https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/tf1_detection_zoo.md (仅供参考,Chrome不会因为不是https而让您失望,我必须右键单击检查链接并单击检查器中的链接)

我有剧本,

import tensorflow as tf

converter = tf.lite.TFLiteConverter.from_frozen_graph(
    graph_def_file='frozen_graph.pb',
    input_shapes = 'normalized_input_image_tensor':[1,300,300,3],
    input_arrays = ['normalized_input_image_tensor'],
    output_arrays = ['TFLite_Detection_PostProcess','TFLite_Detection_PostProcess:1', 'TFLite_Detection_PostProcess:2','TFLite_Detection_PostProcess:3']
)
tflite_model = converter.convert()

with open('model.tflite', 'wb') as f:
  f.write(tflite_model)

但给出错误, ValueError:找到了无效的张量“normalized_input_image_tensor”

线条,

input_shapes = 'normalized_input_image_tensor':[1,300,300,3], input_arrays = ['normalized_input_image_tensor'], output_arrays = ['TFLite_Detection_PostProcess','TFLite_Detection_PostProcess:1', 'TFLite_Detection_PostProcess:2','TFLite_Detection_PostProcess:3']

一定是错的,需要不同的形状,但是我如何为每个动物园模型得到这个, 还是我需要先运行一些预转换代码?

运行下面我得到的“代码片段”,

--------------------------------------------------
Frozen model layers:
name: "add/y"
op: "Const"
attr 
  key: "dtype"
  value 
    type: DT_FLOAT
  

attr 
  key: "value"
  value 
    tensor 
      dtype: DT_FLOAT
      tensor_shape 
      
      float_val: 1.0
    
  


Input layer:  add/y
Output layer:  Postprocessor/BatchMultiClassNonMaxSuppression/map/while/NextIteration_1
--------------------------------------------------

但我看不出这将如何映射到 input_shape 或帮助转换??

甚至可以将诸如faster_rcnn_inception_v2_coco之类的模型转换为tflite吗?我在某处读到仅支持 SSD 型号?

所以我尝试使用下面建议的代码将 faster_rcnn_inception_v2_coco 转换为 tflite,对话代码在 TF1 中不起作用,但在 TF2 中起作用,但是当我尝试在 TFlite 示例应用程序中使用 tflite 文件时,我得到了这个错误,

2021-12-14 13:23:01.979 24542-24542/org.tensorflow.lite.examples.detection E/tflite: Missing 'operators' section in subgraph.
2021-12-14 13:23:01.984 24542-24542/org.tensorflow.lite.examples.detection E/TaskJniUtils: Error getting native address of native library: task_vision_jni
    java.lang.RuntimeException: Error occurred when initializing ObjectDetector: Could not build model from the provided pre-loaded flatbuffer: Missing 'operators' section in subgraph.
        at org.tensorflow.lite.task.vision.detector.ObjectDetector.initJniWithByteBuffer(Native Method)
        at org.tensorflow.lite.task.vision.detector.ObjectDetector.access$100(ObjectDetector.java:88)
        at org.tensorflow.lite.task.vision.detector.ObjectDetector$3.createHandle(ObjectDetector.java:223)
        at org.tensorflow.lite.task.core.TaskJniUtils.createHandleFromLibrary(TaskJniUtils.java:91)
        at org.tensorflow.lite.task.vision.detector.ObjectDetector.createFromBufferAndOptions(ObjectDetector.java:219)
        at org.tensorflow.lite.examples.detection.tflite.TFLiteObjectDetectionAPIModel.<init>(TFLiteObjectDetectionAPIModel.java:88)
        at org.tensorflow.lite.examples.detection.tflite.TFLiteObjectDetectionAPIModel.create(TFLiteObjectDetectionAPIModel.java:82)
        at org.tensorflow.lite.examples.detection.DetectorActivity.onPreviewSizeChosen(DetectorActivity.java:99)
        at org.tensorflow.lite.examples.detection.CameraActivity$7.onPreviewSizeChosen(CameraActivity.java:446)

【问题讨论】:

您确定输入的张量名称正确吗?至少有一个模型输入张量被命名为image_tensor 不,它们不正确,我如何找到正确的名称?每个动物园模型 例如,您可以使用 Netron (github.com/lutzroeder/netron) 来可视化 protobuffs。找到输入和输出张量,就可以看到它们的名字了。 是否有简单的 python 代码来获取 input_shape、input_array、output_array,或者这些是否记录在某个地方用于动物园模型? 你使用 tensorflow 1 有什么原因吗? 【参考方案1】:

这段代码sn-p

import tensorflow as tf

def print_layers(graph_def):
    def _imports_graph_def():
        tf.compat.v1.import_graph_def(graph_def, name="")

    wrapped_import = tf.compat.v1.wrap_function(_imports_graph_def, [])
    import_graph = wrapped_import.graph

    print("-" * 50)
    print("Frozen model layers: ")
    layers = [op.name for op in import_graph.get_operations()]
    ops = import_graph.get_operations()
    print(ops[0])
    print("Input layer: ", layers[0])
    print("Output layer: ", layers[-1])
    print("-" * 50)

# Load frozen graph using TensorFlow 1.x functions
with tf.io.gfile.GFile("model.pb", "rb") as f:
    graph_def = tf.compat.v1.GraphDef()
    loaded = graph_def.ParseFromString(f.read())

frozen_func = print_layers(graph_def=graph_def)

打印输入层的属性,包括形状,以及输入和输出层的名称:

--------------------------------------------------
Frozen model layers: 
name: "image_tensor"
op: "Placeholder"
attr 
  key: "dtype"
  value 
    type: DT_UINT8
  

attr 
  key: "shape"
  value 
    shape 
      dim 
        size: -1
      
      dim 
        size: -1
      
      dim 
        size: -1
      
      dim 
        size: 3
      
    
  


Input layer:  image_tensor
Output layer:  detection_classes
--------------------------------------------------

然后,您可以在代码中插入正确的图层名称和形状,转换应该会起作用。

【讨论】:

那么从你的例子来看 input_shapes input_array 的值是什么? 查看我上面的编辑结果【参考方案2】:

这些模型是使用 TensorFlow 版本 1 制作的。因此您必须使用 saved_model 生成具体函数(因为 TFLite 不喜欢动态输入形状),然后从那里转换为 TFLite。

我会写一个你可以立即使用的简单解决方案。

打开一个colab notebook,它是免费的并且是在线的。转至this address 然后点击右下角的New Notebook。

第一个单元格(在下面输入并使用播放按钮执行):

!wget http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_fpn_shared_box_predictor_640x640_coco14_sync_2018_07_03.tar.gz
!tar -xzvf "/content/ssd_mobilenet_v1_fpn_shared_box_predictor_640x640_coco14_sync_2018_07_03.tar.gz" -C "/content/"

第二个单元格(输入,执行):

import tensorflow as tf
print(tf.__version__)

第三个单元格(输入,执行):

model = tf.saved_model.load('/content/ssd_mobilenet_v1_fpn_shared_box_predictor_640x640_coco14_sync_2018_07_03/saved_model')
concrete_func = model.signatures[
tf.saved_model.DEFAULT_SERVING_SIGNATURE_DEF_KEY]
concrete_func.inputs[0].set_shape([1, 300, 300, 3])

converter = tf.lite.TFLiteConverter.from_concrete_functions([concrete_func])
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS]

tflite_model = converter.convert()

with open('detect.tflite', 'wb') as f:
  f.write(tflite_model)

下面的代码是必要的,因为有些操作是 TFLite 本身不支持的:

converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS, tf.lite.OpsSet.SELECT_TF_OPS]

但您还必须在 this 之后的移动项目中添加特定依赖项。

如果您想删除一些 MB 的 tflite 文件并使其更小,请关注 these procedures。

完成后你会在左侧看到一个detect.tflite模型。

转到netron.app 并复制粘贴文件或浏览以上传文件。您将看到所有详细信息:

【讨论】:

尝试这个,当前从 load() 调用中得到“TypeError: load() missing 2 required positional arguments: 'tags' and 'export_dir'”,认为它需要 None arg。 我猜代码是 TF2,TF1 的代码是什么? 并且需要能够转换 freeze_graph.pb 文件,我现有的训练模型没有 save_model 对不起,只是按照您的要求...来自动物园链接的模型。如果您需要什么,或者您有特定的东西,请标记我。 图层名称是您在上图中看到的那些..如果这有助于更多。如果您将模型上传到某个地方,请标记我看看。

以上是关于如何将冻结图转换为 TensorFlow lite的主要内容,如果未能解决你的问题,请参考以下文章

TensorFlow:有没有办法将冻结图转换为检查点模型?

如何将 HED 模型转换为 Tensorflow Lite 模型

将 Keras 模型转换为 TensorFlow lite - 如何避免不支持的操作?

如何创建可轻松转换为 TensorFlow Lite 的模型?

如何创建一个可轻松转换为TensorFlow Lite的模型?

为啥 TensorFlow Lite 比桌面版 TensorFlow 慢?