當 tensorflow 模型包含tf.function帶有 for 回圈的裝飾函式時,tf->onnx 轉換會產生警告:
WARNING:tensorflow:From /Users/amit/Programs/lammps/kim/kliff/venv/lib/python3.7/site-packages/tf2onnx/tf_loader.py:706: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.compat.v1.graph_util.extract_sub_graph`
Cannot infer shape for model/ex_layer/PartitionedCall/while: model/ex_layer/PartitionedCall/while:3
Cannot infer shape for model/ex_layer/PartitionedCall/Identity: model/ex_layer/PartitionedCall/Identity:0
Cannot infer shape for Func/model/ex_layer/PartitionedCall/output/_3: Func/model/ex_layer/PartitionedCall/output/_3:0
Cannot infer shape for Identity: Identity:0
missing output shape for while/Identity_3:0
missing output shape for while/Identity_3:0
missing output shape for while/Identity_3:0
missing output shape for while/Identity_3:0
...
并且由于獲得的模型通過 onnxruntime 運行它運行良好,但模型檢查器給出以下錯誤
Traceback (most recent call last):
File "failed_example.py", line 85, in <module>
onnx.checker.check_model(onnx.load("tmp.onnx"))
File "venv/lib/python3.7/site-packages/onnx/checker.py", line 106, in check_model
C.check_model(protobuf_string)
onnx.onnx_cpp2py_export.checker.ValidationError: Field 'shape' of type is required but missing.
Netron 沒有表現出有裝飾功能的模型和沒有裝飾功能的模型之間有任何明顯的區別。我猜錯誤來自這樣一個事實,即 for 回圈被轉換為單獨的 while 回圈圖,其輸入形狀未定義。但它在沒有 tf.function 裝飾器的情況下作業得很好。我在下面放了一個最小的復制代碼。
我認為這與以下問題有關:
- https://github.com/onnx/onnx/issues/2932
- https://github.com/onnx/onnx/issues/2492
- https://github.com/onnx/onnx/pull/2937
復制代碼:
import tensorflow as tf
import numpy as np
import sys
import onnx
import onnxruntime
import tf2onnx
# =============================================================================
# Layer and its herler functions
# COMMENT IT OUT TO PASS ONNX CHECK
@tf.function(
input_signature=[
tf.TensorSpec(shape=[None,None], dtype=tf.int32),
tf.TensorSpec(shape=[None,None], dtype=tf.float32),
tf.TensorSpec(shape=None, dtype=tf.float32),
])
def extra_function(
list1,
list2,
accum_var
):
some_num = 4
num_iter = tf.size(list1)//some_num
for i in range(num_iter):
xyz_i = list2[0, i * 3 : (i 1) * 3]
accum_var = tf.reduce_sum(xyz_i)
return accum_var
class ExLayer(tf.keras.layers.Layer):
def __init__(self):
super().__init__()
# Doesnt tf.function also create graphs out of called functions?
# however it does not seem to do that if `call` function is decorated
# @tf.function(
# input_signature=[
# tf.TensorSpec(shape=[None,None], dtype=tf.float32),
# tf.TensorSpec(shape=[None,None], dtype=tf.int32),
# ])
def call(self, list2,list1):
accum_var = tf.constant(0.0)
accum_var = extra_function( list1, list2, accum_var)
return accum_var
# =============================================================================
# =============================================================================
# Example implementation
layer1 = tf.keras.layers.Input(shape=(1,))
layer2 = tf.keras.layers.Input(shape=(1,), dtype=tf.int32)
EL = ExLayer()(layer1,layer2)
model = tf.keras.models.Model(inputs=[layer1, layer2], outputs=EL)
# Define input data
list2_tf = tf.constant([[0.,0.,0.,1.,1.,1.,2.,2.,2.,3.,3.,3.]],dtype=tf.float32)
list1_tf = tf.constant([[0,1,2,-1,1,0,2,-1,2,0,1,-1]],dtype=tf.int32)
list2_np = np.array([[0.,0.,0.,1.,1.,1.,2.,2.,2.,3.,3.,3.]],dtype=np.float32)
list1_np = np.array([[0,1,2,-1,1,0,2,-1,2,0,1,-1]],dtype=np.int32)
# Save to onnx
model_proto, external_tensor_storage = tf2onnx.convert.from_keras(model,
input_signature=[
tf.TensorSpec(shape=[None,None], dtype=tf.float32, name="list2"),
tf.TensorSpec(shape=[None,None], dtype=tf.int32, name="list1")
],
opset=11,
output_path="tmp.onnx")
# Load onnx runtime session
ort_session = onnxruntime.InferenceSession("tmp.onnx")
inputs = {"list2":list2_np, "list1":list1_np}
print("===================================================")
print("Original model evaluation:")
print(model([list2_tf,list1_tf]))
print("ORT session evaluation")
print(ort_session.run(None, inputs))
print("===================================================")
# Check with model checker
onnx.checker.check_model(onnx.load("tmp.onnx"))
- ONNX 版本:1.10.2
- Python版本:3.7.7
- TF版本:2.7.0
我提交的相關github問題:
- https://github.com/onnx/onnx/issues/3909
- https://github.com/onnx/tensorflow-onnx/issues/1812
uj5u.com熱心網友回復:
問題在于您指定 accumm_var 的形狀的方式。
在輸入簽名中,您有tf.TensorSpec(shape=None, dtype=tf.float32). 閱讀代碼我看到你正在傳遞一個標量張量。標量張量是一個 0 維張量,因此您應該使用shape=[]代替shape=None。
我注釋后運行沒有在這里警告extra_function與
tf.function(
input_signature=[
tf.TensorSpec(shape=[None,None], dtype=tf.int32),
tf.TensorSpec(shape=[None,None], dtype=tf.float32),
tf.TensorSpec(shape=[], dtype=tf.float32),
])
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/396765.html
