【发布时间】:2021-07-23 14:05:52
【问题描述】:
我在将 SSD 对象检测模型转换为 EdgeTPU 的 uint8 TFLite 时遇到问题。
据我所知,我一直在不同的论坛、堆栈溢出线程和 github 问题中进行搜索,我认为我正在遵循正确的步骤。我的 jupyter notebook 一定有问题,因为我无法实现我的建议。
我正在与您分享我在 Jupyter Notebook 上解释的步骤。我想会更清楚。
#!/usr/bin/env python
# coding: utf-8
设置
这一步是克隆存储库。如果之前做过一次,可以省略这一步。
import os
import pathlib
# Clone the tensorflow models repository if it doesn't already exist
if "models" in pathlib.Path.cwd().parts:
while "models" in pathlib.Path.cwd().parts:
os.chdir('..')
elif not pathlib.Path('models').exists():
!git clone --depth 1 https://github.com/tensorflow/models
进口
需要的步骤:这只是为了进行导入
import matplotlib
import matplotlib.pyplot as plt
import pathlib
import os
import random
import io
import imageio
import glob
import scipy.misc
import numpy as np
from six import BytesIO
from PIL import Image, ImageDraw, ImageFont
from IPython.display import display, Javascript
from IPython.display import Image as IPyImage
import tensorflow as tf
import tensorflow_datasets as tfds
from object_detection.utils import label_map_util
from object_detection.utils import config_util
from object_detection.utils import visualization_utils as viz_utils
#from object_detection.utils import colab_utils
from object_detection.utils import config_util
from object_detection.builders import model_builder
%matplotlib inline
下载友好模型
对于 tflite,建议使用 SSD 网络。 我已经下载了以下模型,它是关于“对象检测”的。它适用于 320x320 图像。# Download the checkpoint and put it into models/research/object_detection/test_data/
!wget http://download.tensorflow.org/models/object_detection/tf2/20200711/ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8.tar.gz
!tar -xf ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8.tar.gz
!if [ -d "models/research/object_detection/test_data/checkpoint" ]; then rm -Rf models/research/object_detection/test_data/checkpoint; fi
!mkdir models/research/object_detection/test_data/checkpoint
!mv ssd_mobilenet_v2_fpnlite_320x320_coco17_tpu-8/checkpoint models/research/object_detection/test_data/
用于为每个框添加正确标签的字符串列表。
PATH_TO_LABELS = '/home/jose/codeWorkspace-2.4.1/tf_2.4.1/models/research/object_detection/data/mscoco_label_map.pbtxt'
category_index = label_map_util.create_category_index_from_labelmap(PATH_TO_LABELS, use_display_name=True)
导出并使用 TFLite 运行
模型转换
在这一步中,我将 pb 保存的模型转换为 .tflite
!tflite_convert --saved_model_dir=/home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/saved_model --output_file=/home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/model.tflite
模型量化(从 float 到 uint8)
模型转换后,我需要对其进行量化。原始模型选择一个浮点数作为张量输入。因为我想在 Edge TPU 上运行它,所以我需要输入和输出张量为 uint8。生成校准数据集。
def representative_dataset_gen():
folder = "/home/jose/codeWorkspace-2.4.1/tf_2.4.1/images_ssd_mb2_2"
image_size = 320
raw_test_data = []
files = glob.glob(folder+'/*.jpeg')
for file in files:
image = Image.open(file)
image = image.convert("RGB")
image = image.resize((image_size, image_size))
#Quantizing the image between -1,1;
image = (2.0 / 255.0) * np.float32(image) - 1.0
#image = np.asarray(image).astype(np.float32)
image = image[np.newaxis,:,:,:]
raw_test_data.append(image)
for data in raw_test_data:
yield [data]
(不要运行这个)。就是上面的步骤,但是有随机值
如果您没有数据集,您也可以引入随机生成的值,就像它是图像一样。这是我以前这样做的代码:####THIS IS A RANDOM-GENERATED DATASET####
def representative_dataset_gen():
for _ in range(320):
data = np.random.rand(1, 320, 320, 3)
yield [data.astype(np.float32)]
调用模型转换
converter = tf.lite.TFLiteConverter.from_saved_model('/home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/saved_model')
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8, tf.lite.OpsSet.SELECT_TF_OPS]
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8
converter.allow_custom_ops = True
converter.representative_dataset = representative_dataset_gen
tflite_model = converter.convert()
警告:
转换步骤返回警告。
警告:absl:对于包含不受支持的操作的模型输入 无法量化,
inference_input_type属性将默认 到原来的类型。警告:absl:对于包含的模型输出 无法量化的不受支持的操作,inference_output_type属性将默认为原始类型。
这让我觉得转换不正确。
保存模型
with open('/home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/model_full_integer_quant.tflite'.format('/home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/saved_model'), 'wb') as w:
w.write(tflite_model)
print("tflite convert complete! - {}/home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/model_full_integer_quant.tflite".format('/home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/saved_model'))
测试
测试 1:获取 TensorFlow 版本
我读到建议为此使用 nightly。所以就我而言,版本是 2.6.0
print(tf.version.VERSION)
测试 2:获取输入/输出张量详细信息
interpreter = tf.lite.Interpreter(model_path="/home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/model_full_integer_quant.tflite")
interpreter.allocate_tensors()
print(interpreter.get_input_details())
print("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
print(interpreter.get_output_details())
测试 2 结果:
我得到以下信息:
[{'name': 'serving_default_input:0', 'index': 0, 'shape': array([ 1, 320, 320, 3], dtype=int32), 'shape_signature': array([ 1, 320, 320, 3], dtype=int32), 'dtype':
, '量化': (0.007843137718737125, 127), 'quantization_parameters': {'scales': 数组([0.00784314],dtype=float32),'zero_points':数组([127], dtype=int32), 'quantized_dimension': 0}, 'sparsity_parameters': {}}] @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ [{'name': 'StatefulPartitionedCall:31', 'index': 377, 'shape': array([ 1, 10, 4], dtype=int32), 'shape_signature': array([ 1, 10, 4], dtype=int32), 'dtype':
, '量化': (0.0, 0), 'quantization_parameters': {'scales': array([], dtype=float32), 'zero_points':数组([],dtype=int32),'quantized_dimension':0}, 'sparsity_parameters': {}}, {'name': 'StatefulPartitionedCall:32', “索引”:378,“形状”:数组([1, 10],dtype=int32), 'shape_signature': 数组([ 1, 10], dtype=int32), 'dtype': , '量化': (0.0, 0), 'quantization_parameters': {'scales': array([], dtype=float32), 'zero_points': array([], dtype=int32), 'quantized_dimension': 0}, 'sparsity_parameters': {}}, {'name': 'StatefulPartitionedCall:33', 'index': 379, 'shape': array([ 1, 10], dtype=int32), 'shape_signature': 数组([ 1, 10], dtype=int32), 'dtype': , '量化': (0.0, 0), 'quantization_parameters': {'scales': array([], dtype=float32), 'zero_points':数组([],dtype=int32),'quantized_dimension':0}, 'sparsity_parameters': {}}, {'name': 'StatefulPartitionedCall:34', “索引”:380,“形状”:数组([1],dtype = int32),“形状签名”: 数组([1],dtype=int32),'dtype':, “量化”:(0.0,0),“量化参数”:{“尺度”: 数组([],dtype=float32),'zero_points':数组([],dtype=int32), 'quantized_dimension': 0}, 'sparsity_parameters': {}}]
所以,我认为它没有正确量化它
将生成的模型转换为 EdgeTPU
!edgetpu_compiler -s /home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/model_full_integer_quant.tflite
jose@jose-VirtualBox:~/python-envs$ edgetpu_compiler -s /home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/model_full_integer_quant.tflite Edge TPU 编译器版本 15.0.340273435
模型在 1136 毫秒内成功编译。
输入模型: /home/jose/codeWorkspace-2.4.1/tf_2.4.1/tflite/model_full_integer_quant.tflite 输入大小:3.70MiB 输出模型: model_full_integer_quant_edgetpu.tflite 输出大小:4.21MiB 片上 用于缓存模型参数的内存:3.42MiB 片上内存 剩余用于缓存模型参数:4.31MiB 使用的片外内存 对于流式未缓存模型参数:0.00B 边缘 TPU 数量 子图:1 操作总数:162 操作日志: model_full_integer_quant_edgetpu.log
模型成功编译,但并非所有操作都支持 边缘 TPU。模型的一部分将改为在 CPU 上运行, 这是较慢的。如果可能,请考虑更新您的模型以仅使用 Edge TPU 支持的操作。有关详细信息,请访问 g.co/coral/model-reqs。将在 Edge TPU 上运行的操作数: 112 将在 CPU 上运行的操作数:50
操作员计数状态
LOGISTIC 1 操作否则 支持,但由于某些未指定的限制而未映射 DEPTHWISE_CONV_2D 14 不止一个子图 不支持 DEPTHWISE_CONV_2D 37 映射到边缘 TPU QUANTIZE 1 映射到边缘 TPU QUANTIZE 4 操作是否则 支持,但由于某些未指定的限制而未映射 CONV_2D
58 映射到边缘 TPU CONV_2D 14
不支持多个子图 DEQUANTIZE
1 操作正在处理不受支持的数据类型 DEQUANTIZE 1 操作在其他方面受支持,但由于以下原因未映射 一些未指定的限制 CUSTOM 1
操作正在处理不受支持的数据类型 ADD
2 不支持多个子图 ADD
10 映射到边缘 TPU 连接 1
否则支持操作,但由于某些原因未映射 未指定的限制 CONCATENATION 1 更多 不支持一个以上的子图 RESHAPE 2
否则支持操作,但由于某些原因未映射 未指定的限制 RESHAPE 6
映射到 Edge TPU RESHAPE 4 多于 PACK 4 不支持一个子图
张量的等级不受支持(最多映射 3 个最内层维度)
我准备的jupyter notebook可以在以下链接找到:https://github.com/jagumiel/Artificial-Intelligence/blob/main/tensorflow-scripts/Step-by-step-explaining-problems.ipynb
有没有我遗漏的步骤?为什么没有导致我的转换?
非常感谢您。
【问题讨论】:
-
我认为你的模型量化得很好。并不是所有的 TFLite 算子都能被量化。对 EdgeTPU 的部分委托是一种预期行为。如果对非量化操作有任何要求,请在 TensorFlow github 提出功能请求。
-
@JaesungChung,我应该尝试其他型号吗?你能推荐我另一个 320x320 对象检测模型来遵循相同的步骤吗?感谢您的回复。
标签: python tensorflow tensorflow-lite google-coral edge-tpu