TensorFlow Lite 无法识别 op VarHandleOp
TensorFlow Lite does not recognize op VarHandleOp
我正在尝试将 TF 模型转换为 TFLite。模型保存为 .pb
格式,我用下面的代码转换了它:
import os
import tensorflow as tf
from tensorflow.core.protobuf import meta_graph_pb2
export_dir = os.path.join('export_dir', '0')
if not os.path.exists('export_dir'):
os.mkdir('export_dir')
tf.compat.v1.enable_control_flow_v2()
tf.compat.v1.enable_v2_tensorshape()
# I took this function from a tutorial on the TF website
def wrap_frozen_graph(graph_def, inputs, outputs):
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
return wrapped_import.prune(
inputs, outputs)
graph_def = tf.compat.v1.GraphDef()
loaded = graph_def.ParseFromString(open(os.path.join(export_dir, 'saved_model.pb'),'rb').read())
concrete_func = wrap_frozen_graph(
graph_def, inputs=['extern_data/placeholders/data/data:0', 'extern_data/placeholders/data/data_dim0_size:0'],
outputs=['output/output_batch_major:0'])
concrete_func.inputs[0].set_shape([None, 50])
concrete_func.inputs[1].set_shape([None])
concrete_func.outputs[0].set_shape([None, 100])
converter = tf.lite.TFLiteConverter.from_concrete_functions([concrete_func])
converter.experimental_new_converter = True
converter.post_training_quantize=True
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS,
tf.lite.OpsSet.SELECT_TF_OPS]
converter.allow_custom_ops=True
tflite_model = converter.convert()
# Save the model.
if not os.path.exists('tflite'):
os.mkdir('tflite')
output_model = os.path.join('tflite', 'model.tflite')
with open(output_model, 'wb') as f:
f.write(tflite_model)
但是,当我尝试对这个模型使用 intepretere 时,出现以下错误:
INFO: TfLiteFlexDelegate delegate: 8 nodes delegated out of 970 nodes with 3 partitions.
INFO: TfLiteFlexDelegate delegate: 0 nodes delegated out of 4 nodes with 0 partitions.
INFO: TfLiteFlexDelegate delegate: 3 nodes delegated out of 946 nodes with 1 partitions.
INFO: TfLiteFlexDelegate delegate: 0 nodes delegated out of 1 nodes with 0 partitions.
INFO: TfLiteFlexDelegate delegate: 3 nodes delegated out of 16 nodes with 2 partitions.
Traceback (most recent call last):
File "/path/to/tflite_interpreter.py", line 9, in <module>
interpreter.allocate_tensors()
File "/path/to/lib/python3.6/site-packages/tensorflow/lite/python/interpreter.py", line 243, in allocate_tensors
return self._interpreter.AllocateTensors()
RuntimeError: Encountered unresolved custom op: VarHandleOp.Node number 0 (VarHandleOp) failed to prepare.
现在,我在代码中找不到任何 VarHandleOp
,我发现它实际上在 tensorflow (https://www.tensorflow.org/api_docs/python/tf/raw_ops/VarHandleOp) 中。
那么,为什么 TFLite 无法识别它?
按照 SO 指南的建议,在模型转换的情况下提供最小的可重现示例当然很困难,但是问题会从更好的指针中受益。例如,与其说“我从 TF 网站上的教程中获取了此功能”,不如为教程提供 link 是一个更好的主意。 TF网站非常庞大
您所指的教程可能来自 section on migrating from TF1 to TF2,特别是处理原始图形文件的部分。至关重要的注意事项是
if you have a "Frozen graph" (a tf.Graph
where the variables have been turned into constants)
(粗体突出显示是我的)。显然,您的图表包含 VarHandleOp
(这同样适用于 Variable
和 VariableV2
节点),并且根据此定义没有“冻结”。您的一般方法是有道理的,但您需要一个图表,其中包含 Const
节点形式的变量的实际训练值。您在训练时需要变量,但在推理时需要变量,并且应该被烘焙到图中。 TFLite 作为一个 inference-time 框架,不支持变量。
你的其他想法似乎不错。 TFLiteConverter.from_concrete_functions
目前恰好需要一个 concrete_function
,但这是您通过包装图表得到的结果。如果足够幸运,它可能会起作用。
有一个实用程序 tensorflow/python/tools/freeze_graph.py
会尽力用最新检查点文件中的常量替换 Graph.pb 中的变量。如果你查看它的代码,要么使用保存的元图(checkpoint_name.meta)文件,要么将工具指向训练目录,这样可以消除很多猜测;另外,我认为提供模型目录是将单个冻结图作为分片模型的唯一方法。
我注意到您在示例中仅使用 input
代替了 tf.nest.map_structure(import_graph.as_graph_element, inputs)
。您可能有其他原因,但如果您这样做是因为 as_graph_element
抱怨 datatype/shape,这可能会通过适当冻结图表来解决。您从冻结图中获得的 concrete_function 将对其输入形状和数据类型有一个很好的了解。一般来说,需要手动设置它们是意想不到的,而且你这样做的事实对我来说似乎很奇怪(但我并没有声称对 TF 的这个黑暗角落有广泛的经验)。
map_structure
有一个跳过检查的关键字参数。
我正在尝试将 TF 模型转换为 TFLite。模型保存为 .pb
格式,我用下面的代码转换了它:
import os
import tensorflow as tf
from tensorflow.core.protobuf import meta_graph_pb2
export_dir = os.path.join('export_dir', '0')
if not os.path.exists('export_dir'):
os.mkdir('export_dir')
tf.compat.v1.enable_control_flow_v2()
tf.compat.v1.enable_v2_tensorshape()
# I took this function from a tutorial on the TF website
def wrap_frozen_graph(graph_def, inputs, outputs):
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
return wrapped_import.prune(
inputs, outputs)
graph_def = tf.compat.v1.GraphDef()
loaded = graph_def.ParseFromString(open(os.path.join(export_dir, 'saved_model.pb'),'rb').read())
concrete_func = wrap_frozen_graph(
graph_def, inputs=['extern_data/placeholders/data/data:0', 'extern_data/placeholders/data/data_dim0_size:0'],
outputs=['output/output_batch_major:0'])
concrete_func.inputs[0].set_shape([None, 50])
concrete_func.inputs[1].set_shape([None])
concrete_func.outputs[0].set_shape([None, 100])
converter = tf.lite.TFLiteConverter.from_concrete_functions([concrete_func])
converter.experimental_new_converter = True
converter.post_training_quantize=True
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS,
tf.lite.OpsSet.SELECT_TF_OPS]
converter.allow_custom_ops=True
tflite_model = converter.convert()
# Save the model.
if not os.path.exists('tflite'):
os.mkdir('tflite')
output_model = os.path.join('tflite', 'model.tflite')
with open(output_model, 'wb') as f:
f.write(tflite_model)
但是,当我尝试对这个模型使用 intepretere 时,出现以下错误:
INFO: TfLiteFlexDelegate delegate: 8 nodes delegated out of 970 nodes with 3 partitions.
INFO: TfLiteFlexDelegate delegate: 0 nodes delegated out of 4 nodes with 0 partitions.
INFO: TfLiteFlexDelegate delegate: 3 nodes delegated out of 946 nodes with 1 partitions.
INFO: TfLiteFlexDelegate delegate: 0 nodes delegated out of 1 nodes with 0 partitions.
INFO: TfLiteFlexDelegate delegate: 3 nodes delegated out of 16 nodes with 2 partitions.
Traceback (most recent call last):
File "/path/to/tflite_interpreter.py", line 9, in <module>
interpreter.allocate_tensors()
File "/path/to/lib/python3.6/site-packages/tensorflow/lite/python/interpreter.py", line 243, in allocate_tensors
return self._interpreter.AllocateTensors()
RuntimeError: Encountered unresolved custom op: VarHandleOp.Node number 0 (VarHandleOp) failed to prepare.
现在,我在代码中找不到任何 VarHandleOp
,我发现它实际上在 tensorflow (https://www.tensorflow.org/api_docs/python/tf/raw_ops/VarHandleOp) 中。
那么,为什么 TFLite 无法识别它?
按照 SO 指南的建议,在模型转换的情况下提供最小的可重现示例当然很困难,但是问题会从更好的指针中受益。例如,与其说“我从 TF 网站上的教程中获取了此功能”,不如为教程提供 link 是一个更好的主意。 TF网站非常庞大
您所指的教程可能来自 section on migrating from TF1 to TF2,特别是处理原始图形文件的部分。至关重要的注意事项是
if you have a "Frozen graph" (a
tf.Graph
where the variables have been turned into constants)
(粗体突出显示是我的)。显然,您的图表包含 VarHandleOp
(这同样适用于 Variable
和 VariableV2
节点),并且根据此定义没有“冻结”。您的一般方法是有道理的,但您需要一个图表,其中包含 Const
节点形式的变量的实际训练值。您在训练时需要变量,但在推理时需要变量,并且应该被烘焙到图中。 TFLite 作为一个 inference-time 框架,不支持变量。
你的其他想法似乎不错。 TFLiteConverter.from_concrete_functions
目前恰好需要一个 concrete_function
,但这是您通过包装图表得到的结果。如果足够幸运,它可能会起作用。
有一个实用程序 tensorflow/python/tools/freeze_graph.py
会尽力用最新检查点文件中的常量替换 Graph.pb 中的变量。如果你查看它的代码,要么使用保存的元图(checkpoint_name.meta)文件,要么将工具指向训练目录,这样可以消除很多猜测;另外,我认为提供模型目录是将单个冻结图作为分片模型的唯一方法。
我注意到您在示例中仅使用 input
代替了 tf.nest.map_structure(import_graph.as_graph_element, inputs)
。您可能有其他原因,但如果您这样做是因为 as_graph_element
抱怨 datatype/shape,这可能会通过适当冻结图表来解决。您从冻结图中获得的 concrete_function 将对其输入形状和数据类型有一个很好的了解。一般来说,需要手动设置它们是意想不到的,而且你这样做的事实对我来说似乎很奇怪(但我并没有声称对 TF 的这个黑暗角落有广泛的经验)。
map_structure
有一个跳过检查的关键字参数。