From 18aefa4dd0b7b5028445c018c8190a67842cc5a6 Mon Sep 17 00:00:00 2001 From: zxros10 Date: Wed, 23 Sep 2020 09:09:49 +0800 Subject: [PATCH] add pt2tf tool --- pt2tf/README.md | 15 + pt2tf/onnx-tensorflow/.travis.yml | 30 + pt2tf/onnx-tensorflow/LICENSE | 213 + pt2tf/onnx-tensorflow/MANIFEST.in | 3 + pt2tf/onnx-tensorflow/ONNX_VERSION_NUMBER | 1 + pt2tf/onnx-tensorflow/README.md | 101 + pt2tf/onnx-tensorflow/VERSION_NUMBER | 1 + pt2tf/onnx-tensorflow/Versioning.md | 10 + pt2tf/onnx-tensorflow/doc/API.md | 62 + pt2tf/onnx-tensorflow/doc/CLI.md | 54 + pt2tf/onnx-tensorflow/doc/CLI_template.md | 22 + .../doc/IMPLEMENTING_NEW_OP.md | 22 + pt2tf/onnx-tensorflow/doc/support_status.md | 209 + .../doc/support_status_v1_5_0.md | 170 + .../doc/support_status_v1_6_0.md | 203 + pt2tf/onnx-tensorflow/example/onnx_to_tf.py | 7 + pt2tf/onnx-tensorflow/example/relu.py | 11 + .../example/test_model_large_stepping.py | 68 + .../onnx-tensorflow/onnx_tf.egg-info/PKG-INFO | 12 + .../onnx_tf.egg-info/SOURCES.txt | 209 + .../onnx_tf.egg-info/dependency_links.txt | 1 + .../onnx_tf.egg-info/entry_points.txt | 3 + .../onnx_tf.egg-info/not-zip-safe | 1 + .../onnx_tf.egg-info/requires.txt | 2 + .../onnx_tf.egg-info/top_level.txt | 3 + pt2tf/onnx-tensorflow/onnx_tf/__init__.py | 2 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 203 bytes .../__pycache__/backend.cpython-36.pyc | Bin 0 -> 11398 bytes .../__pycache__/backend_rep.cpython-36.pyc | Bin 0 -> 3684 bytes .../onnx_tf/__pycache__/cli.cpython-36.pyc | Bin 0 -> 697 bytes .../__pycache__/converter.cpython-36.pyc | Bin 0 -> 4698 bytes .../__pycache__/pb_wrapper.cpython-36.pyc | Bin 0 -> 15773 bytes .../__pycache__/version.cpython-36.pyc | Bin 0 -> 367 bytes pt2tf/onnx-tensorflow/onnx_tf/backend.py | 352 ++ pt2tf/onnx-tensorflow/onnx_tf/backend_rep.py | 109 + pt2tf/onnx-tensorflow/onnx_tf/cli.py | 24 + .../onnx_tf/common/__init__.py | 196 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 5890 bytes .../__pycache__/attr_converter.cpython-36.pyc | Bin 0 -> 2148 bytes .../attr_translator.cpython-36.pyc | Bin 0 -> 2977 bytes .../__pycache__/data_type.cpython-36.pyc | Bin 0 -> 2088 bytes .../__pycache__/exception.cpython-36.pyc | Bin 0 -> 3370 bytes .../__pycache__/handler_helper.cpython-36.pyc | Bin 0 -> 2298 bytes .../__pycache__/pooling_helper.cpython-36.pyc | Bin 0 -> 7643 bytes .../__pycache__/tf_helper.cpython-36.pyc | Bin 0 -> 1293 bytes .../onnx_tf/common/attr_converter.py | 86 + .../onnx_tf/common/attr_translator.py | 37 + .../onnx_tf/common/data_type.py | 71 + .../onnx_tf/common/exception.py | 73 + .../onnx_tf/common/handler_helper.py | 76 + .../onnx-tensorflow/onnx_tf/common/legacy.py | 21 + .../onnx_tf/common/pooling_helper.py | 263 ++ .../onnx_tf/common/tf_helper.py | 45 + pt2tf/onnx-tensorflow/onnx_tf/converter.py | 138 + pt2tf/onnx-tensorflow/onnx_tf/gen_doc.py | 74 + pt2tf/onnx-tensorflow/onnx_tf/gen_opset.py | 35 + pt2tf/onnx-tensorflow/onnx_tf/gen_status.py | 231 + .../onnx_tf/handlers/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 137 bytes .../backend_handler.cpython-36.pyc | Bin 0 -> 6260 bytes .../__pycache__/handler.cpython-36.pyc | Bin 0 -> 3705 bytes .../onnx_tf/handlers/backend/__init__.py | 7 + .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 391 bytes .../backend/__pycache__/abs.cpython-36.pyc | Bin 0 -> 872 bytes .../backend/__pycache__/acos.cpython-36.pyc | Bin 0 -> 736 bytes .../backend/__pycache__/acosh.cpython-36.pyc | Bin 0 -> 740 bytes .../backend/__pycache__/add.cpython-36.pyc | Bin 0 -> 1023 bytes .../backend/__pycache__/and.cpython-36.pyc | Bin 0 -> 903 bytes .../__pycache__/arg_max.cpython-36.pyc | Bin 0 -> 1676 bytes .../__pycache__/arg_min.cpython-36.pyc | Bin 0 -> 1676 bytes .../backend/__pycache__/asin.cpython-36.pyc | Bin 0 -> 736 bytes .../backend/__pycache__/asinh.cpython-36.pyc | Bin 0 -> 740 bytes .../backend/__pycache__/atan.cpython-36.pyc | Bin 0 -> 736 bytes .../backend/__pycache__/atanh.cpython-36.pyc | Bin 0 -> 740 bytes .../__pycache__/average_pool.cpython-36.pyc | Bin 0 -> 1287 bytes .../batch_normalization.cpython-36.pyc | Bin 0 -> 2545 bytes .../__pycache__/bitshift.cpython-36.pyc | Bin 0 -> 911 bytes .../broadcast_mixin.cpython-36.pyc | Bin 0 -> 1599 bytes .../backend/__pycache__/cast.cpython-36.pyc | Bin 0 -> 1746 bytes .../backend/__pycache__/ceil.cpython-36.pyc | Bin 0 -> 877 bytes .../backend/__pycache__/clip.cpython-36.pyc | Bin 0 -> 2266 bytes .../__pycache__/compress.cpython-36.pyc | Bin 0 -> 1394 bytes .../backend/__pycache__/concat.cpython-36.pyc | Bin 0 -> 1312 bytes .../__pycache__/constant.cpython-36.pyc | Bin 0 -> 2118 bytes .../__pycache__/constant_fill.cpython-36.pyc | Bin 0 -> 1603 bytes .../constant_of_shape.cpython-36.pyc | Bin 0 -> 1070 bytes .../control_flow_mixin.cpython-36.pyc | Bin 0 -> 505 bytes .../backend/__pycache__/conv.cpython-36.pyc | Bin 0 -> 796 bytes .../__pycache__/conv_integer.cpython-36.pyc | Bin 0 -> 2001 bytes .../__pycache__/conv_mixin.cpython-36.pyc | Bin 0 -> 6223 bytes .../__pycache__/conv_transpose.cpython-36.pyc | Bin 0 -> 1271 bytes .../backend/__pycache__/cos.cpython-36.pyc | Bin 0 -> 732 bytes .../backend/__pycache__/cosh.cpython-36.pyc | Bin 0 -> 736 bytes .../backend/__pycache__/cumsum.cpython-36.pyc | Bin 0 -> 1691 bytes .../__pycache__/depth_to_space.cpython-36.pyc | Bin 0 -> 1875 bytes .../dequantize_linear.cpython-36.pyc | Bin 0 -> 1479 bytes .../backend/__pycache__/det.cpython-36.pyc | Bin 0 -> 688 bytes .../dilated_pooling.cpython-36.pyc | Bin 0 -> 16990 bytes .../backend/__pycache__/div.cpython-36.pyc | Bin 0 -> 1023 bytes .../__pycache__/dropout.cpython-36.pyc | Bin 0 -> 1507 bytes .../dynamic_quantize_linear.cpython-36.pyc | Bin 0 -> 1082 bytes .../backend/__pycache__/elu.cpython-36.pyc | Bin 0 -> 1164 bytes .../backend/__pycache__/equal.cpython-36.pyc | Bin 0 -> 1815 bytes .../backend/__pycache__/erf.cpython-36.pyc | Bin 0 -> 676 bytes .../backend/__pycache__/exp.cpython-36.pyc | Bin 0 -> 872 bytes .../backend/__pycache__/expand.cpython-36.pyc | Bin 0 -> 835 bytes .../__pycache__/eye_like.cpython-36.pyc | Bin 0 -> 1379 bytes .../__pycache__/flatten.cpython-36.pyc | Bin 0 -> 1427 bytes .../backend/__pycache__/floor.cpython-36.pyc | Bin 0 -> 882 bytes .../backend/__pycache__/gather.cpython-36.pyc | Bin 0 -> 1414 bytes .../gather_and_scatter_mixin.cpython-36.pyc | Bin 0 -> 3970 bytes .../gather_elements.cpython-36.pyc | Bin 0 -> 1974 bytes .../__pycache__/gather_nd.cpython-36.pyc | Bin 0 -> 1065 bytes .../backend/__pycache__/gemm.cpython-36.pyc | Bin 0 -> 1647 bytes .../global_average_pool.cpython-36.pyc | Bin 0 -> 836 bytes .../__pycache__/global_lp_pool.cpython-36.pyc | Bin 0 -> 1179 bytes .../global_max_pool.cpython-36.pyc | Bin 0 -> 823 bytes .../__pycache__/greater.cpython-36.pyc | Bin 0 -> 1057 bytes .../backend/__pycache__/gru.cpython-36.pyc | Bin 0 -> 6347 bytes .../__pycache__/hard_sigmoid.cpython-36.pyc | Bin 0 -> 1151 bytes .../__pycache__/hardmax.cpython-36.pyc | Bin 0 -> 1345 bytes .../__pycache__/identity.cpython-36.pyc | Bin 0 -> 696 bytes .../backend/__pycache__/if.cpython-36.pyc | Bin 0 -> 2077 bytes .../__pycache__/image_scaler.cpython-36.pyc | Bin 0 -> 859 bytes .../instance_normalization.cpython-36.pyc | Bin 0 -> 1913 bytes .../backend/__pycache__/is_inf.cpython-36.pyc | Bin 0 -> 991 bytes .../backend/__pycache__/is_nan.cpython-36.pyc | Bin 0 -> 686 bytes .../__pycache__/leaky_relu.cpython-36.pyc | Bin 0 -> 1048 bytes .../backend/__pycache__/less.cpython-36.pyc | Bin 0 -> 1039 bytes .../backend/__pycache__/log.cpython-36.pyc | Bin 0 -> 872 bytes .../__pycache__/log_softmax.cpython-36.pyc | Bin 0 -> 1364 bytes .../backend/__pycache__/loop.cpython-36.pyc | Bin 0 -> 4075 bytes .../lp_normalization.cpython-36.pyc | Bin 0 -> 1089 bytes .../__pycache__/lp_pool.cpython-36.pyc | Bin 0 -> 1108 bytes .../backend/__pycache__/lrn.cpython-36.pyc | Bin 0 -> 984 bytes .../backend/__pycache__/lstm.cpython-36.pyc | Bin 0 -> 5820 bytes .../__pycache__/mat_mul.cpython-36.pyc | Bin 0 -> 832 bytes .../mat_mul_integer.cpython-36.pyc | Bin 0 -> 1144 bytes .../__pycache__/math_mixin.cpython-36.pyc | Bin 0 -> 1053 bytes .../backend/__pycache__/max.cpython-36.pyc | Bin 0 -> 1498 bytes .../__pycache__/max_pool.cpython-36.pyc | Bin 0 -> 2178 bytes .../__pycache__/max_unpool.cpython-36.pyc | Bin 0 -> 827 bytes .../backend/__pycache__/mean.cpython-36.pyc | Bin 0 -> 1507 bytes ...mean_variance_normalization.cpython-36.pyc | Bin 0 -> 1462 bytes .../backend/__pycache__/min.cpython-36.pyc | Bin 0 -> 1498 bytes .../backend/__pycache__/mod.cpython-36.pyc | Bin 0 -> 1691 bytes .../backend/__pycache__/mul.cpython-36.pyc | Bin 0 -> 1028 bytes .../backend/__pycache__/neg.cpython-36.pyc | Bin 0 -> 877 bytes .../non_max_suppression.cpython-36.pyc | Bin 0 -> 2481 bytes .../__pycache__/non_zero.cpython-36.pyc | Bin 0 -> 776 bytes .../backend/__pycache__/not.cpython-36.pyc | Bin 0 -> 746 bytes .../backend/__pycache__/onehot.cpython-36.pyc | Bin 0 -> 2740 bytes .../backend/__pycache__/or.cpython-36.pyc | Bin 0 -> 893 bytes .../backend/__pycache__/p_relu.cpython-36.pyc | Bin 0 -> 1566 bytes .../backend/__pycache__/pad.cpython-36.pyc | Bin 0 -> 2367 bytes .../__pycache__/pad_mixin.cpython-36.pyc | Bin 0 -> 763 bytes .../__pycache__/pool_mixin.cpython-36.pyc | Bin 0 -> 3146 bytes .../backend/__pycache__/pow.cpython-36.pyc | Bin 0 -> 884 bytes .../__pycache__/q_linear_conv.cpython-36.pyc | Bin 0 -> 2431 bytes .../q_linear_mat_mul.cpython-36.pyc | Bin 0 -> 1465 bytes .../quantize_linear.cpython-36.pyc | Bin 0 -> 963 bytes .../__pycache__/random_normal.cpython-36.pyc | Bin 0 -> 952 bytes .../random_normal_like.cpython-36.pyc | Bin 0 -> 1050 bytes .../__pycache__/random_uniform.cpython-36.pyc | Bin 0 -> 966 bytes .../random_uniform_like.cpython-36.pyc | Bin 0 -> 1064 bytes .../backend/__pycache__/range.cpython-36.pyc | Bin 0 -> 693 bytes .../__pycache__/reciprocal.cpython-36.pyc | Bin 0 -> 907 bytes .../__pycache__/reduce_l1.cpython-36.pyc | Bin 0 -> 1053 bytes .../__pycache__/reduce_l2.cpython-36.pyc | Bin 0 -> 1053 bytes .../__pycache__/reduce_log_sum.cpython-36.pyc | Bin 0 -> 1207 bytes .../reduce_log_sum_exp.cpython-36.pyc | Bin 0 -> 915 bytes .../__pycache__/reduce_max.cpython-36.pyc | Bin 0 -> 1029 bytes .../__pycache__/reduce_mean.cpython-36.pyc | Bin 0 -> 888 bytes .../__pycache__/reduce_min.cpython-36.pyc | Bin 0 -> 1029 bytes .../__pycache__/reduce_prod.cpython-36.pyc | Bin 0 -> 888 bytes .../__pycache__/reduce_sum.cpython-36.pyc | Bin 0 -> 883 bytes .../reduce_sum_square.cpython-36.pyc | Bin 0 -> 1225 bytes .../backend/__pycache__/relu.cpython-36.pyc | Bin 0 -> 827 bytes .../__pycache__/reshape.cpython-36.pyc | Bin 0 -> 1535 bytes .../backend/__pycache__/resize.cpython-36.pyc | Bin 0 -> 30375 bytes .../reverse_sequence.cpython-36.pyc | Bin 0 -> 975 bytes .../backend/__pycache__/rnn.cpython-36.pyc | Bin 0 -> 4019 bytes .../__pycache__/rnn_mixin.cpython-36.pyc | Bin 0 -> 2295 bytes .../backend/__pycache__/round.cpython-36.pyc | Bin 0 -> 742 bytes .../backend/__pycache__/scan.cpython-36.pyc | Bin 0 -> 1089 bytes .../__pycache__/scan_mixin.cpython-36.pyc | Bin 0 -> 4764 bytes .../__pycache__/scatter.cpython-36.pyc | Bin 0 -> 683 bytes .../scatter_elements.cpython-36.pyc | Bin 0 -> 1907 bytes .../__pycache__/scatter_nd.cpython-36.pyc | Bin 0 -> 1114 bytes .../backend/__pycache__/selu.cpython-36.pyc | Bin 0 -> 1250 bytes .../__pycache__/sequence_at.cpython-36.pyc | Bin 0 -> 1579 bytes .../sequence_construct.cpython-36.pyc | Bin 0 -> 983 bytes .../__pycache__/sequence_empty.cpython-36.pyc | Bin 0 -> 1020 bytes .../__pycache__/sequence_erase.cpython-36.pyc | Bin 0 -> 1687 bytes .../sequence_insert.cpython-36.pyc | Bin 0 -> 1798 bytes .../sequence_length.cpython-36.pyc | Bin 0 -> 762 bytes .../backend/__pycache__/shape.cpython-36.pyc | Bin 0 -> 872 bytes .../backend/__pycache__/shrink.cpython-36.pyc | Bin 0 -> 1191 bytes .../__pycache__/sigmoid.cpython-36.pyc | Bin 0 -> 842 bytes .../backend/__pycache__/sign.cpython-36.pyc | Bin 0 -> 736 bytes .../backend/__pycache__/sin.cpython-36.pyc | Bin 0 -> 732 bytes .../backend/__pycache__/sinh.cpython-36.pyc | Bin 0 -> 736 bytes .../backend/__pycache__/size.cpython-36.pyc | Bin 0 -> 867 bytes .../backend/__pycache__/slice.cpython-36.pyc | Bin 0 -> 2833 bytes .../__pycache__/softmax.cpython-36.pyc | Bin 0 -> 1322 bytes .../__pycache__/softplus.cpython-36.pyc | Bin 0 -> 702 bytes .../__pycache__/softsign.cpython-36.pyc | Bin 0 -> 702 bytes .../__pycache__/space_to_depth.cpython-36.pyc | Bin 0 -> 1223 bytes .../backend/__pycache__/split.cpython-36.pyc | Bin 0 -> 2078 bytes .../backend/__pycache__/sqrt.cpython-36.pyc | Bin 0 -> 877 bytes .../__pycache__/squeeze.cpython-36.pyc | Bin 0 -> 1018 bytes .../backend/__pycache__/sub.cpython-36.pyc | Bin 0 -> 1028 bytes .../backend/__pycache__/sum.cpython-36.pyc | Bin 0 -> 1359 bytes .../backend/__pycache__/tan.cpython-36.pyc | Bin 0 -> 732 bytes .../backend/__pycache__/tanh.cpython-36.pyc | Bin 0 -> 877 bytes .../tfidf_vectorizer.cpython-36.pyc | Bin 0 -> 4052 bytes .../thresholded_relu.cpython-36.pyc | Bin 0 -> 1107 bytes .../backend/__pycache__/tile.cpython-36.pyc | Bin 0 -> 1204 bytes .../backend/__pycache__/top_k.cpython-36.pyc | Bin 0 -> 2891 bytes .../__pycache__/transpose.cpython-36.pyc | Bin 0 -> 700 bytes .../__pycache__/unpool_mixin.cpython-36.pyc | Bin 0 -> 4573 bytes .../__pycache__/unsqueeze.cpython-36.pyc | Bin 0 -> 1253 bytes .../__pycache__/upsample.cpython-36.pyc | Bin 0 -> 2705 bytes .../backend/__pycache__/where.cpython-36.pyc | Bin 0 -> 684 bytes .../backend/__pycache__/xor.cpython-36.pyc | Bin 0 -> 898 bytes .../onnx_tf/handlers/backend/abs.py | 19 + .../onnx_tf/handlers/backend/acos.py | 15 + .../onnx_tf/handlers/backend/acosh.py | 15 + .../onnx_tf/handlers/backend/add.py | 23 + .../onnx_tf/handlers/backend/and.py | 19 + .../onnx_tf/handlers/backend/arg_max.py | 45 + .../onnx_tf/handlers/backend/arg_min.py | 45 + .../onnx_tf/handlers/backend/asin.py | 15 + .../onnx_tf/handlers/backend/asinh.py | 15 + .../onnx_tf/handlers/backend/atan.py | 15 + .../onnx_tf/handlers/backend/atanh.py | 15 + .../onnx_tf/handlers/backend/average_pool.py | 28 + .../handlers/backend/batch_normalization.py | 73 + .../onnx_tf/handlers/backend/bitshift.py | 20 + .../handlers/backend/broadcast_mixin.py | 45 + .../onnx_tf/handlers/backend/cast.py | 44 + .../onnx_tf/handlers/backend/ceil.py | 19 + .../onnx_tf/handlers/backend/clip.py | 70 + .../onnx_tf/handlers/backend/compress.py | 36 + .../onnx_tf/handlers/backend/concat.py | 27 + .../onnx_tf/handlers/backend/constant.py | 74 + .../onnx_tf/handlers/backend/constant_fill.py | 44 + .../handlers/backend/constant_of_shape.py | 37 + .../handlers/backend/control_flow_mixin.py | 9 + .../onnx_tf/handlers/backend/conv.py | 15 + .../onnx_tf/handlers/backend/conv_integer.py | 63 + .../onnx_tf/handlers/backend/conv_mixin.py | 274 ++ .../handlers/backend/conv_transpose.py | 21 + .../onnx_tf/handlers/backend/cos.py | 15 + .../onnx_tf/handlers/backend/cosh.py | 15 + .../onnx_tf/handlers/backend/cumsum.py | 46 + .../handlers/backend/depth_to_space.py | 57 + .../handlers/backend/dequantize_linear.py | 40 + .../onnx_tf/handlers/backend/det.py | 16 + .../handlers/backend/dilated_pooling.py | 702 ++++ .../onnx_tf/handlers/backend/div.py | 23 + .../onnx_tf/handlers/backend/dropout.py | 37 + .../backend/dynamic_quantize_linear.py | 39 + .../onnx_tf/handlers/backend/elu.py | 30 + .../onnx_tf/handlers/backend/equal.py | 41 + .../onnx_tf/handlers/backend/erf.py | 14 + .../onnx_tf/handlers/backend/exp.py | 19 + .../onnx_tf/handlers/backend/expand.py | 22 + .../onnx_tf/handlers/backend/eye_like.py | 41 + .../onnx_tf/handlers/backend/flatten.py | 39 + .../onnx_tf/handlers/backend/floor.py | 19 + .../onnx_tf/handlers/backend/gather.py | 29 + .../backend/gather_and_scatter_mixin.py | 79 + .../handlers/backend/gather_elements.py | 58 + .../onnx_tf/handlers/backend/gather_nd.py | 20 + .../onnx_tf/handlers/backend/gemm.py | 48 + .../handlers/backend/global_average_pool.py | 15 + .../handlers/backend/global_lp_pool.py | 26 + .../handlers/backend/global_max_pool.py | 15 + .../onnx_tf/handlers/backend/greater.py | 23 + .../onnx_tf/handlers/backend/gru.py | 202 + .../onnx_tf/handlers/backend/hard_sigmoid.py | 26 + .../onnx_tf/handlers/backend/hardmax.py | 35 + .../onnx_tf/handlers/backend/identity.py | 14 + .../onnx_tf/handlers/backend/if.py | 51 + .../onnx_tf/handlers/backend/image_scaler.py | 19 + .../backend/instance_normalization.py | 60 + .../onnx_tf/handlers/backend/is_inf.py | 27 + .../onnx_tf/handlers/backend/is_nan.py | 14 + .../onnx_tf/handlers/backend/leaky_relu.py | 22 + .../onnx_tf/handlers/backend/less.py | 23 + .../onnx_tf/handlers/backend/log.py | 19 + .../onnx_tf/handlers/backend/log_softmax.py | 35 + .../onnx_tf/handlers/backend/loop.py | 110 + .../handlers/backend/lp_normalization.py | 33 + .../onnx_tf/handlers/backend/lp_pool.py | 24 + .../onnx_tf/handlers/backend/lrn.py | 29 + .../onnx_tf/handlers/backend/lstm.py | 218 + .../onnx_tf/handlers/backend/mat_mul.py | 18 + .../handlers/backend/mat_mul_integer.py | 38 + .../onnx_tf/handlers/backend/math_mixin.py | 25 + .../onnx_tf/handlers/backend/max.py | 34 + .../onnx_tf/handlers/backend/max_pool.py | 40 + .../onnx_tf/handlers/backend/max_unpool.py | 15 + .../onnx_tf/handlers/backend/mean.py | 34 + .../backend/mean_variance_normalization.py | 47 + .../onnx_tf/handlers/backend/min.py | 34 + .../onnx_tf/handlers/backend/mod.py | 38 + .../onnx_tf/handlers/backend/mul.py | 23 + .../onnx_tf/handlers/backend/neg.py | 19 + .../handlers/backend/non_max_suppression.py | 84 + .../onnx_tf/handlers/backend/non_zero.py | 15 + .../onnx_tf/handlers/backend/not.py | 15 + .../onnx_tf/handlers/backend/onehot.py | 60 + .../onnx_tf/handlers/backend/or.py | 19 + .../onnx_tf/handlers/backend/p_relu.py | 38 + .../onnx_tf/handlers/backend/pad.py | 65 + .../onnx_tf/handlers/backend/pad_mixin.py | 17 + .../onnx_tf/handlers/backend/pool_mixin.py | 125 + .../onnx_tf/handlers/backend/pow.py | 19 + .../onnx_tf/handlers/backend/q_linear_conv.py | 86 + .../handlers/backend/q_linear_mat_mul.py | 57 + .../handlers/backend/quantize_linear.py | 29 + .../onnx_tf/handlers/backend/random_normal.py | 18 + .../handlers/backend/random_normal_like.py | 19 + .../handlers/backend/random_uniform.py | 27 + .../handlers/backend/random_uniform_like.py | 28 + .../onnx_tf/handlers/backend/range.py | 14 + .../onnx_tf/handlers/backend/reciprocal.py | 19 + .../onnx_tf/handlers/backend/reduce_l1.py | 23 + .../onnx_tf/handlers/backend/reduce_l2.py | 23 + .../handlers/backend/reduce_log_sum.py | 24 + .../handlers/backend/reduce_log_sum_exp.py | 19 + .../onnx_tf/handlers/backend/reduce_max.py | 23 + .../onnx_tf/handlers/backend/reduce_mean.py | 19 + .../onnx_tf/handlers/backend/reduce_min.py | 23 + .../onnx_tf/handlers/backend/reduce_prod.py | 19 + .../onnx_tf/handlers/backend/reduce_sum.py | 19 + .../handlers/backend/reduce_sum_square.py | 24 + .../onnx_tf/handlers/backend/relu.py | 18 + .../onnx_tf/handlers/backend/reshape.py | 48 + .../onnx_tf/handlers/backend/resize.py | 274 ++ .../handlers/backend/reverse_sequence.py | 19 + .../onnx_tf/handlers/backend/rnn.py | 161 + .../onnx_tf/handlers/backend/rnn_mixin.py | 86 + .../onnx_tf/handlers/backend/round.py | 15 + .../onnx_tf/handlers/backend/scan.py | 24 + .../onnx_tf/handlers/backend/scan_mixin.py | 188 + .../onnx_tf/handlers/backend/scatter.py | 12 + .../handlers/backend/scatter_elements.py | 64 + .../onnx_tf/handlers/backend/scatter_nd.py | 20 + .../onnx_tf/handlers/backend/selu.py | 33 + .../onnx_tf/handlers/backend/sequence_at.py | 45 + .../handlers/backend/sequence_construct.py | 26 + .../handlers/backend/sequence_empty.py | 20 + .../handlers/backend/sequence_erase.py | 45 + .../handlers/backend/sequence_insert.py | 52 + .../handlers/backend/sequence_length.py | 15 + .../onnx_tf/handlers/backend/shape.py | 18 + .../onnx_tf/handlers/backend/shrink.py | 36 + .../onnx_tf/handlers/backend/sigmoid.py | 18 + .../onnx_tf/handlers/backend/sign.py | 15 + .../onnx_tf/handlers/backend/sin.py | 15 + .../onnx_tf/handlers/backend/sinh.py | 15 + .../onnx_tf/handlers/backend/size.py | 18 + .../onnx_tf/handlers/backend/slice.py | 129 + .../onnx_tf/handlers/backend/softmax.py | 35 + .../onnx_tf/handlers/backend/softplus.py | 14 + .../onnx_tf/handlers/backend/softsign.py | 14 + .../handlers/backend/space_to_depth.py | 29 + .../onnx_tf/handlers/backend/split.py | 56 + .../onnx_tf/handlers/backend/sqrt.py | 19 + .../onnx_tf/handlers/backend/squeeze.py | 22 + .../onnx_tf/handlers/backend/sub.py | 23 + .../onnx_tf/handlers/backend/sum.py | 33 + .../onnx_tf/handlers/backend/tan.py | 15 + .../onnx_tf/handlers/backend/tanh.py | 19 + .../handlers/backend/tfidf_vectorizer.py | 136 + .../handlers/backend/thresholded_relu.py | 23 + .../onnx_tf/handlers/backend/tile.py | 29 + .../onnx_tf/handlers/backend/top_k.py | 80 + .../onnx_tf/handlers/backend/transpose.py | 14 + .../onnx_tf/handlers/backend/unpool_mixin.py | 155 + .../onnx_tf/handlers/backend/unsqueeze.py | 32 + .../onnx_tf/handlers/backend/upsample.py | 87 + .../onnx_tf/handlers/backend/where.py | 14 + .../onnx_tf/handlers/backend/xor.py | 19 + .../onnx_tf/handlers/backend_handler.py | 188 + .../onnx_tf/handlers/handler.py | 114 + .../onnx-tensorflow/onnx_tf/opset_version.py | 256 ++ pt2tf/onnx-tensorflow/onnx_tf/pb_wrapper.py | 461 ++ pt2tf/onnx-tensorflow/onnx_tf/version.py | 7 + pt2tf/onnx-tensorflow/setup.cfg | 3 + pt2tf/onnx-tensorflow/setup.py | 59 + pt2tf/onnx-tensorflow/test/__init__.py | 0 .../onnx-tensorflow/test/backend/__init__.py | 0 .../test/backend/test_dynamic_shape.py | 305 ++ .../test/backend/test_model.py | 157 + .../onnx-tensorflow/test/backend/test_node.py | 3724 +++++++++++++++++ .../test/backend/test_onnx_backend.py | 119 + pt2tf/onnx-tensorflow/test/download_model.sh | 28 + pt2tf/onnx-tensorflow/test/test_cli.py | 79 + pt2tf/onnx-tensorflow/third_party/__init__.py | 0 pt2tf/onnx-tensorflow/third_party/get_info.py | 110 + pt2tf/onnx-tensorflow/util/get_version.py | 18 + pt2tf/pt2onnx.py | 19 + pt2tf/requirements.txt | 30 + 407 files changed, 16211 insertions(+) create mode 100644 pt2tf/README.md create mode 100644 pt2tf/onnx-tensorflow/.travis.yml create mode 100644 pt2tf/onnx-tensorflow/LICENSE create mode 100644 pt2tf/onnx-tensorflow/MANIFEST.in create mode 100644 pt2tf/onnx-tensorflow/ONNX_VERSION_NUMBER create mode 100644 pt2tf/onnx-tensorflow/README.md create mode 100644 pt2tf/onnx-tensorflow/VERSION_NUMBER create mode 100644 pt2tf/onnx-tensorflow/Versioning.md create mode 100644 pt2tf/onnx-tensorflow/doc/API.md create mode 100644 pt2tf/onnx-tensorflow/doc/CLI.md create mode 100644 pt2tf/onnx-tensorflow/doc/CLI_template.md create mode 100644 pt2tf/onnx-tensorflow/doc/IMPLEMENTING_NEW_OP.md create mode 100644 pt2tf/onnx-tensorflow/doc/support_status.md create mode 100644 pt2tf/onnx-tensorflow/doc/support_status_v1_5_0.md create mode 100644 pt2tf/onnx-tensorflow/doc/support_status_v1_6_0.md create mode 100644 pt2tf/onnx-tensorflow/example/onnx_to_tf.py create mode 100644 pt2tf/onnx-tensorflow/example/relu.py create mode 100644 pt2tf/onnx-tensorflow/example/test_model_large_stepping.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf.egg-info/PKG-INFO create mode 100644 pt2tf/onnx-tensorflow/onnx_tf.egg-info/SOURCES.txt create mode 100644 pt2tf/onnx-tensorflow/onnx_tf.egg-info/dependency_links.txt create mode 100644 pt2tf/onnx-tensorflow/onnx_tf.egg-info/entry_points.txt create mode 100644 pt2tf/onnx-tensorflow/onnx_tf.egg-info/not-zip-safe create mode 100644 pt2tf/onnx-tensorflow/onnx_tf.egg-info/requires.txt create mode 100644 pt2tf/onnx-tensorflow/onnx_tf.egg-info/top_level.txt create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/__init__.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/__pycache__/__init__.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/__pycache__/backend.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/__pycache__/backend_rep.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/__pycache__/cli.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/__pycache__/converter.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/__pycache__/pb_wrapper.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/__pycache__/version.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/backend.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/backend_rep.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/cli.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/__init__.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/__init__.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/attr_converter.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/attr_translator.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/data_type.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/exception.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/handler_helper.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/pooling_helper.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/tf_helper.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/attr_converter.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/attr_translator.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/data_type.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/exception.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/handler_helper.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/legacy.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/pooling_helper.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/common/tf_helper.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/converter.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/gen_doc.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/gen_opset.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/gen_status.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/__init__.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/__pycache__/__init__.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/__pycache__/backend_handler.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/__pycache__/handler.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__init__.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/__init__.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/abs.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/acos.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/acosh.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/add.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/and.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/arg_max.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/arg_min.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/asin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/asinh.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/atan.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/atanh.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/average_pool.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/batch_normalization.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/bitshift.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/broadcast_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cast.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/ceil.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/clip.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/compress.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/concat.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/constant.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/constant_fill.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/constant_of_shape.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/control_flow_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv_integer.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv_transpose.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cos.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cosh.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cumsum.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/depth_to_space.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dequantize_linear.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/det.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dilated_pooling.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/div.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dropout.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dynamic_quantize_linear.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/elu.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/equal.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/erf.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/exp.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/expand.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/eye_like.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/flatten.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/floor.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gather.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gather_and_scatter_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gather_elements.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gather_nd.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gemm.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/global_average_pool.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/global_lp_pool.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/global_max_pool.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/greater.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gru.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/hard_sigmoid.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/hardmax.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/identity.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/if.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/image_scaler.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/instance_normalization.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/is_inf.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/is_nan.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/leaky_relu.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/less.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/log.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/log_softmax.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/loop.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lp_normalization.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lp_pool.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lrn.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lstm.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mat_mul.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mat_mul_integer.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/math_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/max.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/max_pool.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/max_unpool.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mean.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mean_variance_normalization.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/min.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mod.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mul.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/neg.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/non_max_suppression.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/non_zero.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/not.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/onehot.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/or.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/p_relu.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pad.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pad_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pool_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pow.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/q_linear_conv.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/q_linear_mat_mul.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/quantize_linear.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/random_normal.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/random_normal_like.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/random_uniform.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/random_uniform_like.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/range.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reciprocal.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_l1.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_l2.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_log_sum.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_log_sum_exp.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_max.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_mean.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_min.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_prod.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_sum.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_sum_square.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/relu.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reshape.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/resize.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reverse_sequence.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/rnn.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/rnn_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/round.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/scan.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/scan_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/scatter.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/scatter_elements.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/scatter_nd.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/selu.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_at.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_construct.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_empty.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_erase.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_insert.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_length.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/shape.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/shrink.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sigmoid.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sign.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sinh.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/size.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/slice.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/softmax.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/softplus.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/softsign.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/space_to_depth.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/split.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sqrt.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/squeeze.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sub.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sum.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/tan.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/tanh.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/tfidf_vectorizer.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/thresholded_relu.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/tile.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/top_k.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/transpose.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/unpool_mixin.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/unsqueeze.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/upsample.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/where.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/xor.cpython-36.pyc create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/abs.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/acos.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/acosh.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/add.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/and.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/arg_max.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/arg_min.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/asin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/asinh.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/atan.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/atanh.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/average_pool.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/batch_normalization.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/bitshift.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/broadcast_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cast.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/ceil.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/clip.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/compress.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/concat.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant_fill.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant_of_shape.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/control_flow_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_integer.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_transpose.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cos.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cosh.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cumsum.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/depth_to_space.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dequantize_linear.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/det.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dilated_pooling.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/div.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dropout.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dynamic_quantize_linear.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/elu.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/equal.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/erf.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/exp.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/expand.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/eye_like.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/flatten.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/floor.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_and_scatter_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_elements.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_nd.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gemm.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_average_pool.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_lp_pool.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_max_pool.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/greater.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gru.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/hard_sigmoid.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/hardmax.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/identity.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/if.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/image_scaler.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/instance_normalization.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/is_inf.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/is_nan.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/leaky_relu.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/less.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/log.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/log_softmax.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/loop.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lp_normalization.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lp_pool.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lrn.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lstm.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mat_mul.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mat_mul_integer.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/math_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max_pool.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max_unpool.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mean.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mean_variance_normalization.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/min.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mod.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mul.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/neg.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/non_max_suppression.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/non_zero.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/not.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/onehot.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/or.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/p_relu.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pad.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pad_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pool_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pow.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/q_linear_conv.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/q_linear_mat_mul.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/quantize_linear.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_normal.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_normal_like.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_uniform.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_uniform_like.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/range.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reciprocal.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_l1.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_l2.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_log_sum.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_log_sum_exp.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_max.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_mean.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_min.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_prod.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_sum.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_sum_square.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/relu.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reshape.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/resize.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reverse_sequence.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/rnn.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/rnn_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/round.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scan.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scan_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter_elements.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter_nd.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/selu.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_at.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_construct.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_empty.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_erase.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_insert.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_length.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/shape.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/shrink.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sigmoid.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sign.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sinh.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/size.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/slice.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softmax.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softplus.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softsign.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/space_to_depth.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/split.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sqrt.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/squeeze.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sub.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sum.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tan.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tanh.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tfidf_vectorizer.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/thresholded_relu.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tile.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/top_k.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/transpose.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/unpool_mixin.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/unsqueeze.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/upsample.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/where.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/xor.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/backend_handler.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/handlers/handler.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/opset_version.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/pb_wrapper.py create mode 100644 pt2tf/onnx-tensorflow/onnx_tf/version.py create mode 100644 pt2tf/onnx-tensorflow/setup.cfg create mode 100644 pt2tf/onnx-tensorflow/setup.py create mode 100644 pt2tf/onnx-tensorflow/test/__init__.py create mode 100644 pt2tf/onnx-tensorflow/test/backend/__init__.py create mode 100644 pt2tf/onnx-tensorflow/test/backend/test_dynamic_shape.py create mode 100644 pt2tf/onnx-tensorflow/test/backend/test_model.py create mode 100644 pt2tf/onnx-tensorflow/test/backend/test_node.py create mode 100644 pt2tf/onnx-tensorflow/test/backend/test_onnx_backend.py create mode 100644 pt2tf/onnx-tensorflow/test/download_model.sh create mode 100644 pt2tf/onnx-tensorflow/test/test_cli.py create mode 100644 pt2tf/onnx-tensorflow/third_party/__init__.py create mode 100644 pt2tf/onnx-tensorflow/third_party/get_info.py create mode 100644 pt2tf/onnx-tensorflow/util/get_version.py create mode 100644 pt2tf/pt2onnx.py create mode 100644 pt2tf/requirements.txt diff --git a/pt2tf/README.md b/pt2tf/README.md new file mode 100644 index 0000000..9462537 --- /dev/null +++ b/pt2tf/README.md @@ -0,0 +1,15 @@ +#1 建立虚拟环境 +$ virtualenv .venv + +#2 激活虚拟环境 +$ source .venv/bin/activate + +#3 安装依赖包 +$ pip install -r requirements.txt +$ pip install -e onnx-tensorflow + +#4 生成onnx模型 +$ python pt2onnx.py + +#5 生成pb模型 +$ onnx-tf convert -i efficientnet-b3.onnx -o efficientnet-b3.pb diff --git a/pt2tf/onnx-tensorflow/.travis.yml b/pt2tf/onnx-tensorflow/.travis.yml new file mode 100644 index 0000000..b647b39 --- /dev/null +++ b/pt2tf/onnx-tensorflow/.travis.yml @@ -0,0 +1,30 @@ +os: linux +arch: amd64 +dist: bionic +language: python +python: 3.6 +cache: pip + +# Required +# - ONNX 1.6 (Opset 11), TensorFlow 1.15.0, Sep 2019 +# - ONNX 1.6 (Opset 11), TensorFlow 1.15.3, May 2020 +# Optional +# - ONNX 1.7 (Opset 12), TensorFlow 1.15.3, May 2020 + +env: + - ONNX_PIP=onnx==1.6.0 TF_PIP=tensorflow==1.15.0 + - ONNX_PIP=onnx==1.6.0 TF_PIP=tensorflow==1.15.3 + - ONNX_PIP=onnx==1.7.0 TF_PIP=tensorflow==1.15.3 + +jobs: + fast_finish: true + # Be aware when updating the dependency versions. + # Envs below must match *exactly* an env from above, + # otherwise an env failure will fail the overall build. + allow_failures: + - env: ONNX_PIP=onnx==1.7.0 TF_PIP=tensorflow==1.15.3 + +before_install: pip install -U setuptools +install: pip install $ONNX_PIP $TF_PIP +before_script: pip install -e . +script: python -m unittest discover test -v diff --git a/pt2tf/onnx-tensorflow/LICENSE b/pt2tf/onnx-tensorflow/LICENSE new file mode 100644 index 0000000..6598f66 --- /dev/null +++ b/pt2tf/onnx-tensorflow/LICENSE @@ -0,0 +1,213 @@ +ONNX-Tensorflow Converter + +Copyright (c) International Business Machines Corporation 2017, 2018 +Copyright (c) LeapMind Inc. 2018 + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, and + distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by the + copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all other + entities that control, are controlled by, or are under common control with + that entity. For the purposes of this definition, "control" means (i) the + power, direct or indirect, to cause the direction or management of such + entity, whether by contract or otherwise, or (ii) ownership of + fifty percent (50%) or more of the outstanding shares, or (iii) beneficial + ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity exercising + permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation source, + and configuration files. + + "Object" form shall mean any form resulting from mechanical transformation + or translation of a Source form, including but not limited to compiled + object code, generated documentation, and conversions to + other media types. + + "Work" shall mean the work of authorship, whether in Source or Object + form, made available under the License, as indicated by a copyright notice + that is included in or attached to the work (an example is provided in the + Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object form, + that is based on (or derived from) the Work and for which the editorial + revisions, annotations, elaborations, or other modifications represent, + as a whole, an original work of authorship. For the purposes of this + License, Derivative Works shall not include works that remain separable + from, or merely link (or bind by name) to the interfaces of, the Work and + Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including the original + version of the Work and any modifications or additions to that Work or + Derivative Works thereof, that is intentionally submitted to Licensor for + inclusion in the Work by the copyright owner or by an individual or + Legal Entity authorized to submit on behalf of the copyright owner. + For the purposes of this definition, "submitted" means any form of + electronic, verbal, or written communication sent to the Licensor or its + representatives, including but not limited to communication on electronic + mailing lists, source code control systems, and issue tracking systems + that are managed by, or on behalf of, the Licensor for the purpose of + discussing and improving the Work, but excluding communication that is + conspicuously marked or otherwise designated in writing by the copyright + owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity on + behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. + + Subject to the terms and conditions of this License, each Contributor + hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable copyright license to reproduce, prepare + Derivative Works of, publicly display, publicly perform, sublicense, + and distribute the Work and such Derivative Works in + Source or Object form. + + 3. Grant of Patent License. + + Subject to the terms and conditions of this License, each Contributor + hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, + royalty-free, irrevocable (except as stated in this section) patent + license to make, have made, use, offer to sell, sell, import, and + otherwise transfer the Work, where such license applies only to those + patent claims licensable by such Contributor that are necessarily + infringed by their Contribution(s) alone or by combination of their + Contribution(s) with the Work to which such Contribution(s) was submitted. + If You institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work or a + Contribution incorporated within the Work constitutes direct or + contributory patent infringement, then any patent licenses granted to + You under this License for that Work shall terminate as of the date such + litigation is filed. + + 4. Redistribution. + + You may reproduce and distribute copies of the Work or Derivative Works + thereof in any medium, with or without modifications, and in Source or + Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works a + copy of this License; and + + 2. You must cause any modified files to carry prominent notices stating + that You changed the files; and + + 3. You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices from + the Source form of the Work, excluding those notices that do not pertain + to any part of the Derivative Works; and + + 4. If the Work includes a "NOTICE" text file as part of its distribution, + then any Derivative Works that You distribute must include a readable copy + of the attribution notices contained within such NOTICE file, excluding + those notices that do not pertain to any part of the Derivative Works, + in at least one of the following places: within a NOTICE text file + distributed as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, within a + display generated by the Derivative Works, if and wherever such + third-party notices normally appear. The contents of the NOTICE file are + for informational purposes only and do not modify the License. + You may add Your own attribution notices within Derivative Works that You + distribute, alongside or as an addendum to the NOTICE text from the Work, + provided that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and may + provide additional or different license terms and conditions for use, + reproduction, or distribution of Your modifications, or for any such + Derivative Works as a whole, provided Your use, reproduction, and + distribution of the Work otherwise complies with the conditions + stated in this License. + + 5. Submission of Contributions. + + Unless You explicitly state otherwise, any Contribution intentionally + submitted for inclusion in the Work by You to the Licensor shall be under + the terms and conditions of this License, without any additional + terms or conditions. Notwithstanding the above, nothing herein shall + supersede or modify the terms of any separate license agreement you may + have executed with Licensor regarding such Contributions. + + 6. Trademarks. + + This License does not grant permission to use the trade names, trademarks, + service marks, or product names of the Licensor, except as required for + reasonable and customary use in describing the origin of the Work and + reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. + + Unless required by applicable law or agreed to in writing, Licensor + provides the Work (and each Contributor provides its Contributions) + on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + either express or implied, including, without limitation, any warranties + or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS + FOR A PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any risks + associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. + + In no event and under no legal theory, whether in tort + (including negligence), contract, or otherwise, unless required by + applicable law (such as deliberate and grossly negligent acts) or agreed + to in writing, shall any Contributor be liable to You for damages, + including any direct, indirect, special, incidental, or consequential + damages of any character arising as a result of this License or out of + the use or inability to use the Work (including but not limited to damages + for loss of goodwill, work stoppage, computer failure or malfunction, + or any and all other commercial damages or losses), even if such + Contributor has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. + + While redistributing the Work or Derivative Works thereof, You may choose + to offer, and charge a fee for, acceptance of support, warranty, + indemnity, or other liability obligations and/or rights consistent with + this License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf of any + other Contributor, and only if You agree to indemnify, defend, and hold + each Contributor harmless for any liability incurred by, or claims + asserted against, such Contributor by reason of your accepting any such + warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work + + To apply the Apache License to your work, attach the following boilerplate + notice, with the fields enclosed by brackets "[]" replaced with your own + identifying information. (Don't include the brackets!) The text should be + enclosed in the appropriate comment syntax for the file format. We also + recommend that a file or class name and description of purpose be included + on the same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 ONNX-TF Authors + + 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. + diff --git a/pt2tf/onnx-tensorflow/MANIFEST.in b/pt2tf/onnx-tensorflow/MANIFEST.in new file mode 100644 index 0000000..ea4e78d --- /dev/null +++ b/pt2tf/onnx-tensorflow/MANIFEST.in @@ -0,0 +1,3 @@ +include LICENSE +include VERSION_NUMBER +include ONNX_VERSION_NUMBER diff --git a/pt2tf/onnx-tensorflow/ONNX_VERSION_NUMBER b/pt2tf/onnx-tensorflow/ONNX_VERSION_NUMBER new file mode 100644 index 0000000..dc1e644 --- /dev/null +++ b/pt2tf/onnx-tensorflow/ONNX_VERSION_NUMBER @@ -0,0 +1 @@ +1.6.0 diff --git a/pt2tf/onnx-tensorflow/README.md b/pt2tf/onnx-tensorflow/README.md new file mode 100644 index 0000000..c909dd0 --- /dev/null +++ b/pt2tf/onnx-tensorflow/README.md @@ -0,0 +1,101 @@ +# Tensorflow Backend for ONNX +[![Build Status](https://travis-ci.org/onnx/onnx-tensorflow.svg?branch=tf-1.x)](https://travis-ci.org/onnx/onnx-tensorflow) + +## To convert models from ONNX to Tensorflow: + +### Use CLI: + +[Command Line Interface Documentation](https://github.com/onnx/onnx-tensorflow/blob/master/doc/CLI.md) + +From ONNX to Tensorflow: `onnx-tf convert -i /path/to/input.onnx -o /path/to/output.pb` + +### Convert programmatically: + +[From ONNX to Tensorflow](https://github.com/onnx/onnx-tensorflow/blob/master/example/onnx_to_tf.py) + +### Migrating from `onnx-tf` to `tf-onnx`: +We have joined force with Microsoft to co-develop ONNX Tensorflow frontend. +For current onnx-tf frontend users, please migrate to use tf-onnx (https://github.com/onnx/tensorflow-onnx) where our code had been merged into. + +## ONNX model inference with Tensorflow backend: +``` +import onnx +from onnx_tf.backend import prepare + +onnx_model = onnx.load("input_path") # load onnx model +output = prepare(onnx_model).run(input) # run the loaded model +``` + +## More tutorials: +[Running an ONNX model using Tensorflow](https://github.com/onnx/tutorials/blob/master/tutorials/OnnxTensorflowImport.ipynb) + +## Production Installation: +ONNX-TF requires ONNX (Open Neural Network Exchange) as an external dependency, for any issues related to ONNX installation, we refer our users to [ONNX project repository](https://github.com/onnx/onnx) for documentation and help. Notably, please ensure that protoc is available if you plan to install ONNX via pip. + +The specific ONNX release version that we support in the master branch of ONNX-TF can be found [here](https://github.com/onnx/onnx-tensorflow/blob/master/ONNX_VERSION_NUMBER). This information about ONNX version requirement is automatically encoded in `setup.py`, therefore users needn't worry about ONNX version requirement when installing ONNX-TF. + +Because users often have their own preferences for which variant of Tensorflow to install (i.e., a GPU version instead of a CPU version), we do not explicitly require tensorflow in the installation script. It is therefore users' responsibility to ensure that the proper variant of Tensorflow is available to ONNX-TF. Moreover, we require Tensorflow version == 1.15.0. + +To install the latest version of ONNX-TF v1.6.0 +- Run `git clone https://github.com/onnx/onnx-tensorflow.git && cd onnx-tensorflow`. +- Run `git checkout v1.6.0-tf-1.15`. +- Run `pip install -e .`. + +## Development: + +### Coverage Status: +[ONNX-Tensorflow Op Coverage Status](https://github.com/onnx/onnx-tensorflow/blob/tf-1.x/doc/support_status.md) + +### API: +[ONNX-Tensorflow API](https://github.com/onnx/onnx-tensorflow/blob/tf-1.x/doc/API.md) + +### Installation: +- Install ONNX master branch from source. +- Install Tensorflow 1.15.0. (For Tensorflow 2.x support please refer [here](https://github.com/onnx/onnx-tensorflow/blob/master/README.md/).) +- Run `git clone https://github.com/onnx/onnx-tensorflow.git && cd onnx-tensorflow`. +- Run `git checkout tf-1.x`. +- Run `pip install -e .`. + +### Folder Structure: +- __onnx_tf__ main source code file. +- __test__ test files. + +### Code Standard: +- Format code: +``` +pip install yapf +yapf -rip --style="{based_on_style: google, indent_width: 2}" $FilePath$ +``` +- Install pylint: +``` +pip install pylint +wget -O /tmp/pylintrc https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/tools/ci_build/pylintrc +``` +- Check format: +``` +pylint --rcfile=/tmp/pylintrc myfile.py +``` + +### Documentation Standard: +http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html + +### To test: +To perfom unit tests, run `python -m unittest discover test`. +Testing requires significant hardware resources, but nonetheless, we highly recommend that users run through the complete test suite before deploying onnx-tf. The complete test suite typically takes between 15 and 45 minutes to complete, depending on hardware configurations. + +PS. Please ensure your code is backward compatible with older version of ONNX. You can easily test it by running the following [docker container](https://hub.docker.com/r/winnietsang/onnx-tensorflow) with your code. If you don't have Docker installed yet, please follow this link to install [Docker](https://docs.docker.com/install/) on your environment. +``` +sudo docker pull winnietsang/onnx-tensorflow:onnx1.7.0-tf1.15 +sudo docker run -it --name=YOUR-CONTAINER-NAME winnietsang/onnx-tensorflow:onnx1.7.0-tf1.15 /bin/bash +git clone https://github.com/YOUR-USERNAME/onnx-tensorflow.git +cd onnx-tensorflow +git checkout -b YOUR-BRANCH --track remotes/origin/YOUR-BRANCH +pip3 install -e . +python3 -m unittest discover test +``` + +#### Test Help: +https://docs.python.org/2/library/unittest.html + +#### Note: +Branch tf-1.x is for users who cannot upgrade to Tensorflow 2.x yet. This branch will only support up to ONNX OpSet 12 operators. If any user needs to use operators in OpSet 13 or above, please upgrade Tensoflow to 2.x and use the master branch of this repo. By January 1st, 2021 this branch will switch to maintenance mode only, no new development will be added into this branch from then on. diff --git a/pt2tf/onnx-tensorflow/VERSION_NUMBER b/pt2tf/onnx-tensorflow/VERSION_NUMBER new file mode 100644 index 0000000..dc1e644 --- /dev/null +++ b/pt2tf/onnx-tensorflow/VERSION_NUMBER @@ -0,0 +1 @@ +1.6.0 diff --git a/pt2tf/onnx-tensorflow/Versioning.md b/pt2tf/onnx-tensorflow/Versioning.md new file mode 100644 index 0000000..b60e8d5 --- /dev/null +++ b/pt2tf/onnx-tensorflow/Versioning.md @@ -0,0 +1,10 @@ +## Released Versions + +These are the supported ONNX versions and TensorFlow versions for each release. + +ONNX-TensorFlow version|ONNX version|TensorFlow version +-----------------------|------------|------------------ +1.2.1|1.1.2 (opset 4)|1.5 +1.3.0|1.3.0 (opset 8)|1.13.1 +1.5.0|1.5.0 (opset 10)|1.15.0 +1.6.0|1.6.0 (opset 11)|1.15.0 diff --git a/pt2tf/onnx-tensorflow/doc/API.md b/pt2tf/onnx-tensorflow/doc/API.md new file mode 100644 index 0000000..7063643 --- /dev/null +++ b/pt2tf/onnx-tensorflow/doc/API.md @@ -0,0 +1,62 @@ +ONNX-Tensorflow API +====== + +#### `onnx_tf.backend.prepare` + +
+ Prepare an ONNX model for Tensorflow Backend. + + +This function converts an ONNX model to an internel representation +of the computational graph called TensorflowRep and returns +the converted representation. + +
+ + + +_params_: + +`model` : The ONNX model to be converted. + + +`device` : The device to execute this model on. + + +`strict` : Whether to enforce semantic equivalence between the original model +and the converted tensorflow model, defaults to True (yes, enforce semantic equivalence). +Changing to False is strongly discouraged. +Currently, the strict flag only affects the behavior of MaxPool and AveragePool ops. + + +`logging_level` : The logging level, default is INFO. Change it to DEBUG +to see more conversion details or to WARNING to see less + + +_returns_: + +A TensorflowRep class object representing the ONNX model + +#### `onnx_tf.backend_rep.TensorflowRep.export_graph` + +
+ Export backend representation to a Tensorflow proto file. + + +This function obtains the graph proto corresponding to the ONNX +model associated with the backend representation and serializes +to a protobuf file. + +
+ + + +_params_: + +`path` : The path to the output TF protobuf file. + + +_returns_: + +none. + diff --git a/pt2tf/onnx-tensorflow/doc/CLI.md b/pt2tf/onnx-tensorflow/doc/CLI.md new file mode 100644 index 0000000..1a7c57a --- /dev/null +++ b/pt2tf/onnx-tensorflow/doc/CLI.md @@ -0,0 +1,54 @@ +ONNX-Tensorflow Command Line Interface +====== + +## Available commands: +- convert + +More information: `onnx-tf -h` +``` +usage: onnx-tf [-h] {convert} + +ONNX-Tensorflow Command Line Interface + +positional arguments: + {convert} Available commands. + +optional arguments: + -h, --help show this help message and exit +``` + +## Usage: + +### Convert: + +#### From ONNX to Tensorflow: +`onnx-tf convert -i /path/to/input.onnx -o /path/to/output.pb` + +More information: `onnx-tf convert -h` +``` +usage: onnx-tf [-h] --infile INFILE --outfile OUTFILE [--device DEVICE] + [--strict STRICT] [--logging_level LOGGING_LEVEL] + +This is the converter for converting protocol buffer between tf and onnx. + +optional arguments: + -h, --help show this help message and exit + --infile INFILE, -i INFILE + Input file path. + --outfile OUTFILE, -o OUTFILE + Output file path. + +backend arguments (onnx -> tf): + --device DEVICE The device to execute this model on. (from + onnx_tf.backend.prepare) + --strict STRICT Whether to enforce semantic equivalence between the + original model and the converted tensorflow model, + defaults to True (yes, enforce semantic equivalence). + Changing to False is strongly discouraged. Currently, + the strict flag only affects the behavior of MaxPool + and AveragePool ops. (from onnx_tf.backend.prepare) + --logging_level LOGGING_LEVEL + The logging level, default is INFO. Change it to DEBUG + to see more conversion details or to WARNING to see + less (from onnx_tf.backend.prepare) +``` diff --git a/pt2tf/onnx-tensorflow/doc/CLI_template.md b/pt2tf/onnx-tensorflow/doc/CLI_template.md new file mode 100644 index 0000000..dd5e54f --- /dev/null +++ b/pt2tf/onnx-tensorflow/doc/CLI_template.md @@ -0,0 +1,22 @@ +ONNX-Tensorflow Command Line Interface +====== + +## Available commands: +- convert + +More information: `onnx-tf -h` +``` +{onnx-tf -h} +``` + +## Usage: + +### Convert: + +#### From ONNX to Tensorflow: +`onnx-tf convert -i /path/to/input.onnx -o /path/to/output.pb` + +More information: `onnx-tf convert -h` +``` +{onnx-tf convert -h} +``` diff --git a/pt2tf/onnx-tensorflow/doc/IMPLEMENTING_NEW_OP.md b/pt2tf/onnx-tensorflow/doc/IMPLEMENTING_NEW_OP.md new file mode 100644 index 0000000..6491727 --- /dev/null +++ b/pt2tf/onnx-tensorflow/doc/IMPLEMENTING_NEW_OP.md @@ -0,0 +1,22 @@ +How to implement new op +====== + +When you get `{} op is not implemented`, you can follow next steps to implement. +Customize op can also be implemented in similar way. + +### Backend + +1. Verify the latest master version of ONNX is installed on your environment +2. Find specification from [onnx/Operators](https://github.com/onnx/onnx/blob/master/docs/Operators.md). +3. Implement the handler. All inputs and attrs could get from step 2. + ``` + - add handler to /onnx_tf/handlers/backend/ + - in the new handler define a classmethod called version_{version} + + * version is the number of since version, which can get from operator's specification + ``` +4. From within the `onnx_tf` directory, run `gen_opset.py`. +5. From within the `onnx_tf` directory, run `gen_status.py`. +6. From within the `onnx_tf` directory, run `gen_doc.py` if there is any update to CLI or API. +7. Verify the operator's test cases in `test/backend/test_onnx_backend.py` all pass. +8. Add any additional test cases to `test/backend/test_node.py`. diff --git a/pt2tf/onnx-tensorflow/doc/support_status.md b/pt2tf/onnx-tensorflow/doc/support_status.md new file mode 100644 index 0000000..e3024c9 --- /dev/null +++ b/pt2tf/onnx-tensorflow/doc/support_status.md @@ -0,0 +1,209 @@ +# ONNX-Tensorflow Support Status +||| +|-:|:-| +|ONNX-Tensorflow Version|Master ( commit id: 8fea59a976e2d65eab2ab021864e2cab038bb7d5 )| +|ONNX Version|v1.7.0| +|Tensorflow Version|v1.15.0| + +Notes: +* Values that are new or updated from a previous opset version are in bold. +* -: not defined in corresponding ONNX opset version +* \*: the operator is deprecated +* :small_red_triangle:: not supported yet +* :small_orange_diamond:: partially supported +* the rest are all supported + +||||||||||||||| +|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +|**ONNX Operator**|**Opset 1**|**Opset 2**|**Opset 3**|**Opset 4**|**Opset 5**|**Opset 6**|**Opset 7**|**Opset 8**|**Opset 9**|**Opset 10**|**Opset 11**|**Opset 12**|**ONNX Operator**| +|Abs|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Abs| +|Acos|-|-|-|-|-|-|**7**|7|7|7|7|7|Acos| +|Acosh|-|-|-|-|-|-|-|-|**9**|9|9|9|Acosh| +|Add|**1**|1|1|1|1|**6**|**7**|7|7|7|7|7|Add| +|And|**1**|1|1|1|1|1|**7**|7|7|7|7|7|And| +|ArgMax|**1**|1|1|1|1|1|1|1|1|1|**11**|**12**|ArgMax| +|ArgMin|**1**|1|1|1|1|1|1|1|1|1|**11**|**12**|ArgMin| +|Asin|-|-|-|-|-|-|**7**|7|7|7|7|7|Asin| +|Asinh|-|-|-|-|-|-|-|-|**9**|9|9|9|Asinh| +|Atan|-|-|-|-|-|-|**7**|7|7|7|7|7|Atan| +|Atanh|-|-|-|-|-|-|-|-|**9**|9|9|9|Atanh| +|AveragePool|**1**|1|1|1|1|1|**7**|7|7|**10**|**11**|11|AveragePool| +|BatchNormalization|**1**|1|1|1|1|**6**|**7**|7|**9**|9|9|9|BatchNormalization| +|BitShift|-|-|-|-|-|-|-|-|-|-|**11**|11|BitShift| +|Cast|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**6**:small_orange_diamond:|6:small_orange_diamond:|6:small_orange_diamond:|**9**:small_orange_diamond:|9:small_orange_diamond:|9:small_orange_diamond:|9:small_orange_diamond:|Cast| +|Ceil|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Ceil| +|Celu|-|-|-|-|-|-|-|-|-|-|-|**12**:small_red_triangle:|Celu| +|Clip|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**6**:small_orange_diamond:|6:small_orange_diamond:|6:small_orange_diamond:|6:small_orange_diamond:|6:small_orange_diamond:|**11**:small_orange_diamond:|**12**:small_orange_diamond:|Clip| +|Compress|-|-|-|-|-|-|-|-|**9**|9|**11**|11|Compress| +|Concat|**1**|1|1|**4**|4|4|4|4|4|4|**11**|11|Concat| +|ConcatFromSequence|-|-|-|-|-|-|-|-|-|-|**11**:small_red_triangle:|11:small_red_triangle:|ConcatFromSequence| +|Constant|**1**|1|1|1|1|1|1|1|**9**|9|**11**|**12**|Constant| +|ConstantOfShape|-|-|-|-|-|-|-|-|**9**|9|9|9|ConstantOfShape| +|Conv|**1**|1|1|1|1|1|1|1|1|1|**11**|11|Conv| +|ConvInteger|-|-|-|-|-|-|-|-|-|**10**|10|10|ConvInteger| +|ConvTranspose|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**11**:small_orange_diamond:|11:small_orange_diamond:|ConvTranspose| +|Cos|-|-|-|-|-|-|**7**|7|7|7|7|7|Cos| +|Cosh|-|-|-|-|-|-|-|-|**9**|9|9|9|Cosh| +|CumSum|-|-|-|-|-|-|-|-|-|-|**11**:small_orange_diamond:|11:small_orange_diamond:|CumSum| +|DepthToSpace|**1**|1|1|1|1|1|1|1|1|1|**11**|11|DepthToSpace| +|DequantizeLinear|-|-|-|-|-|-|-|-|-|**10**|10|10|DequantizeLinear| +|Det|-|-|-|-|-|-|-|-|-|-|**11**|11|Det| +|Div|**1**|1|1|1|1|**6**|**7**|7|7|7|7|7|Div| +|Dropout|**1**|1|1|1|1|**6**|**7**|7|7|**10**|10|**12**:small_red_triangle:|Dropout| +|DynamicQuantizeLinear|-|-|-|-|-|-|-|-|-|-|**11**|11|DynamicQuantizeLinear| +|Einsum|-|-|-|-|-|-|-|-|-|-|-|**12**:small_red_triangle:|Einsum| +|Elu|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Elu| +|Equal|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|**11**:small_orange_diamond:|11:small_orange_diamond:|Equal| +|Erf|-|-|-|-|-|-|-|-|**9**|9|9|9|Erf| +|Exp|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Exp| +|Expand|-|-|-|-|-|-|-|**8**|8|8|8|8|Expand| +|EyeLike|-|-|-|-|-|-|-|-|**9**|9|9|9|EyeLike| +|Flatten|**1**|1|1|1|1|1|1|1|**9**|9|**11**|11|Flatten| +|Floor|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Floor| +|GRU|**1**:small_orange_diamond:|1:small_orange_diamond:|**3**:small_orange_diamond:|3:small_orange_diamond:|3:small_orange_diamond:|3:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|GRU| +|Gather|**1**|1|1|1|1|1|1|1|1|1|**11**|11|Gather| +|GatherElements|-|-|-|-|-|-|-|-|-|-|**11**|11|GatherElements| +|GatherND|-|-|-|-|-|-|-|-|-|-|**11**|**12**:small_red_triangle:|GatherND| +|Gemm|**1**|1|1|1|1|**6**|**7**|7|**9**|9|**11**|11|Gemm| +|GlobalAveragePool|**1**|1|1|1|1|1|1|1|1|1|1|1|GlobalAveragePool| +|GlobalLpPool|**1**|**2**|2|2|2|2|2|2|2|2|2|2|GlobalLpPool| +|GlobalMaxPool|**1**|1|1|1|1|1|1|1|1|1|1|1|GlobalMaxPool| +|Greater|**1**|1|1|1|1|1|**7**|7|**9**|9|9|9|Greater| +|GreaterOrEqual|-|-|-|-|-|-|-|-|-|-|-|**12**:small_red_triangle:|GreaterOrEqual| +|HardSigmoid|**1**|1|1|1|1|**6**|6|6|6|6|6|6|HardSigmoid| +|Hardmax|**1**|1|1|1|1|1|1|1|1|1|**11**|11|Hardmax| +|Identity|**1**|1|1|1|1|1|1|1|1|1|1|1|Identity| +|If|**1**|1|1|1|1|1|1|1|1|1|**11**|11|If| +|InstanceNormalization|**1**|1|1|1|1|**6**|6|6|6|6|6|6|InstanceNormalization| +|IsInf|-|-|-|-|-|-|-|-|-|**10**|10|10|IsInf| +|IsNaN|-|-|-|-|-|-|-|-|**9**|9|9|9|IsNaN| +|LRN|**1**|1|1|1|1|1|1|1|1|1|1|1|LRN| +|LSTM|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|LSTM| +|LeakyRelu|**1**|1|1|1|1|**6**|6|6|6|6|6|6|LeakyRelu| +|Less|**1**|1|1|1|1|1|**7**|7|**9**|9|9|9|Less| +|LessOrEqual|-|-|-|-|-|-|-|-|-|-|-|**12**:small_red_triangle:|LessOrEqual| +|Log|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Log| +|LogSoftmax|**1**|1|1|1|1|1|1|1|1|1|**11**|11|LogSoftmax| +|Loop|**1**|1|1|1|1|1|1|1|1|1|**11**|11|Loop| +|LpNormalization|**1**|1|1|1|1|1|1|1|1|1|1|1|LpNormalization| +|LpPool|**1**|**2**|2|2|2|2|2|2|2|2|**11**|11|LpPool| +|MatMul|**1**|1|1|1|1|1|1|1|**9**|9|9|9|MatMul| +|MatMulInteger|-|-|-|-|-|-|-|-|-|**10**|10|10|MatMulInteger| +|Max|**1**|1|1|1|1|**6**|6|**8**|8|8|8|**12**:small_red_triangle:|Max| +|MaxPool|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**8**:small_orange_diamond:|8:small_orange_diamond:|**10**:small_orange_diamond:|**11**:small_orange_diamond:|**12**:small_orange_diamond:|MaxPool| +|MaxRoiPool|**1**:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|MaxRoiPool| +|MaxUnpool|-|-|-|-|-|-|-|-|**9**|9|**11**|11|MaxUnpool| +|Mean|**1**|1|1|1|1|**6**|6|**8**|8|8|8|8|Mean| +|MeanVarianceNormalization|-|-|-|-|-|-|-|-|**9**|9|9|9|MeanVarianceNormalization| +|Min|**1**|1|1|1|1|**6**|6|**8**|8|8|8|**12**:small_red_triangle:|Min| +|Mod|-|-|-|-|-|-|-|-|-|**10**:small_orange_diamond:|10:small_orange_diamond:|10:small_orange_diamond:|Mod| +|Mul|**1**|1|1|1|1|**6**|**7**|7|7|7|7|7|Mul| +|Multinomial|-|-|-|-|-|-|**7**:small_red_triangle:|7:small_red_triangle:|7:small_red_triangle:|7:small_red_triangle:|7:small_red_triangle:|7:small_red_triangle:|Multinomial| +|Neg|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Neg| +|NegativeLogLikelihoodLoss|-|-|-|-|-|-|-|-|-|-|-|**12**:small_red_triangle:|NegativeLogLikelihoodLoss| +|NonMaxSuppression|-|-|-|-|-|-|-|-|-|**10**|**11**|11|NonMaxSuppression| +|NonZero|-|-|-|-|-|-|-|-|**9**|9|9|9|NonZero| +|Not|**1**|1|1|1|1|1|1|1|1|1|1|1|Not| +|OneHot|-|-|-|-|-|-|-|-|**9**:small_orange_diamond:|9:small_orange_diamond:|**11**:small_orange_diamond:|11:small_orange_diamond:|OneHot| +|Or|**1**|1|1|1|1|1|**7**|7|7|7|7|7|Or| +|PRelu|**1**|1|1|1|1|**6**|**7**|7|**9**|9|9|9|PRelu| +|Pad|**1**|**2**|2|2|2|2|2|2|2|2|**11**|11|Pad| +|Pow|**1**|1|1|1|1|1|**7**|7|7|7|7|**12**:small_red_triangle:|Pow| +|QLinearConv|-|-|-|-|-|-|-|-|-|**10**|10|10|QLinearConv| +|QLinearMatMul|-|-|-|-|-|-|-|-|-|**10**|10|10|QLinearMatMul| +|QuantizeLinear|-|-|-|-|-|-|-|-|-|**10**|10|10|QuantizeLinear| +|RNN|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|RNN| +|RandomNormal|**1**|1|1|1|1|1|1|1|1|1|1|1|RandomNormal| +|RandomNormalLike|**1**|1|1|1|1|1|1|1|1|1|1|1|RandomNormalLike| +|RandomUniform|**1**|1|1|1|1|1|1|1|1|1|1|1|RandomUniform| +|RandomUniformLike|**1**|1|1|1|1|1|1|1|1|1|1|1|RandomUniformLike| +|Range|-|-|-|-|-|-|-|-|-|-|**11**|11|Range| +|Reciprocal|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Reciprocal| +|ReduceL1|**1**|1|1|1|1|1|1|1|1|1|**11**|11|ReduceL1| +|ReduceL2|**1**|1|1|1|1|1|1|1|1|1|**11**|11|ReduceL2| +|ReduceLogSum|**1**|1|1|1|1|1|1|1|1|1|**11**|11|ReduceLogSum| +|ReduceLogSumExp|**1**|1|1|1|1|1|1|1|1|1|**11**|11|ReduceLogSumExp| +|ReduceMax|**1**|1|1|1|1|1|1|1|1|1|**11**|**12**|ReduceMax| +|ReduceMean|**1**|1|1|1|1|1|1|1|1|1|**11**|11|ReduceMean| +|ReduceMin|**1**|1|1|1|1|1|1|1|1|1|**11**|**12**|ReduceMin| +|ReduceProd|**1**|1|1|1|1|1|1|1|1|1|**11**|11|ReduceProd| +|ReduceSum|**1**|1|1|1|1|1|1|1|1|1|**11**|11|ReduceSum| +|ReduceSumSquare|**1**|1|1|1|1|1|1|1|1|1|**11**|11|ReduceSumSquare| +|Relu|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Relu| +|Reshape|**1**|1|1|1|**5**|5|5|5|5|5|5|5|Reshape| +|Resize|-|-|-|-|-|-|-|-|-|**10**:small_orange_diamond:|**11**:small_orange_diamond:|11:small_orange_diamond:|Resize| +|ReverseSequence|-|-|-|-|-|-|-|-|-|**10**|10|10|ReverseSequence| +|RoiAlign|-|-|-|-|-|-|-|-|-|**10**:small_red_triangle:|10:small_red_triangle:|10:small_red_triangle:|RoiAlign| +|Round|-|-|-|-|-|-|-|-|-|-|**11**|11|Round| +|Scan|-|-|-|-|-|-|-|**8**|**9**|9|**11**|11|Scan| +|Scatter|-|-|-|-|-|-|-|-|**9**|9|**11**\*|11\*|Scatter| +|ScatterElements|-|-|-|-|-|-|-|-|-|-|**11**|11|ScatterElements| +|ScatterND|-|-|-|-|-|-|-|-|-|-|**11**|11|ScatterND| +|Selu|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Selu| +|SequenceAt|-|-|-|-|-|-|-|-|-|-|**11**|11|SequenceAt| +|SequenceConstruct|-|-|-|-|-|-|-|-|-|-|**11**|11|SequenceConstruct| +|SequenceEmpty|-|-|-|-|-|-|-|-|-|-|**11**|11|SequenceEmpty| +|SequenceErase|-|-|-|-|-|-|-|-|-|-|**11**|11|SequenceErase| +|SequenceInsert|-|-|-|-|-|-|-|-|-|-|**11**|11|SequenceInsert| +|SequenceLength|-|-|-|-|-|-|-|-|-|-|**11**|11|SequenceLength| +|Shape|**1**|1|1|1|1|1|1|1|1|1|1|1|Shape| +|Shrink|-|-|-|-|-|-|-|-|**9**|9|9|9|Shrink| +|Sigmoid|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Sigmoid| +|Sign|-|-|-|-|-|-|-|-|**9**|9|9|9|Sign| +|Sin|-|-|-|-|-|-|**7**|7|7|7|7|7|Sin| +|Sinh|-|-|-|-|-|-|-|-|**9**|9|9|9|Sinh| +|Size|**1**|1|1|1|1|1|1|1|1|1|1|1|Size| +|Slice|**1**|1|1|1|1|1|1|1|1|**10**|**11**|11|Slice| +|Softmax|**1**|1|1|1|1|1|1|1|1|1|**11**|11|Softmax| +|SoftmaxCrossEntropyLoss|-|-|-|-|-|-|-|-|-|-|-|**12**:small_red_triangle:|SoftmaxCrossEntropyLoss| +|Softplus|**1**|1|1|1|1|1|1|1|1|1|1|1|Softplus| +|Softsign|**1**|1|1|1|1|1|1|1|1|1|1|1|Softsign| +|SpaceToDepth|**1**|1|1|1|1|1|1|1|1|1|1|1|SpaceToDepth| +|Split|**1**|**2**|2|2|2|2|2|2|2|2|**11**|11|Split| +|SplitToSequence|-|-|-|-|-|-|-|-|-|-|**11**:small_red_triangle:|11:small_red_triangle:|SplitToSequence| +|Sqrt|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Sqrt| +|Squeeze|**1**|1|1|1|1|1|1|1|1|1|**11**|11|Squeeze| +|StringNormalizer|-|-|-|-|-|-|-|-|-|**10**:small_red_triangle:|10:small_red_triangle:|10:small_red_triangle:|StringNormalizer| +|Sub|**1**|1|1|1|1|**6**|**7**|7|7|7|7|7|Sub| +|Sum|**1**|1|1|1|1|**6**|6|**8**|8|8|8|8|Sum| +|Tan|-|-|-|-|-|-|**7**|7|7|7|7|7|Tan| +|Tanh|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Tanh| +|TfIdfVectorizer|-|-|-|-|-|-|-|-|**9**|9|9|9|TfIdfVectorizer| +|ThresholdedRelu|-|-|-|-|-|-|-|-|-|**10**|10|10|ThresholdedRelu| +|Tile|**1**|1|1|1|1|**6**|6|6|6|6|6|6|Tile| +|TopK|**1**|1|1|1|1|1|1|1|1|**10**|**11**|11|TopK| +|Transpose|**1**|1|1|1|1|1|1|1|1|1|1|1|Transpose| +|Unique|-|-|-|-|-|-|-|-|-|-|**11**:small_red_triangle:|11:small_red_triangle:|Unique| +|Unsqueeze|**1**|1|1|1|1|1|1|1|1|1|**11**|11|Unsqueeze| +|Upsample|**1**:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|**7**:small_orange_diamond:|7:small_orange_diamond:|**9**:small_orange_diamond:|**10**\*|10\*|10\*|Upsample| +|Where|-|-|-|-|-|-|-|-|**9**|9|9|9|Where| +|Xor|**1**|1|1|1|1|1|**7**|7|7|7|7|7|Xor| + +ONNX-TF Supported Operators / ONNX Operators: 144 / 162 + +Notes: +1. Cast: Cast string to float32/float64/int32/int64 are not supported in Tensorflow. +2. Clip: Clip input in uint64 is not supported in Tensorflow. +3. ConvTranspose: ConvTranspose with dilations != 1, or transposed convolution for 4D or higher are not supported in Tensorflow. +4. CumSum: CumSum inputs in uint32/uint64 are not supported in Tensorflow. +5. Equal: Equal inputs in uint16/uint32/uint64 are not supported in Tensorflow. +6. GRU: GRU with clip or GRU with linear_before_reset, or GRU not using sigmoid for z and r, or GRU using Elu as the activation function with alpha != 1, or GRU using HardSigmoid as the activation function with alpha != 0.2 or beta != 0.5 are not supported in TensorFlow. +7. LSTM: LSTM not using sigmoid for `f`, or LSTM not using the same activation for `g` and `h` are not supported in Tensorflow. +8. MaxPool: MaxPoolWithArgmax with pad is None or incompatible mode, or MaxPoolWithArgmax with 4D or higher input, orMaxPoolWithArgmax with column major are not supported in Tensorflow. +9. Mod: Mod Dividend or Divisor in int8/int16/uint8/uint16/uint32/uint64 are not supported in Tensorflow. +10. OneHot: OneHot indices in uint16/uint32/uint64/int8/int16/float16/float/double, or OneHot depth in uint8/uint16/uint32/uint64/int8/int16/int64/float16/float/double are not supported in Tensorflow. +11. RNN: RNN with clip is not supported in Tensorflow. +12. Resize: Resize required 4D input in Tensorflow. For opset 11, only the following attributes and inputs conbination are supported in Tensorflow: + 1. mode=nearest, coordinate_transformation_mode=align_corners, nearest_mode=round_prefer_ceil, can use scales(*) or sizes. + 2. mode=nearest, coordinate_transformation_mode=asymmetric, nearest_mode=floor, can use scales(*) or sizes. + 3. mode=nearest, coordinate_transformation_mode=tf_half_pixel_for_nn, nearest_mode=floor, can use scales(*) or sizes. + 4. mode=linear, coordinate_transformation_mode=align_corners, can use scales(*) or sizes. + 5. mode=linear, coordinate_transformation_mode=asymmetric, can use scales(*) or sizes. + 6. mode=linear, coordinate_transformation_mode=half_pixel, can use scales(*) or sizes. + 7. mode=cubic, coordinate_transformation_mode=align_corners, cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) or sizes. + 8. mode=cubic, coordinate_transformation_mode=asymmetric, cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) or sizes. + 9. mode=cubic, coordinate_transformation_mode=half_pixel, cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) or sizes. + 10. mode=nearest, coordinate_transformation_mode=tf_crop_and_resize, extrapolation_value=any_float_value, nearest_mode=round_prefer_ceil, can use scales or sizes. + 11. mode=linear, coordinate_transformation_mode=tf_crop_and_resize, extrapolation_value=any_float_value, can use scales or sizes. + - Note (*): The accuracy of your model will go down, if the height and the width of the new sizes(scales * origial sizes) are not in whole numbers. +13. Upsample: Upsample required 4D input in Tensorflow. diff --git a/pt2tf/onnx-tensorflow/doc/support_status_v1_5_0.md b/pt2tf/onnx-tensorflow/doc/support_status_v1_5_0.md new file mode 100644 index 0000000..d3b2bd6 --- /dev/null +++ b/pt2tf/onnx-tensorflow/doc/support_status_v1_5_0.md @@ -0,0 +1,170 @@ +# ONNX-Tensorflow Support Status +||| +|-:|:-| +|ONNX-Tensorflow Version|v1.5.0| +|ONNX Version|v1.5.0| +|Tensorflow Version|v1.15.0| + +Notes: +* Values that are new or updated from a previous opset version are in bold. +* -: not defined in corresponding ONNX opset version +* \*: the operator is deprecated +* :small_red_triangle:: not supported yet +* :small_orange_diamond:: partially supported +* the rest are all supported + +|||||||||||| +|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +|**ONNX Operator**|**Opset 1**|**Opset 2**|**Opset 3**|**Opset 4**|**Opset 5**|**Opset 6**|**Opset 7**|**Opset 8**|**Opset 9**|**Opset 10**| +|Abs|**1**|1|1|1|1|**6**|6|6|6|6| +|Acos|-|-|-|-|-|-|**7**|7|7|7| +|Acosh|-|-|-|-|-|-|-|-|**9**|9| +|Add|**1**|1|1|1|1|**6**|**7**|7|7|7| +|And|**1**|1|1|1|1|1|**7**|7|7|7| +|ArgMax|**1**|1|1|1|1|1|1|1|1|1| +|ArgMin|**1**|1|1|1|1|1|1|1|1|1| +|Asin|-|-|-|-|-|-|**7**|7|7|7| +|Asinh|-|-|-|-|-|-|-|-|**9**|9| +|Atan|-|-|-|-|-|-|**7**|7|7|7| +|Atanh|-|-|-|-|-|-|-|-|**9**|9| +|AveragePool|**1**|1|1|1|1|1|**7**|7|7|**10**| +|BatchNormalization|**1**|1|1|1|1|**6**|**7**|7|**9**|9| +|Cast|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**6**:small_orange_diamond:|6:small_orange_diamond:|6:small_orange_diamond:|**9**:small_orange_diamond:|9:small_orange_diamond:| +|Ceil|**1**|1|1|1|1|**6**|6|6|6|6| +|Clip|**1**|1|1|1|1|**6**|6|6|6|6| +|Compress|-|-|-|-|-|-|-|-|**9**|9| +|Concat|**1**|1|1|**4**|4|4|4|4|4|4| +|Constant|**1**|1|1|1|1|1|1|1|**9**|9| +|ConstantOfShape|-|-|-|-|-|-|-|-|**9**|9| +|Conv|**1**|1|1|1|1|1|1|1|1|1| +|ConvInteger|-|-|-|-|-|-|-|-|-|**10**| +|ConvTranspose|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:| +|Cos|-|-|-|-|-|-|**7**|7|7|7| +|Cosh|-|-|-|-|-|-|-|-|**9**|9| +|DepthToSpace|**1**|1|1|1|1|1|1|1|1|1| +|DequantizeLinear|-|-|-|-|-|-|-|-|-|**10**| +|Div|**1**|1|1|1|1|**6**|**7**|7|7|7| +|Dropout|**1**|1|1|1|1|**6**|**7**|7|7|**10**| +|Elu|**1**|1|1|1|1|**6**|6|6|6|6| +|Equal|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:| +|Erf|-|-|-|-|-|-|-|-|**9**|9| +|Exp|**1**|1|1|1|1|**6**|6|6|6|6| +|Expand|-|-|-|-|-|-|-|**8**|8|8| +|EyeLike|-|-|-|-|-|-|-|-|**9**|9| +|Flatten|**1**|1|1|1|1|1|1|1|**9**|9| +|Floor|**1**|1|1|1|1|**6**|6|6|6|6| +|GRU|**1**:small_orange_diamond:|1:small_orange_diamond:|**3**:small_orange_diamond:|3:small_orange_diamond:|3:small_orange_diamond:|3:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:| +|Gather|**1**|1|1|1|1|1|1|1|1|1| +|Gemm|**1**|1|1|1|1|**6**|**7**|7|**9**|9| +|GlobalAveragePool|**1**|1|1|1|1|1|1|1|1|1| +|GlobalLpPool|**1**|**2**|2|2|2|2|2|2|2|2| +|GlobalMaxPool|**1**|1|1|1|1|1|1|1|1|1| +|Greater|**1**|1|1|1|1|1|**7**|7|**9**|9| +|HardSigmoid|**1**|1|1|1|1|**6**|6|6|6|6| +|Hardmax|**1**|1|1|1|1|1|1|1|1|1| +|Identity|**1**|1|1|1|1|1|1|1|1|1| +|If|**1**:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:| +|InstanceNormalization|**1**|1|1|1|1|**6**|6|6|6|6| +|IsInf|-|-|-|-|-|-|-|-|-|**10**| +|IsNaN|-|-|-|-|-|-|-|-|**9**|9| +|LRN|**1**|1|1|1|1|1|1|1|1|1| +|LSTM|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:| +|LeakyRelu|**1**|1|1|1|1|**6**|6|6|6|6| +|Less|**1**|1|1|1|1|1|**7**|7|**9**|9| +|Log|**1**|1|1|1|1|**6**|6|6|6|6| +|LogSoftmax|**1**|1|1|1|1|1|1|1|1|1| +|Loop|**1**:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:| +|LpNormalization|**1**|1|1|1|1|1|1|1|1|1| +|LpPool|**1**:small_red_triangle:|**2**:small_red_triangle:|2:small_red_triangle:|2:small_red_triangle:|2:small_red_triangle:|2:small_red_triangle:|2:small_red_triangle:|2:small_red_triangle:|2:small_red_triangle:|2:small_red_triangle:| +|MatMul|**1**|1|1|1|1|1|1|1|**9**|9| +|MatMulInteger|-|-|-|-|-|-|-|-|-|**10**| +|Max|**1**|1|1|1|1|**6**|6|**8**|8|8| +|MaxPool|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**8**:small_orange_diamond:|8:small_orange_diamond:|**10**:small_orange_diamond:| +|MaxRoiPool|**1**:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:| +|MaxUnpool|-|-|-|-|-|-|-|-|**9**|9| +|Mean|**1**|1|1|1|1|**6**|6|**8**|8|8| +|MeanVarianceNormalization|-|-|-|-|-|-|-|-|**9**|9| +|Min|**1**|1|1|1|1|**6**|6|**8**|8|8| +|Mod|-|-|-|-|-|-|-|-|-|**10**:small_orange_diamond:| +|Mul|**1**|1|1|1|1|**6**|**7**|7|7|7| +|Multinomial|-|-|-|-|-|-|**7**:small_red_triangle:|7:small_red_triangle:|7:small_red_triangle:|7:small_red_triangle:| +|Neg|**1**|1|1|1|1|**6**|6|6|6|6| +|NonMaxSuppression|-|-|-|-|-|-|-|-|-|**10**| +|NonZero|-|-|-|-|-|-|-|-|**9**|9| +|Not|**1**|1|1|1|1|1|1|1|1|1| +|OneHot|-|-|-|-|-|-|-|-|**9**:small_orange_diamond:|9:small_orange_diamond:| +|Or|**1**|1|1|1|1|1|**7**|7|7|7| +|PRelu|**1**|1|1|1|1|**6**|**7**|7|**9**|9| +|Pad|**1**|**2**|2|2|2|2|2|2|2|2| +|Pow|**1**|1|1|1|1|1|**7**|7|7|7| +|QLinearConv|-|-|-|-|-|-|-|-|-|**10**| +|QLinearMatMul|-|-|-|-|-|-|-|-|-|**10**| +|QuantizeLinear|-|-|-|-|-|-|-|-|-|**10**| +|RNN|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:| +|RandomNormal|**1**|1|1|1|1|1|1|1|1|1| +|RandomNormalLike|**1**|1|1|1|1|1|1|1|1|1| +|RandomUniform|**1**|1|1|1|1|1|1|1|1|1| +|RandomUniformLike|**1**|1|1|1|1|1|1|1|1|1| +|Reciprocal|**1**|1|1|1|1|**6**|6|6|6|6| +|ReduceL1|**1**|1|1|1|1|1|1|1|1|1| +|ReduceL2|**1**|1|1|1|1|1|1|1|1|1| +|ReduceLogSum|**1**|1|1|1|1|1|1|1|1|1| +|ReduceLogSumExp|**1**|1|1|1|1|1|1|1|1|1| +|ReduceMax|**1**|1|1|1|1|1|1|1|1|1| +|ReduceMean|**1**|1|1|1|1|1|1|1|1|1| +|ReduceMin|**1**|1|1|1|1|1|1|1|1|1| +|ReduceProd|**1**|1|1|1|1|1|1|1|1|1| +|ReduceSum|**1**|1|1|1|1|1|1|1|1|1| +|ReduceSumSquare|**1**|1|1|1|1|1|1|1|1|1| +|Relu|**1**|1|1|1|1|**6**|6|6|6|6| +|Reshape|**1**|1|1|1|**5**|5|5|5|5|5| +|Resize|-|-|-|-|-|-|-|-|-|**10**:small_orange_diamond:| +|ReverseSequence|-|-|-|-|-|-|-|-|-|**10**| +|RoiAlign|-|-|-|-|-|-|-|-|-|**10**:small_red_triangle:| +|Scan|-|-|-|-|-|-|-|**8**|**9**|9| +|Scatter|-|-|-|-|-|-|-|-|**9**|9| +|Selu|**1**|1|1|1|1|**6**|6|6|6|6| +|Shape|**1**|1|1|1|1|1|1|1|1|1| +|Shrink|-|-|-|-|-|-|-|-|**9**|9| +|Sigmoid|**1**|1|1|1|1|**6**|6|6|6|6| +|Sign|-|-|-|-|-|-|-|-|**9**|9| +|Sin|-|-|-|-|-|-|**7**|7|7|7| +|Sinh|-|-|-|-|-|-|-|-|**9**|9| +|Size|**1**|1|1|1|1|1|1|1|1|1| +|Slice|**1**|1|1|1|1|1|1|1|1|**10**| +|Softmax|**1**|1|1|1|1|1|1|1|1|1| +|Softplus|**1**|1|1|1|1|1|1|1|1|1| +|Softsign|**1**|1|1|1|1|1|1|1|1|1| +|SpaceToDepth|**1**|1|1|1|1|1|1|1|1|1| +|Split|**1**|**2**|2|2|2|2|2|2|2|2| +|Sqrt|**1**|1|1|1|1|**6**|6|6|6|6| +|Squeeze|**1**|1|1|1|1|1|1|1|1|1| +|StringNormalizer|-|-|-|-|-|-|-|-|-|**10**:small_red_triangle:| +|Sub|**1**|1|1|1|1|**6**|**7**|7|7|7| +|Sum|**1**|1|1|1|1|**6**|6|**8**|8|8| +|Tan|-|-|-|-|-|-|**7**|7|7|7| +|Tanh|**1**|1|1|1|1|**6**|6|6|6|6| +|TfIdfVectorizer|-|-|-|-|-|-|-|-|**9**|9| +|ThresholdedRelu|-|-|-|-|-|-|-|-|-|**10**| +|Tile|**1**|1|1|1|1|**6**|6|6|6|6| +|TopK|**1**|1|1|1|1|1|1|1|1|**10**| +|Transpose|**1**|1|1|1|1|1|1|1|1|1| +|Unsqueeze|**1**|1|1|1|1|1|1|1|1|1| +|Upsample|**1**:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|**7**:small_orange_diamond:|7:small_orange_diamond:|**9**:small_orange_diamond:|**10**\*| +|Where|-|-|-|-|-|-|-|-|**9**|9| +|Xor|**1**|1|1|1|1|1|**7**|7|7|7| + +ONNX-TF Supported Operators / ONNX Operators: 130 / 137 + +Notes: +1. Cast: Cast string to float32/float64/int32/int64 are not supported in Tensorflow. +2. ConvTranspose: ConvTranspose with dilations != 1, or transposed convolution for 4D or higher are not supported in Tensorflow. +3. Equal: Equal inputs in uint16/uint32/uint64 are not supported in Tensorflow. +4. GRU: GRU with clip or GRU with linear_before_reset, or GRU not using sigmoid for z and r, or GRU using Elu as the activation function with alpha != 1, or GRU using HardSigmoid as the activation function with alpha != 0.2 or beta != 0.5 are not supported in TensorFlow. +5. LSTM: LSTM not using sigmoid for `f`, or LSTM not using the same activation for `g` and `h` are not supported in Tensorflow. +6. MaxPool: MaxPoolWithArgmax with pad is None or incompatible mode, or MaxPoolWithArgmax with 4D or higher input, orMaxPoolWithArgmax with column major are not supported in Tensorflow. +7. Mod: Mod Dividend or Divisor in int8/int16/uint8/uint16/uint32/uint64 are not supported in Tensorflow. +8. OneHot: OneHot indices in uint16/uint32/uint64/int8/int16/float16/float/double, or OneHot depth in uint8/uint16/uint32/uint64/int8/int16/int64/float16/float/double are not supported in Tensorflow. +9. RNN: RNN with clip is not supported in Tensorflow. +10. Resize: Resize required 4D input in Tensorflow. +11. Upsample: Upsample required 4D input in Tensorflow. diff --git a/pt2tf/onnx-tensorflow/doc/support_status_v1_6_0.md b/pt2tf/onnx-tensorflow/doc/support_status_v1_6_0.md new file mode 100644 index 0000000..ffb4dfb --- /dev/null +++ b/pt2tf/onnx-tensorflow/doc/support_status_v1_6_0.md @@ -0,0 +1,203 @@ +# ONNX-Tensorflow Support Status +||| +|-:|:-| +|ONNX-Tensorflow Version|v1.6.0| +|ONNX Version|v1.6.0| +|Tensorflow Version|v1.15.0| + +Notes: +* Values that are new or updated from a previous opset version are in bold. +* -: not defined in corresponding ONNX opset version +* \*: the operator is deprecated +* :small_red_triangle:: not supported yet +* :small_orange_diamond:: partially supported +* the rest are all supported + +|||||||||||||| +|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +|**ONNX Operator**|**Opset 1**|**Opset 2**|**Opset 3**|**Opset 4**|**Opset 5**|**Opset 6**|**Opset 7**|**Opset 8**|**Opset 9**|**Opset 10**|**Opset 11**|**ONNX Operator**| +|Abs|**1**|1|1|1|1|**6**|6|6|6|6|6|Abs| +|Acos|-|-|-|-|-|-|**7**|7|7|7|7|Acos| +|Acosh|-|-|-|-|-|-|-|-|**9**|9|9|Acosh| +|Add|**1**|1|1|1|1|**6**|**7**|7|7|7|7|Add| +|And|**1**|1|1|1|1|1|**7**|7|7|7|7|And| +|ArgMax|**1**|1|1|1|1|1|1|1|1|1|**11**|ArgMax| +|ArgMin|**1**|1|1|1|1|1|1|1|1|1|**11**|ArgMin| +|Asin|-|-|-|-|-|-|**7**|7|7|7|7|Asin| +|Asinh|-|-|-|-|-|-|-|-|**9**|9|9|Asinh| +|Atan|-|-|-|-|-|-|**7**|7|7|7|7|Atan| +|Atanh|-|-|-|-|-|-|-|-|**9**|9|9|Atanh| +|AveragePool|**1**|1|1|1|1|1|**7**|7|7|**10**|**11**|AveragePool| +|BatchNormalization|**1**|1|1|1|1|**6**|**7**|7|**9**|9|9|BatchNormalization| +|BitShift|-|-|-|-|-|-|-|-|-|-|**11**|BitShift| +|Cast|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**6**:small_orange_diamond:|6:small_orange_diamond:|6:small_orange_diamond:|**9**:small_orange_diamond:|9:small_orange_diamond:|9:small_orange_diamond:|Cast| +|Ceil|**1**|1|1|1|1|**6**|6|6|6|6|6|Ceil| +|Clip|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**6**:small_orange_diamond:|6:small_orange_diamond:|6:small_orange_diamond:|6:small_orange_diamond:|6:small_orange_diamond:|**11**:small_orange_diamond:|Clip| +|Compress|-|-|-|-|-|-|-|-|**9**|9|**11**|Compress| +|Concat|**1**|1|1|**4**|4|4|4|4|4|4|**11**|Concat| +|ConcatFromSequence|-|-|-|-|-|-|-|-|-|-|**11**:small_red_triangle:|ConcatFromSequence| +|Constant|**1**|1|1|1|1|1|1|1|**9**|9|**11**|Constant| +|ConstantOfShape|-|-|-|-|-|-|-|-|**9**|9|9|ConstantOfShape| +|Conv|**1**|1|1|1|1|1|1|1|1|1|**11**|Conv| +|ConvInteger|-|-|-|-|-|-|-|-|-|**10**|10|ConvInteger| +|ConvTranspose|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**11**:small_orange_diamond:|ConvTranspose| +|Cos|-|-|-|-|-|-|**7**|7|7|7|7|Cos| +|Cosh|-|-|-|-|-|-|-|-|**9**|9|9|Cosh| +|CumSum|-|-|-|-|-|-|-|-|-|-|**11**:small_orange_diamond:|CumSum| +|DepthToSpace|**1**|1|1|1|1|1|1|1|1|1|**11**|DepthToSpace| +|DequantizeLinear|-|-|-|-|-|-|-|-|-|**10**|10|DequantizeLinear| +|Det|-|-|-|-|-|-|-|-|-|-|**11**|Det| +|Div|**1**|1|1|1|1|**6**|**7**|7|7|7|7|Div| +|Dropout|**1**|1|1|1|1|**6**|**7**|7|7|**10**|10|Dropout| +|DynamicQuantizeLinear|-|-|-|-|-|-|-|-|-|-|**11**|DynamicQuantizeLinear| +|Elu|**1**|1|1|1|1|**6**|6|6|6|6|6|Elu| +|Equal|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|**11**:small_orange_diamond:|Equal| +|Erf|-|-|-|-|-|-|-|-|**9**|9|9|Erf| +|Exp|**1**|1|1|1|1|**6**|6|6|6|6|6|Exp| +|Expand|-|-|-|-|-|-|-|**8**|8|8|8|Expand| +|EyeLike|-|-|-|-|-|-|-|-|**9**|9|9|EyeLike| +|Flatten|**1**|1|1|1|1|1|1|1|**9**|9|**11**|Flatten| +|Floor|**1**|1|1|1|1|**6**|6|6|6|6|6|Floor| +|GRU|**1**:small_orange_diamond:|1:small_orange_diamond:|**3**:small_orange_diamond:|3:small_orange_diamond:|3:small_orange_diamond:|3:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|GRU| +|Gather|**1**|1|1|1|1|1|1|1|1|1|**11**|Gather| +|GatherElements|-|-|-|-|-|-|-|-|-|-|**11**|GatherElements| +|GatherND|-|-|-|-|-|-|-|-|-|-|**11**|GatherND| +|Gemm|**1**|1|1|1|1|**6**|**7**|7|**9**|9|**11**|Gemm| +|GlobalAveragePool|**1**|1|1|1|1|1|1|1|1|1|1|GlobalAveragePool| +|GlobalLpPool|**1**|**2**|2|2|2|2|2|2|2|2|2|GlobalLpPool| +|GlobalMaxPool|**1**|1|1|1|1|1|1|1|1|1|1|GlobalMaxPool| +|Greater|**1**|1|1|1|1|1|**7**|7|**9**|9|9|Greater| +|HardSigmoid|**1**|1|1|1|1|**6**|6|6|6|6|6|HardSigmoid| +|Hardmax|**1**|1|1|1|1|1|1|1|1|1|**11**|Hardmax| +|Identity|**1**|1|1|1|1|1|1|1|1|1|1|Identity| +|If|**1**|1|1|1|1|1|1|1|1|1|**11**|If| +|InstanceNormalization|**1**|1|1|1|1|**6**|6|6|6|6|6|InstanceNormalization| +|IsInf|-|-|-|-|-|-|-|-|-|**10**|10|IsInf| +|IsNaN|-|-|-|-|-|-|-|-|**9**|9|9|IsNaN| +|LRN|**1**|1|1|1|1|1|1|1|1|1|1|LRN| +|LSTM|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|LSTM| +|LeakyRelu|**1**|1|1|1|1|**6**|6|6|6|6|6|LeakyRelu| +|Less|**1**|1|1|1|1|1|**7**|7|**9**|9|9|Less| +|Log|**1**|1|1|1|1|**6**|6|6|6|6|6|Log| +|LogSoftmax|**1**|1|1|1|1|1|1|1|1|1|**11**|LogSoftmax| +|Loop|**1**|1|1|1|1|1|1|1|1|1|**11**|Loop| +|LpNormalization|**1**|1|1|1|1|1|1|1|1|1|1|LpNormalization| +|LpPool|**1**|**2**|2|2|2|2|2|2|2|2|**11**|LpPool| +|MatMul|**1**|1|1|1|1|1|1|1|**9**|9|9|MatMul| +|MatMulInteger|-|-|-|-|-|-|-|-|-|**10**|10|MatMulInteger| +|Max|**1**|1|1|1|1|**6**|6|**8**|8|8|8|Max| +|MaxPool|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**8**:small_orange_diamond:|8:small_orange_diamond:|**10**:small_orange_diamond:|**11**:small_orange_diamond:|MaxPool| +|MaxRoiPool|**1**:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|MaxRoiPool| +|MaxUnpool|-|-|-|-|-|-|-|-|**9**|9|**11**|MaxUnpool| +|Mean|**1**|1|1|1|1|**6**|6|**8**|8|8|8|Mean| +|MeanVarianceNormalization|-|-|-|-|-|-|-|-|**9**|9|9|MeanVarianceNormalization| +|Min|**1**|1|1|1|1|**6**|6|**8**|8|8|8|Min| +|Mod|-|-|-|-|-|-|-|-|-|**10**:small_orange_diamond:|10:small_orange_diamond:|Mod| +|Mul|**1**|1|1|1|1|**6**|**7**|7|7|7|7|Mul| +|Multinomial|-|-|-|-|-|-|**7**:small_red_triangle:|7:small_red_triangle:|7:small_red_triangle:|7:small_red_triangle:|7:small_red_triangle:|Multinomial| +|Neg|**1**|1|1|1|1|**6**|6|6|6|6|6|Neg| +|NonMaxSuppression|-|-|-|-|-|-|-|-|-|**10**|**11**|NonMaxSuppression| +|NonZero|-|-|-|-|-|-|-|-|**9**|9|9|NonZero| +|Not|**1**|1|1|1|1|1|1|1|1|1|1|Not| +|OneHot|-|-|-|-|-|-|-|-|**9**:small_orange_diamond:|9:small_orange_diamond:|**11**:small_orange_diamond:|OneHot| +|Or|**1**|1|1|1|1|1|**7**|7|7|7|7|Or| +|PRelu|**1**|1|1|1|1|**6**|**7**|7|**9**|9|9|PRelu| +|Pad|**1**|**2**|2|2|2|2|2|2|2|2|**11**|Pad| +|Pow|**1**|1|1|1|1|1|**7**|7|7|7|7|Pow| +|QLinearConv|-|-|-|-|-|-|-|-|-|**10**|10|QLinearConv| +|QLinearMatMul|-|-|-|-|-|-|-|-|-|**10**|10|QLinearMatMul| +|QuantizeLinear|-|-|-|-|-|-|-|-|-|**10**|10|QuantizeLinear| +|RNN|**1**:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|1:small_orange_diamond:|**7**:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|7:small_orange_diamond:|RNN| +|RandomNormal|**1**|1|1|1|1|1|1|1|1|1|1|RandomNormal| +|RandomNormalLike|**1**|1|1|1|1|1|1|1|1|1|1|RandomNormalLike| +|RandomUniform|**1**|1|1|1|1|1|1|1|1|1|1|RandomUniform| +|RandomUniformLike|**1**|1|1|1|1|1|1|1|1|1|1|RandomUniformLike| +|Range|-|-|-|-|-|-|-|-|-|-|**11**|Range| +|Reciprocal|**1**|1|1|1|1|**6**|6|6|6|6|6|Reciprocal| +|ReduceL1|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceL1| +|ReduceL2|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceL2| +|ReduceLogSum|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceLogSum| +|ReduceLogSumExp|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceLogSumExp| +|ReduceMax|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceMax| +|ReduceMean|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceMean| +|ReduceMin|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceMin| +|ReduceProd|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceProd| +|ReduceSum|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceSum| +|ReduceSumSquare|**1**|1|1|1|1|1|1|1|1|1|**11**|ReduceSumSquare| +|Relu|**1**|1|1|1|1|**6**|6|6|6|6|6|Relu| +|Reshape|**1**|1|1|1|**5**|5|5|5|5|5|5|Reshape| +|Resize|-|-|-|-|-|-|-|-|-|**10**:small_orange_diamond:|**11**:small_orange_diamond:|Resize| +|ReverseSequence|-|-|-|-|-|-|-|-|-|**10**|10|ReverseSequence| +|RoiAlign|-|-|-|-|-|-|-|-|-|**10**:small_red_triangle:|10:small_red_triangle:|RoiAlign| +|Round|-|-|-|-|-|-|-|-|-|-|**11**|Round| +|Scan|-|-|-|-|-|-|-|**8**|**9**|9|**11**|Scan| +|Scatter|-|-|-|-|-|-|-|-|**9**|9|**11**\*|Scatter| +|ScatterElements|-|-|-|-|-|-|-|-|-|-|**11**|ScatterElements| +|ScatterND|-|-|-|-|-|-|-|-|-|-|**11**|ScatterND| +|Selu|**1**|1|1|1|1|**6**|6|6|6|6|6|Selu| +|SequenceAt|-|-|-|-|-|-|-|-|-|-|**11**|SequenceAt| +|SequenceConstruct|-|-|-|-|-|-|-|-|-|-|**11**|SequenceConstruct| +|SequenceEmpty|-|-|-|-|-|-|-|-|-|-|**11**|SequenceEmpty| +|SequenceErase|-|-|-|-|-|-|-|-|-|-|**11**|SequenceErase| +|SequenceInsert|-|-|-|-|-|-|-|-|-|-|**11**|SequenceInsert| +|SequenceLength|-|-|-|-|-|-|-|-|-|-|**11**|SequenceLength| +|Shape|**1**|1|1|1|1|1|1|1|1|1|1|Shape| +|Shrink|-|-|-|-|-|-|-|-|**9**|9|9|Shrink| +|Sigmoid|**1**|1|1|1|1|**6**|6|6|6|6|6|Sigmoid| +|Sign|-|-|-|-|-|-|-|-|**9**|9|9|Sign| +|Sin|-|-|-|-|-|-|**7**|7|7|7|7|Sin| +|Sinh|-|-|-|-|-|-|-|-|**9**|9|9|Sinh| +|Size|**1**|1|1|1|1|1|1|1|1|1|1|Size| +|Slice|**1**|1|1|1|1|1|1|1|1|**10**|**11**|Slice| +|Softmax|**1**|1|1|1|1|1|1|1|1|1|**11**|Softmax| +|Softplus|**1**|1|1|1|1|1|1|1|1|1|1|Softplus| +|Softsign|**1**|1|1|1|1|1|1|1|1|1|1|Softsign| +|SpaceToDepth|**1**|1|1|1|1|1|1|1|1|1|1|SpaceToDepth| +|Split|**1**|**2**|2|2|2|2|2|2|2|2|**11**|Split| +|SplitToSequence|-|-|-|-|-|-|-|-|-|-|**11**:small_red_triangle:|SplitToSequence| +|Sqrt|**1**|1|1|1|1|**6**|6|6|6|6|6|Sqrt| +|Squeeze|**1**|1|1|1|1|1|1|1|1|1|**11**|Squeeze| +|StringNormalizer|-|-|-|-|-|-|-|-|-|**10**:small_red_triangle:|10:small_red_triangle:|StringNormalizer| +|Sub|**1**|1|1|1|1|**6**|**7**|7|7|7|7|Sub| +|Sum|**1**|1|1|1|1|**6**|6|**8**|8|8|8|Sum| +|Tan|-|-|-|-|-|-|**7**|7|7|7|7|Tan| +|Tanh|**1**|1|1|1|1|**6**|6|6|6|6|6|Tanh| +|TfIdfVectorizer|-|-|-|-|-|-|-|-|**9**|9|9|TfIdfVectorizer| +|ThresholdedRelu|-|-|-|-|-|-|-|-|-|**10**|10|ThresholdedRelu| +|Tile|**1**|1|1|1|1|**6**|6|6|6|6|6|Tile| +|TopK|**1**|1|1|1|1|1|1|1|1|**10**|**11**|TopK| +|Transpose|**1**|1|1|1|1|1|1|1|1|1|1|Transpose| +|Unique|-|-|-|-|-|-|-|-|-|-|**11**:small_red_triangle:|Unique| +|Unsqueeze|**1**|1|1|1|1|1|1|1|1|1|**11**|Unsqueeze| +|Upsample|**1**:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|1:small_red_triangle:|**7**:small_orange_diamond:|7:small_orange_diamond:|**9**:small_orange_diamond:|**10**\*|10\*|Upsample| +|Where|-|-|-|-|-|-|-|-|**9**|9|9|Where| +|Xor|**1**|1|1|1|1|1|**7**|7|7|7|7|Xor| + +ONNX-TF Supported Operators / ONNX Operators: 149 / 156 + +Notes: +1. Cast: Cast string to float32/float64/int32/int64 are not supported in Tensorflow. +2. Clip: Clip input in uint64 is not supported in Tensorflow. +3. ConvTranspose: ConvTranspose with dilations != 1, or transposed convolution for 4D or higher are not supported in Tensorflow. +4. CumSum: CumSum inputs in uint32/uint64 are not supported in Tensorflow. +5. Equal: Equal inputs in uint16/uint32/uint64 are not supported in Tensorflow. +6. GRU: GRU with clip or GRU with linear_before_reset, or GRU not using sigmoid for z and r, or GRU using Elu as the activation function with alpha != 1, or GRU using HardSigmoid as the activation function with alpha != 0.2 or beta != 0.5 are not supported in TensorFlow. +7. LSTM: LSTM not using sigmoid for `f`, or LSTM not using the same activation for `g` and `h` are not supported in Tensorflow. +8. MaxPool: MaxPoolWithArgmax with pad is None or incompatible mode, or MaxPoolWithArgmax with 4D or higher input, orMaxPoolWithArgmax with column major are not supported in Tensorflow. +9. Mod: Mod Dividend or Divisor in int8/int16/uint8/uint16/uint32/uint64 are not supported in Tensorflow. +10. OneHot: OneHot indices in uint16/uint32/uint64/int8/int16/float16/float/double, or OneHot depth in uint8/uint16/uint32/uint64/int8/int16/int64/float16/float/double are not supported in Tensorflow. +11. RNN: RNN with clip is not supported in Tensorflow. +12. Resize: Resize required 4D input in Tensorflow. For opset 11, only the following attributes and inputs conbination are supported in Tensorflow: + 1. mode=nearest, coordinate_transformation_mode=align_corners, nearest_mode=round_prefer_ceil, can use scales(*) or sizes. + 2. mode=nearest, coordinate_transformation_mode=asymmetric, nearest_mode=floor, can use scales(*) or sizes. + 3. mode=nearest, coordinate_transformation_mode=tf_half_pixel_for_nn, nearest_mode=floor, can use scales(*) or sizes. + 4. mode=linear, coordinate_transformation_mode=align_corners, can use scales(*) or sizes. + 5. mode=linear, coordinate_transformation_mode=asymmetric, can use scales(*) or sizes. + 6. mode=linear, coordinate_transformation_mode=half_pixel, can use scales(*) or sizes. + 7. mode=cubic, coordinate_transformation_mode=align_corners, cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) or sizes. + 8. mode=cubic, coordinate_transformation_mode=asymmetric, cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) or sizes. + 9. mode=cubic, coordinate_transformation_mode=half_pixel, cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) or sizes. + 10. mode=nearest, coordinate_transformation_mode=tf_crop_and_resize, extrapolation_value=any_float_value, nearest_mode=round_prefer_ceil, can use scales or sizes. + 11. mode=linear, coordinate_transformation_mode=tf_crop_and_resize, extrapolation_value=any_float_value, can use scales or sizes. + - Note (*): The accuracy of your model will go down, if the height and the width of the new sizes(scales * origial sizes) are not in whole numbers. +13. Upsample: Upsample required 4D input in Tensorflow. diff --git a/pt2tf/onnx-tensorflow/example/onnx_to_tf.py b/pt2tf/onnx-tensorflow/example/onnx_to_tf.py new file mode 100644 index 0000000..f47f04d --- /dev/null +++ b/pt2tf/onnx-tensorflow/example/onnx_to_tf.py @@ -0,0 +1,7 @@ +import onnx + +from onnx_tf.backend import prepare + +onnx_model = onnx.load("input_path") # load onnx model +tf_rep = prepare(onnx_model) # prepare tf representation +tf_rep.export_graph("output_path") # export the model diff --git a/pt2tf/onnx-tensorflow/example/relu.py b/pt2tf/onnx-tensorflow/example/relu.py new file mode 100644 index 0000000..9831175 --- /dev/null +++ b/pt2tf/onnx-tensorflow/example/relu.py @@ -0,0 +1,11 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from onnx_tf.backend import run_node, prepare +from onnx import helper + +node_def = helper.make_node("Relu", ["X"], ["Y"]) +output = run_node(node_def, [[-0.1, 0.1]]) +print(output["Y"]) diff --git a/pt2tf/onnx-tensorflow/example/test_model_large_stepping.py b/pt2tf/onnx-tensorflow/example/test_model_large_stepping.py new file mode 100644 index 0000000..dfc3c64 --- /dev/null +++ b/pt2tf/onnx-tensorflow/example/test_model_large_stepping.py @@ -0,0 +1,68 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import unittest +import numpy as np + +import caffe2.python.onnx.backend as c2 +import onnx +import onnx_tf.backend as tf +from onnx import helper +from onnx import TensorProto + + +def find_between(s, first, last): + try: + start = s.index(first) + len(first) + end = s.index(last, start) + return s[start:end] + except ValueError: + return "" + + +class TestLargeModel(unittest.TestCase): + MODEL_PATH = "../../onnx_models/" + + def test(self): + _model = onnx.load(self.MODEL_PATH + "shufflenet/model.onnx") + node_count = len(_model.graph.node) + more_outputs = [] + output_to_check = [] + for node in _model.graph.node: + more_outputs.append( + helper.make_tensor_value_info(node.output[0], TensorProto.FLOAT, + (100, 100))) + output_to_check.append(node.output[0]) + _model.graph.output.extend(more_outputs) + + tf_rep = tf.prepare(_model) + cf_rep = c2.prepare(_model) + + sample = np.load( + self.MODEL_PATH + "shufflenet/test_data_{}.npz".format(str(1)), + encoding='bytes') + inputs = list(sample['inputs']) + outputs = list(sample['outputs']) + + my_out = tf_rep.run(inputs) + cf_out = cf_rep.run(inputs) + + for op in output_to_check: + try: + np.savetxt( + op.replace("/", "__") + ".cf", cf_out[op].flatten(), delimiter='\t') + np.savetxt( + op.replace("/", "__") + ".tf", my_out[op].flatten(), delimiter='\t') + np.testing.assert_allclose(my_out[op], cf_out[op], rtol=1e-2) + print(op, "results of this layer are correct within tolerence.") + except Exception as e: + np.set_printoptions(threshold=np.inf) + mismatch_percent = (find_between(str(e), "(mismatch", "%)")) + print(op, "mismatch with percentage {} %".format(mismatch_percent)) + + +if __name__ == '__main__': + unittest.main() + pass diff --git a/pt2tf/onnx-tensorflow/onnx_tf.egg-info/PKG-INFO b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/PKG-INFO new file mode 100644 index 0000000..13ff0eb --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/PKG-INFO @@ -0,0 +1,12 @@ +Metadata-Version: 1.1 +Name: onnx-tf +Version: 1.6.0 +Summary: Tensorflow backend for ONNX (Open Neural Network Exchange). +Home-page: https://github.com/onnx/onnx-tensorflow/ +Author: Arpith Jacob, Tian Jin, Gheorghe-Teodor Bercea, Wenhao Hu +Author-email: tian.jin1@ibm.com +License: Apache License 2.0 +Description: UNKNOWN +Platform: UNKNOWN +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 diff --git a/pt2tf/onnx-tensorflow/onnx_tf.egg-info/SOURCES.txt b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/SOURCES.txt new file mode 100644 index 0000000..2e8e69a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/SOURCES.txt @@ -0,0 +1,209 @@ +LICENSE +MANIFEST.in +ONNX_VERSION_NUMBER +README.md +VERSION_NUMBER +setup.cfg +setup.py +onnx_tf/__init__.py +onnx_tf/backend.py +onnx_tf/backend_rep.py +onnx_tf/cli.py +onnx_tf/converter.py +onnx_tf/gen_doc.py +onnx_tf/gen_opset.py +onnx_tf/gen_status.py +onnx_tf/opset_version.py +onnx_tf/pb_wrapper.py +onnx_tf/version.py +onnx_tf.egg-info/PKG-INFO +onnx_tf.egg-info/SOURCES.txt +onnx_tf.egg-info/dependency_links.txt +onnx_tf.egg-info/entry_points.txt +onnx_tf.egg-info/not-zip-safe +onnx_tf.egg-info/requires.txt +onnx_tf.egg-info/top_level.txt +onnx_tf/common/__init__.py +onnx_tf/common/attr_converter.py +onnx_tf/common/attr_translator.py +onnx_tf/common/data_type.py +onnx_tf/common/exception.py +onnx_tf/common/handler_helper.py +onnx_tf/common/legacy.py +onnx_tf/common/pooling_helper.py +onnx_tf/common/tf_helper.py +onnx_tf/handlers/__init__.py +onnx_tf/handlers/backend_handler.py +onnx_tf/handlers/handler.py +onnx_tf/handlers/backend/__init__.py +onnx_tf/handlers/backend/abs.py +onnx_tf/handlers/backend/acos.py +onnx_tf/handlers/backend/acosh.py +onnx_tf/handlers/backend/add.py +onnx_tf/handlers/backend/and.py +onnx_tf/handlers/backend/arg_max.py +onnx_tf/handlers/backend/arg_min.py +onnx_tf/handlers/backend/asin.py +onnx_tf/handlers/backend/asinh.py +onnx_tf/handlers/backend/atan.py +onnx_tf/handlers/backend/atanh.py +onnx_tf/handlers/backend/average_pool.py +onnx_tf/handlers/backend/batch_normalization.py +onnx_tf/handlers/backend/bitshift.py +onnx_tf/handlers/backend/broadcast_mixin.py +onnx_tf/handlers/backend/cast.py +onnx_tf/handlers/backend/ceil.py +onnx_tf/handlers/backend/clip.py +onnx_tf/handlers/backend/compress.py +onnx_tf/handlers/backend/concat.py +onnx_tf/handlers/backend/constant.py +onnx_tf/handlers/backend/constant_fill.py +onnx_tf/handlers/backend/constant_of_shape.py +onnx_tf/handlers/backend/control_flow_mixin.py +onnx_tf/handlers/backend/conv.py +onnx_tf/handlers/backend/conv_integer.py +onnx_tf/handlers/backend/conv_mixin.py +onnx_tf/handlers/backend/conv_transpose.py +onnx_tf/handlers/backend/cos.py +onnx_tf/handlers/backend/cosh.py +onnx_tf/handlers/backend/cumsum.py +onnx_tf/handlers/backend/depth_to_space.py +onnx_tf/handlers/backend/dequantize_linear.py +onnx_tf/handlers/backend/det.py +onnx_tf/handlers/backend/dilated_pooling.py +onnx_tf/handlers/backend/div.py +onnx_tf/handlers/backend/dropout.py +onnx_tf/handlers/backend/dynamic_quantize_linear.py +onnx_tf/handlers/backend/elu.py +onnx_tf/handlers/backend/equal.py +onnx_tf/handlers/backend/erf.py +onnx_tf/handlers/backend/exp.py +onnx_tf/handlers/backend/expand.py +onnx_tf/handlers/backend/eye_like.py +onnx_tf/handlers/backend/flatten.py +onnx_tf/handlers/backend/floor.py +onnx_tf/handlers/backend/gather.py +onnx_tf/handlers/backend/gather_and_scatter_mixin.py +onnx_tf/handlers/backend/gather_elements.py +onnx_tf/handlers/backend/gather_nd.py +onnx_tf/handlers/backend/gemm.py +onnx_tf/handlers/backend/global_average_pool.py +onnx_tf/handlers/backend/global_lp_pool.py +onnx_tf/handlers/backend/global_max_pool.py +onnx_tf/handlers/backend/greater.py +onnx_tf/handlers/backend/gru.py +onnx_tf/handlers/backend/hard_sigmoid.py +onnx_tf/handlers/backend/hardmax.py +onnx_tf/handlers/backend/identity.py +onnx_tf/handlers/backend/if.py +onnx_tf/handlers/backend/image_scaler.py +onnx_tf/handlers/backend/instance_normalization.py +onnx_tf/handlers/backend/is_inf.py +onnx_tf/handlers/backend/is_nan.py +onnx_tf/handlers/backend/leaky_relu.py +onnx_tf/handlers/backend/less.py +onnx_tf/handlers/backend/log.py +onnx_tf/handlers/backend/log_softmax.py +onnx_tf/handlers/backend/loop.py +onnx_tf/handlers/backend/lp_normalization.py +onnx_tf/handlers/backend/lp_pool.py +onnx_tf/handlers/backend/lrn.py +onnx_tf/handlers/backend/lstm.py +onnx_tf/handlers/backend/mat_mul.py +onnx_tf/handlers/backend/mat_mul_integer.py +onnx_tf/handlers/backend/math_mixin.py +onnx_tf/handlers/backend/max.py +onnx_tf/handlers/backend/max_pool.py +onnx_tf/handlers/backend/max_unpool.py +onnx_tf/handlers/backend/mean.py +onnx_tf/handlers/backend/mean_variance_normalization.py +onnx_tf/handlers/backend/min.py +onnx_tf/handlers/backend/mod.py +onnx_tf/handlers/backend/mul.py +onnx_tf/handlers/backend/neg.py +onnx_tf/handlers/backend/non_max_suppression.py +onnx_tf/handlers/backend/non_zero.py +onnx_tf/handlers/backend/not.py +onnx_tf/handlers/backend/onehot.py +onnx_tf/handlers/backend/or.py +onnx_tf/handlers/backend/p_relu.py +onnx_tf/handlers/backend/pad.py +onnx_tf/handlers/backend/pad_mixin.py +onnx_tf/handlers/backend/pool_mixin.py +onnx_tf/handlers/backend/pow.py +onnx_tf/handlers/backend/q_linear_conv.py +onnx_tf/handlers/backend/q_linear_mat_mul.py +onnx_tf/handlers/backend/quantize_linear.py +onnx_tf/handlers/backend/random_normal.py +onnx_tf/handlers/backend/random_normal_like.py +onnx_tf/handlers/backend/random_uniform.py +onnx_tf/handlers/backend/random_uniform_like.py +onnx_tf/handlers/backend/range.py +onnx_tf/handlers/backend/reciprocal.py +onnx_tf/handlers/backend/reduce_l1.py +onnx_tf/handlers/backend/reduce_l2.py +onnx_tf/handlers/backend/reduce_log_sum.py +onnx_tf/handlers/backend/reduce_log_sum_exp.py +onnx_tf/handlers/backend/reduce_max.py +onnx_tf/handlers/backend/reduce_mean.py +onnx_tf/handlers/backend/reduce_min.py +onnx_tf/handlers/backend/reduce_prod.py +onnx_tf/handlers/backend/reduce_sum.py +onnx_tf/handlers/backend/reduce_sum_square.py +onnx_tf/handlers/backend/relu.py +onnx_tf/handlers/backend/reshape.py +onnx_tf/handlers/backend/resize.py +onnx_tf/handlers/backend/reverse_sequence.py +onnx_tf/handlers/backend/rnn.py +onnx_tf/handlers/backend/rnn_mixin.py +onnx_tf/handlers/backend/round.py +onnx_tf/handlers/backend/scan.py +onnx_tf/handlers/backend/scan_mixin.py +onnx_tf/handlers/backend/scatter.py +onnx_tf/handlers/backend/scatter_elements.py +onnx_tf/handlers/backend/scatter_nd.py +onnx_tf/handlers/backend/selu.py +onnx_tf/handlers/backend/sequence_at.py +onnx_tf/handlers/backend/sequence_construct.py +onnx_tf/handlers/backend/sequence_empty.py +onnx_tf/handlers/backend/sequence_erase.py +onnx_tf/handlers/backend/sequence_insert.py +onnx_tf/handlers/backend/sequence_length.py +onnx_tf/handlers/backend/shape.py +onnx_tf/handlers/backend/shrink.py +onnx_tf/handlers/backend/sigmoid.py +onnx_tf/handlers/backend/sign.py +onnx_tf/handlers/backend/sin.py +onnx_tf/handlers/backend/sinh.py +onnx_tf/handlers/backend/size.py +onnx_tf/handlers/backend/slice.py +onnx_tf/handlers/backend/softmax.py +onnx_tf/handlers/backend/softplus.py +onnx_tf/handlers/backend/softsign.py +onnx_tf/handlers/backend/space_to_depth.py +onnx_tf/handlers/backend/split.py +onnx_tf/handlers/backend/sqrt.py +onnx_tf/handlers/backend/squeeze.py +onnx_tf/handlers/backend/sub.py +onnx_tf/handlers/backend/sum.py +onnx_tf/handlers/backend/tan.py +onnx_tf/handlers/backend/tanh.py +onnx_tf/handlers/backend/tfidf_vectorizer.py +onnx_tf/handlers/backend/thresholded_relu.py +onnx_tf/handlers/backend/tile.py +onnx_tf/handlers/backend/top_k.py +onnx_tf/handlers/backend/transpose.py +onnx_tf/handlers/backend/unpool_mixin.py +onnx_tf/handlers/backend/unsqueeze.py +onnx_tf/handlers/backend/upsample.py +onnx_tf/handlers/backend/where.py +onnx_tf/handlers/backend/xor.py +test/__init__.py +test/test_cli.py +test/backend/__init__.py +test/backend/test_dynamic_shape.py +test/backend/test_model.py +test/backend/test_node.py +test/backend/test_onnx_backend.py +third_party/__init__.py +third_party/get_info.py \ No newline at end of file diff --git a/pt2tf/onnx-tensorflow/onnx_tf.egg-info/dependency_links.txt b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/pt2tf/onnx-tensorflow/onnx_tf.egg-info/entry_points.txt b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/entry_points.txt new file mode 100644 index 0000000..f05be4b --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +onnx-tf = onnx_tf.cli:main + diff --git a/pt2tf/onnx-tensorflow/onnx_tf.egg-info/not-zip-safe b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/not-zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/not-zip-safe @@ -0,0 +1 @@ + diff --git a/pt2tf/onnx-tensorflow/onnx_tf.egg-info/requires.txt b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/requires.txt new file mode 100644 index 0000000..3517455 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/requires.txt @@ -0,0 +1,2 @@ +onnx>=1.6.0 +PyYAML diff --git a/pt2tf/onnx-tensorflow/onnx_tf.egg-info/top_level.txt b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/top_level.txt new file mode 100644 index 0000000..70c9584 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf.egg-info/top_level.txt @@ -0,0 +1,3 @@ +onnx_tf +test +third_party diff --git a/pt2tf/onnx-tensorflow/onnx_tf/__init__.py b/pt2tf/onnx-tensorflow/onnx_tf/__init__.py new file mode 100644 index 0000000..9e6aa3d --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/__init__.py @@ -0,0 +1,2 @@ +from . import backend +from .version import version as __version__ diff --git a/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/__init__.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2f170648d449c14ddc25a3f8599cab077d5638c2 GIT binary patch literal 203 zcmXr!<>hkdOpJG8U|@I*#Bjg_WH|tFu?&z%VMt-jVaR2SVq^rdnR1wNnWC71Z02AF zO_rC8KqZ=tx7d>sle1IvQb5eI)S}|d{5(HRmRk%(AhU{?fy6ED_;{#HeEdp=A~ui& zi1?+eUy@s(pH`Zjt)HKlSD{;ynpd1(l$MiU4(7*~r0K`UXXa&=#K-FuRNmsS$<0qG P%}KQbSzQb=pNA0uwTLmr literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/backend.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/backend.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9d2c0b15d05754218b0f01e0819218e7c9ba319 GIT binary patch literal 11398 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 MM+$$e$u^z;0X+j|=l}o! literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/cli.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/cli.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..071ebb4614bbe909024126da07060921024d910b GIT binary patch literal 697 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 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/pb_wrapper.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/pb_wrapper.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80b63b2a349d8cbad0c7bbed67436790877f827c GIT binary patch literal 15773 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 B4r~Ab literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/version.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/__pycache__/version.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f1044adec1ad938dcf37cbf1a8a8b16e4b75ef0f GIT binary patch literal 367 zcmYk1OHRWu5J2sGno=kraS0+plR`;UsY0B94LffvC$^DAVn>csJ~!YfTq#>tT!9ti zwhKJ+)0>e!W8co_Gyciw1xDx_{aXR}1MGeS;E3Y}wU}V+Jpd0#u=5Z+B;n2@@Q6g< zF^TzvOnCBy(&-O$Kq(&2Sk;?maDu9~GuAegBujH!CSLOBp%M3fSU&@t;C)2+4`6v<-T(jq literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/backend.py b/pt2tf/onnx-tensorflow/onnx_tf/backend.py new file mode 100644 index 0000000..8b7d7f2 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/backend.py @@ -0,0 +1,352 @@ +"""Backend for running ONNX on Tensorflow + +To run this, you will need to have Tensorflow installed as well. +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +try: + from itertools import izip as zip +except ImportError: # will be 3.x series + pass + +from onnx import defs +from onnx import numpy_helper +from onnx.backend.base import Backend +from onnx.backend.base import Device +from onnx.backend.base import namedtupledict +from onnx.backend.test.runner import BackendIsNotSupposedToImplementIt +from onnx.helper import make_opsetid +import tensorflow as tf + +from onnx_tf.backend_rep import TensorflowRep +from onnx_tf.common import data_type +from onnx_tf.common import get_device_option +from onnx_tf.common import get_unique_suffix +from onnx_tf.common import supports_device as common_supports_device +from onnx_tf.common.handler_helper import get_all_backend_handlers +from onnx_tf.pb_wrapper import OnnxNode +import onnx_tf.common as common + + +class TensorflowBackend(Backend): + """ Tensorflow Backend for ONNX + """ + + @classmethod + def prepare(cls, + model, + device='CPU', + strict=True, + logging_level='INFO', + **kwargs): + """Prepare an ONNX model for Tensorflow Backend. + + This function converts an ONNX model to an internel representation + of the computational graph called TensorflowRep and returns + the converted representation. + + :param model: The ONNX model to be converted. + :param device: The device to execute this model on. + :param strict: Whether to enforce semantic equivalence between the original model + and the converted tensorflow model, defaults to True (yes, enforce semantic equivalence). + Changing to False is strongly discouraged. + Currently, the strict flag only affects the behavior of MaxPool and AveragePool ops. + :param logging_level: The logging level, default is INFO. Change it to DEBUG + to see more conversion details or to WARNING to see less + + :returns: A TensorflowRep class object representing the ONNX model + """ + super(TensorflowBackend, cls).prepare(model, device, **kwargs) + common.logger.setLevel(logging_level) + common.logger.handlers[0].setLevel(logging_level) + + return cls.onnx_model_to_tensorflow_rep(model, strict) + + @classmethod + def onnx_model_to_tensorflow_rep(cls, model, strict): + """ Convert ONNX model to TensorflowRep. + + :param model: ONNX ModelProto object. + :param strict: whether to enforce semantic equivalence between the original model + and the converted tensorflow model. + :return: TensorflowRep object. + """ + + # Models with IR_VERSION less than 3 does not have opset_import set. + # We default to minimum opset, this behavior is consistent with + # onnx checker. + # c.f. https://github.com/onnx/onnx/blob/427ac0c1b792363d373e3d7e4eef97fa46458420/onnx/checker.cc#L478 + if model.ir_version < 3: + opset_import = [make_opsetid(defs.ONNX_DOMAIN, 1)] + else: + opset_import = model.opset_import + return cls._onnx_graph_to_tensorflow_rep(model.graph, opset_import, strict) + + @classmethod + def _onnx_graph_to_tensorflow_rep(cls, graph_def, opset, strict): + """ Convert ONNX graph to TensorflowRep. + + :param graph_def: ONNX GraphProto object. + :param opset: ONNX OperatorSetIdProto list. + :param strict: whether to enforce semantic equivalence between the original model + and the converted tensorflow model. + :return: TensorflowRep object. + """ + handlers = cls._get_handlers(opset) + + tf_rep_graph = tf.Graph() + with tf_rep_graph.as_default(): + # initializer: TensorProtos representing the values to initialize + # a given tensor. + # initialized: A list of names of the initialized tensors. + if graph_def.initializer: + input_dict_items = cls._onnx_initializer_to_input_dict_items( + graph_def.initializer) + initialized = {init.name for init in graph_def.initializer} + else: + input_dict_items = [] + initialized = set() + + # creating placeholders for currently unknown inputs + for value_info in graph_def.input: + if value_info.name in initialized: + continue + shape = list( + d.dim_value if (d.dim_value > 0 and d.dim_param == "") else None + for d in value_info.type.tensor_type.shape.dim) + value_info_name = value_info.name.replace( + ":", "_tf_") + "_" + get_unique_suffix( + ) if ":" in value_info.name else value_info.name + + x = tf.placeholder(data_type.onnx2tf( + value_info.type.tensor_type.elem_type), + name=value_info_name, + shape=shape) + input_dict_items.append((value_info.name, x)) + + # tensor dict: this dictionary is a map from variable names + # to the latest produced TF tensors of the given name. + # This dictionary will get updated as we build the graph to + # record the names of newly produced tensors. + tensor_dict = dict(input_dict_items) + # Since tensor dict may be updated, we need to keep a copy + # of the original input dict where we track the earliest + # defined tensors so we can have access to the placeholders + # to feed in input tensors when we run the graph. + input_dict = dict(input_dict_items) + + for node in graph_def.node: + onnx_node = OnnxNode(node) + output_ops = cls._onnx_node_to_tensorflow_op(onnx_node, + tensor_dict, + handlers, + opset=opset, + strict=strict) + curr_node_output_map = dict(zip(onnx_node.outputs, output_ops)) + tensor_dict.update(curr_node_output_map) + + tf_rep = TensorflowRep() + tf_rep.graph = tf_rep_graph + tf_rep.inputs = [ + value_info.name + for value_info in graph_def.input + if value_info.name not in initialized + ] + tf_rep.outputs = [value_info.name for value_info in graph_def.output] + tf_rep.tensor_dict = tensor_dict + return tf_rep + + @classmethod + def run_node(cls, node, inputs, device='CPU', outputs_info=None, **kwargs): + """ Run ONNX node. + + :param node: ONNX NodeProto object. + :param inputs: Inputs. + :param device: Device run on. + :param outputs_info: None. + :param kwargs: Other args. + :return: Outputs. + """ + super(TensorflowBackend, cls).run_node(node, inputs, device) + node_graph = tf.Graph() + with node_graph.as_default(): + node = OnnxNode(node) + device_option = get_device_option(Device(device)) + input_tensors = [] + for i in inputs: + input_tensors.append(tf.constant(i)) + + if isinstance(inputs, dict): + feed_dict_raw = inputs + else: + assert len(node.inputs) == len(inputs) + feed_dict_raw = dict(zip(node.inputs, inputs)) + + # TODO: is constant the best way for feeding inputs? + input_dict = dict([ + (x[0], tf.constant(x[1])) for x in feed_dict_raw.items() + ]) + ops = cls._onnx_node_to_tensorflow_op(node, input_dict) + + with tf.Session() as sess: + with tf.device(device_option): + sess.run(tf.global_variables_initializer()) + output_vals = sess.run(ops) + + return namedtupledict('Outputs', node.outputs)(*output_vals) + + @classmethod + def _onnx_initializer_to_input_dict_items(cls, initializer): + """ Convert ONNX graph initializer to input dict items. + + :param initializer: ONNX graph initializer, list of TensorProto. + :return: List of input dict items. + """ + + def tensor2list(onnx_tensor): + # Use the onnx.numpy_helper because the data may be raw + return numpy_helper.to_array(onnx_tensor).flatten().tolist() + + def validate_initializer_name(name): + # Prepend a unique suffix if leading charater is "_" + name = get_unique_suffix() + name if name[0] is "_" else name + + # Replace ":" with "_tf_" and append a unique suffix for + # traceability + return name.replace( + ":", "_tf_") + "_" + get_unique_suffix() if ":" in name else name + + return [(init.name, + tf.constant(tensor2list(init), + shape=init.dims, + dtype=data_type.onnx2tf(init.data_type), + name=validate_initializer_name(init.name))) + for init in initializer] + + @classmethod + def _onnx_node_to_tensorflow_op(cls, + node, + tensor_dict, + handlers=None, + opset=None, + strict=True): + """ + Convert onnx node to tensorflow op. + + Args: + node: Onnx node object. + tensor_dict: Tensor dict of graph. + opset: Opset version of the operator set. Default 0 means using latest version. + strict: whether to enforce semantic equivalence between the original model + and the converted tensorflow model, defaults to True (yes, enforce semantic equivalence). + Changing to False is strongly discouraged. + Returns: + Tensorflow op + """ + handlers = handlers or cls._get_handlers(opset) + if handlers: + handler = handlers[node.domain].get(node.op_type, None) if node.domain in handlers else None + if handler: + return handler.handle(node, tensor_dict=tensor_dict, strict=strict) + + raise BackendIsNotSupposedToImplementIt("{} is not implemented.".format(node.op_type)) + + @classmethod + def _get_handlers(cls, opset): + """ Get all backend handlers with opset. + + :param opset: ONNX OperatorSetIdProto list. + :return: All backend handlers. + """ + opset = opset or [make_opsetid(defs.ONNX_DOMAIN, defs.onnx_opset_version())] + opset_dict = dict([(o.domain, o.version) for o in opset]) + return get_all_backend_handlers(opset_dict) + + @classmethod + def supports_device(cls, device): + return common_supports_device(device) + + @classmethod + def onnx_graph_to_tensorflow_ops(cls, + subgraph, + input_values, + tensor_dict, + opset=None, + strict=True): + """ + Converts ONNX graph to Tensorflow operations + Args: + subgraph: the ONNX graph to be converted + input_values: dictionary with values/tensors to initialize + the subgraph inputs. if the subgraph.input + are send in as parameters then it is required, + otherwise this can be empty dictionary. + tensor_dict: the dictionary that contain values for all the + node.inputs in the subgraph that are not defined + in the subgraph or input_values. + opset: opset version of the operator set. + strict: whether to enforce semantic equivalence between the + original model and the converted tensorflow model, + defaults to True (yes, enforce semantic equivalence). + Returns: + array of Tensorflow Tensors + """ + # get the subgraph.input from input_values + subgraph_tensor_dict = input_values.copy() + # get the rest of the subgraph input from tensor_dict + for i in subgraph.input: + if i.name not in subgraph_tensor_dict.keys(): + subgraph_tensor_dict[i.name] = tensor_dict[i.name] + # get the required initializer constant node(s) for the subgraph + # Need to get the initializer constant nodes from tensor_dict here + # because input from initializer will not be send in as inputs + # to the subgraph and those nodes are not in the subgraph + nodes_outputs = [] + for node in subgraph.node: + for o_name in node.output: + nodes_outputs.append(o_name) + for node in subgraph.node: + for i_name in node.input: + if i_name not in nodes_outputs and i_name not in subgraph_tensor_dict.keys( + ): + subgraph_tensor_dict[i_name] = tensor_dict[i_name] + onnx_node = OnnxNode(node) + output_ops = cls._onnx_node_to_tensorflow_op(onnx_node, + subgraph_tensor_dict, + opset=opset, + strict=strict) + curr_node_output_map = dict(zip(onnx_node.outputs, output_ops)) + subgraph_tensor_dict.update(curr_node_output_map) + return subgraph_tensor_dict + + @classmethod + def onnx_graph_to_tensorflow_rep(cls, graph_def, strict=True): + """ + Converts ONNX graph to TensorflowRep + Args: + graph_def: the ONNX graph to be converted + strict: whether to enforce semantic equivalence between the + original model and the converted tensorflow model, + defaults to True (yes, enforce semantic equivalence). + Returns: + TensorflowRep object. + """ + # get the opset of the installed ONNX + opset = [make_opsetid(defs.ONNX_DOMAIN, defs.onnx_opset_version())] + return cls._onnx_graph_to_tensorflow_rep(graph_def, opset, strict) + + +prepare = TensorflowBackend.prepare + +run_node = TensorflowBackend.run_node + +run_model = TensorflowBackend.run_model + +supports_device = TensorflowBackend.supports_device + +onnx_graph_to_tensorflow_ops = TensorflowBackend.onnx_graph_to_tensorflow_ops + +onnx_graph_to_tensorflow_rep = TensorflowBackend.onnx_graph_to_tensorflow_rep diff --git a/pt2tf/onnx-tensorflow/onnx_tf/backend_rep.py b/pt2tf/onnx-tensorflow/onnx_tf/backend_rep.py new file mode 100644 index 0000000..8b0c152 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/backend_rep.py @@ -0,0 +1,109 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import tensorflow as tf + +from onnx.backend.base import BackendRep, namedtupledict + + +class TensorflowRep(BackendRep): + + def __init__(self, graph=None, inputs=None, outputs=None, tensor_dict=None): + super(TensorflowRep, self).__init__() + self._graph = graph + self._inputs = inputs or [] + self._outputs = outputs or [] + self._tensor_dict = tensor_dict or {} + + @property + def graph(self): + return self._graph + + @graph.setter + def graph(self, graph): + self._graph = graph + + @property + def inputs(self): + return self._inputs + + @inputs.setter + def inputs(self, inputs): + self._inputs = inputs + + @property + def outputs(self): + return self._outputs + + @outputs.setter + def outputs(self, outputs): + self._outputs = outputs + + @property + def tensor_dict(self): + return self._tensor_dict + + @tensor_dict.setter + def tensor_dict(self, tensor_dict): + self._tensor_dict = tensor_dict + + def run(self, inputs, **kwargs): + """ Run TensorflowRep. + + :param inputs: Given inputs. + :param kwargs: Other args. + :return: Outputs. + """ + super(TensorflowRep, self).run(inputs, **kwargs) + + # TODO: handle name scope if necessary + with self.graph.as_default(): + with tf.Session() as sess: + if isinstance(inputs, dict): + feed_dict = inputs + elif isinstance(inputs, list) or isinstance(inputs, tuple): + if len(self.inputs) != len(inputs): + raise RuntimeError('Expected {} values for uninitialized ' + 'graph inputs ({}), but got {}.'.format( + len(self.inputs), ', '.join(self.inputs), + len(inputs))) + feed_dict = dict(zip(self.inputs, inputs)) + else: + # single input + feed_dict = dict([(self.inputs[0], inputs)]) + + feed_dict = { + self.tensor_dict[key]: feed_dict[key] for key in self.inputs + } + + sess.run(tf.global_variables_initializer()) + outputs = [self.tensor_dict[output] for output in self.outputs] + + output_values = sess.run(outputs, feed_dict=feed_dict) + return namedtupledict('Outputs', self.outputs)(*output_values) + + def export_graph(self, path): + """Export backend representation to a Tensorflow proto file. + + This function obtains the graph proto corresponding to the ONNX + model associated with the backend representation and serializes + to a protobuf file. + + :param path: The path to the output TF protobuf file. + + :returns: none. + """ + graph_proto = self.graph.as_graph_def() + # rename the output nodes + meaningful_names = {} + for output_name in self.outputs: + meaningful_names[self.tensor_dict[output_name].name.replace(':0', '')] = output_name + for node in graph_proto.node: + if node.name in meaningful_names.keys(): + node.name = meaningful_names[node.name] + + file = open(path, "wb") + file.write(graph_proto.SerializeToString()) + file.close() diff --git a/pt2tf/onnx-tensorflow/onnx_tf/cli.py b/pt2tf/onnx-tensorflow/onnx_tf/cli.py new file mode 100644 index 0000000..8364022 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/cli.py @@ -0,0 +1,24 @@ +import argparse +import sys + +import onnx_tf.converter + + +def main(): + args = sys.argv[1:] + parser = argparse.ArgumentParser( + description="ONNX-Tensorflow Command Line Interface") + parser.add_argument( + "command", + choices=["convert"], + help="Available commands.") + + if len(args) == 0: + parser.parse_args(["-h"]) + cli_tool = parser.parse_args([args[0]]) + if cli_tool.command == "convert": + return onnx_tf.converter.main(args[1:]) + + +if __name__ == '__main__': + main() diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/__init__.py b/pt2tf/onnx-tensorflow/onnx_tf/common/__init__.py new file mode 100644 index 0000000..794ef1a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/common/__init__.py @@ -0,0 +1,196 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import inspect +import re +import sys +import uuid +import warnings +import logging + +from onnx.backend.base import DeviceType +from tensorflow.python.client import device_lib + +IS_PYTHON3 = sys.version_info > (3,) +logger = logging.getLogger('onnx-tf') + +# create console handler and formatter for logger +console = logging.StreamHandler() +formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s') +console.setFormatter(formatter) +logger.addHandler(console) + + +class Deprecated: + """Add deprecated message when function is called. + + Usage: + from onnx_tf.common import deprecated + + @deprecated + def func(): + pass + + UserWarning: func is deprecated. It will be removed in future release. + + @deprecated("Message") + def func(): + pass + + UserWarning: Message + + @deprecated({"arg": "Message", + "arg_1": deprecated.MSG_WILL_REMOVE, + "arg_2": "",}) + def func(arg, arg_1, arg_2): + pass + + UserWarning: Message + UserWarning: arg_1 of func is deprecated. It will be removed in future release. + UserWarning: arg_2 of func is deprecated. + """ + + MSG_WILL_REMOVE = " It will be removed in future release." + + def __call__(self, *args, **kwargs): + return self.deprecated_decorator(*args, **kwargs) + + @staticmethod + def messages(): + return {v for k, v in inspect.getmembers(Deprecated) if k.startswith("MSG")} + + @staticmethod + def deprecated_decorator(arg=None): + # deprecate function with default message MSG_WILL_REMOVE + # @deprecated + if inspect.isfunction(arg): + + def wrapper(*args, **kwargs): + warnings.warn("{} is deprecated.{}".format( + arg.__module__ + "." + arg.__name__, Deprecated.MSG_WILL_REMOVE)) + return arg(*args, **kwargs) + + return wrapper + + deprecated_arg = arg if arg is not None else Deprecated.MSG_WILL_REMOVE + + def deco(func): + # deprecate arg + # @deprecated({...}) + if isinstance(deprecated_arg, dict): + for name, message in deprecated_arg.items(): + if message in Deprecated.messages(): + message = "{} of {} is deprecated.{}".format( + name, func.__module__ + "." + func.__name__, message or "") + warnings.warn(message) + # deprecate function with message + # @deprecated("message") + elif isinstance(deprecated_arg, str): + message = deprecated_arg + if message in Deprecated.messages(): + message = "{} is deprecated.{}".format( + func.__module__ + "." + func.__name__, message) + warnings.warn(message) + return func + + return deco + + +deprecated = Deprecated() + + +# This function inserts an underscore before every upper +# case letter and lowers that upper case letter except for +# the first letter. +def op_name_to_lower(name): + return re.sub('(? 0 + elif device == "CPU": + return True + return False + + +@deprecated("onnx_tf.common.get_outputs_names is deprecated.{} {}".format( + deprecated.MSG_WILL_REMOVE, + "Use TensorflowGraph.get_outputs_names instead.")) +def get_output_node_names(graph_def): + """Get output node names from GraphDef. + Args: + graph_def: GraphDef object. + Returns: + List of output node names. + """ + nodes, input_names = dict(), set() + for node in graph_def.node: + nodes[node.name] = node + input_names.update(set(node.input)) + return list(set(nodes) - input_names) + + +CONST_MINUS_ONE_INT32 = "_onnx_tf_internal_minus_one_int32" +CONST_ZERO_INT32 = "_onnx_tf_internal_zero_int32" +CONST_ONE_INT32 = "_onnx_tf_internal_one_int32" +CONST_ONE_FP32 = "_onnx_tf_internal_one_fp32" diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/__init__.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..056c78e59d33e5df45c50425395129e3dcd40176 GIT binary patch literal 5890 zcmbVQ&2!tv6~_YLr>PIivMtMwy;c%iY;8J`J(-NEICdm|O>Nl|+0hiKi$dI`42lHk z1!zkQ)kEnf&Sa)D&7t=mbL;d!=@r+W{4eCx-&;^5B`cG(@eN$jd(1F|Ay~s`GKVo5n;4spsmB(^mSgF$jj`?6dYoxwoDAk> z8d)c+`<#>0ecs9IzTgyeUv!G-vyCIol2g)abB(d)xHHZSnX6BT^INtvDU0=^qR?Z` z6h_B-hBJ-+xG3Vu2{~OqDNppko1Ci8$Y~ngF~kv3dS!@G&vZ`7Q&=%8#>Dt5!#OP` z#3cGN;;5KH|Bg5&rqQ1j$HfWs=fp`dgPzM-ajJe^&erF|Y|rd5aax>tWnjm5#XHV> z;;i$&IOkjt+_@++YesqQ4XLlpk_m4k3LEWMx_+}2su+**!hhjMei&dp-co)LyR~*u zjngNS?ZB^wLb?qAewn{NA9#adL%xuWk^82MB5xBDtHkQwZ(!<=@I)F86NY07=2*gXY+(r-%E-v9 z$cU^KKZkKqv27fH?QzJ2HC9;BL` zEB|jS^q0LQ$oyAxp4yySY|AV2%LF313 zSK?;tO08Ypx{`*d45Cog8sSTQ4}ZRr`tudn^#eb4-AZdG$-6EEg6l34GYB8UV4Y(t zgZQcJz26tP#QicY0D1$Wh55>ejXH|~Rx1E1NMWt+6PH4LjTW3m^9%w%J@I>Um+hKe zRtK{8n6kU(_vUk(6yR9!Cc>U5_Ea3b^y6m`-K>0&u&so>(Bh`e1gQO3Sc+r}(OTC( zr5#9ytkJnJB10boqRLVugtXE1%3uiy=lmdQ$!eSwH)Y(E%?+s{RREQdjYz|ac1!Ym z#6H1YsxWh(!uHFPBJJ^PJOV_JXtUDk!(UPBpM1$E)I5!kU=x4vcH zFw7t<%tKiw)RS4Qf`tB&sHE9*xT0U7A;N;y&DTa9AbJwy>h?(^&eXG%M;PwAa5U{^ z)@tY2SGxxyd3iV~YfNwyZMrUwnVZZj0^hIC!>971^4)w)V14j@3; zROH%f3=M2)!BvMgOL8xj*J??1hd9roF<73>u+9e~Ry!;Nh8FA-*ym*#&^bmF|Bfbx zv@z?M>Wl5Kp$D^PtQb$1`d(+oR^9FyTUm7*`pO{qjCz(dhCYYZY<(uIp0#Vn`Ff$N zb@zOF-3XR6)gq{V|Jopf4CuTTHs~Cn(lbXXbP)nDU*{C`4um>H`|1=JPmDt?L#Ym_ zJU~zcRhihrhs$P=xSM@%oxxglhMIS%p-5A+)SO0>SW&D2gi>H)ljV|J-&J9r@eyV3 zx0Frr^9U3oqGeb`HpNQJX0vP(V_T1>S&?-v|6qV5L*ywFDa)nN4{LP6i27d zQ}b(TDE{D4oW|tnIu=zCqno%ih#Gd$EM;tS$}Ao0ockGO2xSYYibz>W$#tK%JzcWE zwR5g3!YVwQm{F5@0@NP+)uxP}g+ggn)9!~sgqDMJuGz|;woTj2TP53M`pv*&DIHMs zY9O7$AdOyOc8#7z{;FZLGco_^()mA>=Rf`A%bS;-r{#pXgoaAOr0tC)1Av#R%+x$6 zjIg7@YBFr4K^ljyp4Y&nKFX_W7!RNXV~tOm8AA0K!9z@-`~<%L#XP0i>HLY`kugWz z_`EH7)UMV1ZN9O?+i=WHUh`EH^N)G;nWv((lxnwqQK9Acmis~mu^;bn z@UnJurIQ*$ed%ArDR#0#TF>m-$OdRiXNm7IcQSxs9Cm>M^uIm!J z<_7|J!M4$4v^=Te)7-e!@R}RKyZ&cVA}*tI@lfH1Fuu2NffT zZ#mqM)9I*-F`!rz)~2<~Hj!So=VNGJ*fX#IlGn_x)ivwHuXO|m+!^B(o-^b5nROgv z>qteEsCsPI7P&6c{%$6=MIKegAN%*&pd}ahS5S~6Sk7Dy9rx= zLw0&Yn5gE^BWouiNk{55Y!6y{f_#zm z)_?yUIMzk6k)z}|#b(TLmN)YZxrwPS@OEH(l9#|n+x{aAU}?5xste?wJ!2QuH2K0S z6l_#e1BdM`l*gEr!K?+5T{H9vINxz#99iAsBSt~t49;*sBUOxACw;Q0t;PXVaBVWf zz&!T`hSgZ6O|Xw;a^y8!5mg$SVCU&Hg%DNoV9Umc{jFceC)S-uPY^6e`r$yaqtg`P zoARBaGsgjq{#aZh7|`YX53~)b3FZ8|2h2N)Abazb_8uw-9^Xcapx{cTh#GPq%KpA% zM2Xdq0a#eUd*|5bE4QV>IE)Ukq)6O<;EE`*7}-2Z)k&5`Ycu_>b8Y_zg9zV{G00P$8xdX3BS?2-14C&O|Pvx4y z6#&KPtm;3bw2M;y$@4R;rkYSnpw`N_aF<38X2QL z#opRgl5D$$_>!n}2~QNAy2^G^7;KwlXl|4o(eG1rtEZTCz>0}Z8|l_AElH>T6Eh>q zbVhL;wQP}1GgZZ%bKdP66^CVf91Gw-O+RQyc#Q9BL40+=IrH|Ej#Od)?diAQ4wudz z{<7A(x`14#Yn*vHZKWT8P>E6)D1r+`rdO0SbOEhC#0W~;i40OM|9Fn2O8=Not`}ytn2)`rYHZ4_B{3 z?=rp*;!-79+64XBTCAkkyz2#`f!ka)#CL~=ObV!jaAt(=l0pieG%Ufq!xu$Qi2lO# z6p7D`dmr<3eX46TozHdR)Cj6$E677<@!^BpkFG9^xXrMR%rB+K-s^-g5v8RPoCSX%``{0RFPTMFvsbbk{0%=yMX^K-uW&OB(hgRP&V{=fJR723e>s>X?y2IJvyKb5!&+e%>$x|9m((esMaCeYSr)knPW0YgYw3;33 z;Bp3+SHa7%1l3_*cbRuCm&wzcg^mtpD(+{Lsb0>j0dP&7ZY;~@BLzG@bLW9 z4mwPReuZ;tjX}j+&@Cn4+ng=a2aoQ;b4u(0KLmD5>;iuRTq|)6cn{bsu?H-H>m{xO zs|xmk&w>42OEqL;957RJ@sp4N_-dZ4h2@6Ay+!)NkHFH`Oj(#7jN^d{RT}ObtD`h2 zJAyFO?qrlJEpjbJS`4)~(5^bpVqMFRA~aq>=gHl#l6;nBDXCai=U`4vy4S-W&U&4u z_P3+_vr#;eR}K(QQyd@)kV$H?X|ZXuSz>d8%^NT}Fzf!5C?)L;Q<_HVdM1ha;bHRk zVJs&Q{P$k;*yj7^&enopLOfE8Rk1Zh2)YfwAlWtq+os>4`{*yoc4-5CL3E9_;TI%( z6@u&ZE&4&O@}(Fz7UW^Hj&nVEUm#zvBJXus39ijHC%Q=aGCb`LXUTwWapzkwTr?`2 zvD7d1LvI3pfTzs5hm61EZ=3HIS!b2AD2=TCf`i-?vRZ~$l~f2^WZaT0sV(Kux^mH5 zlkU8DQ(W2BPQ@JZ zJ`<-GD{EjSe`2gQ_*{~~_{M_ICirZf`~qD)DoSS1rErwM;9ZoV zN@X;PRQx|_;@F4kC=OYUs~EEP@p`GeaG|>JFjjd;v6@i=VMe)$$Q4DS!y^@%63DTI z$c)@rcqg@)8s1ye0?I#J@WK}Yt6>*U&LZUt0p*TQsog7Ma4sB-k48MZT2=jxNi;o> z(dL&t0v_w+{>#hr>c%7;M3a0IP7$ixc@|L~_sha_r&@SSDi@nCO3pIf#6*=1^6{c~ z*_ax0o4t2nP)H_eq;gY#v{OP3v?EQe}DlQW3xax zua9*+`G+u;cUgVjUR0rKJ#xiO;qn{XMD{v$y<~1KHC!z&N-{g(OOW_FG9}9>$OKfT cH=;E6nZGejnKm5=(>8RZscL(ikI6VE{I`U?)`W9@_ zw}F(vVpMJhYyJKZbUiKs-7E*49)|fk;F9Dc+M-3IZB)0-I2)VM*to)x(>b#I7aK}U zY`Y1SV3ZBj5Q+=D=QjLJBx3~?MJc&w0~~B^pwuXaQj^<8{(7v`MA6&AF`Fg@o)^;03($ZR z@vPVS&T_F-K|a*?v67)b4(=fsB3IaCr>J%F)vs7c7$v3=5a6)Yrn&QT!e`F%u4)h# zpgq$ofyTa4l9Jb=V1wf!Qc;SHzTR48|0z_W4y3TzDAQ>)jKZE+qkG!#S|fJU$klFJLL@Hue59}X z95mn<+wW4xv_7!L+l@MeJReE6jcl{K8qlmQHbAyeGK=vihDhjWpgjpn{WU5A51Tw*b(>n{16Oac4Mx1vnBKo2WtWVmTgq1`;3~kFhKEtjKABy= z;C^LZWy4lai&VYI^q}Rw#beV?T;pt#!yyIT4UMXSehg6h8zh)D8hz+4MKiw>N6xSA brHyu8tJUuW_H|? zV84*Q@QB0%e}TU=uRQfH^oj4xIv1kWtDQM}=JuU4-}!uJb+vx)k9hFFx2%7yGd~;l zJ-p=;G{O=rwKCRcjBK9rzKz~aoy_gK#^=EH`rdN9*7t=gyysSbMbw0kzAjco9eqPI zL=$~eTo9|G^_=xr1@Btn+6$axg-mEP`W=*wvKaQsir1p_E7`;-6Tbgh3V6E!v3DDwQ*kZaz) zt(lT8rkm#F=j$q)u8(HJ{dJmhOPTbH(&Cx<9;ng!u*k9^Ul*~82kKy&w5JCz>znDg zR2Z4wy+G#^7|%LMOe8_nT#d9Jmjkn@cFm#MA&k1YJImELOSYser1nZB!5B#y)?T-_`zZQK z5>ND%XlKy-ac67L+aC0`qVD#t`P4k0YPZ_Ag%c3m^k8|8SEW#UX|cDLNL_mt%N)CF zZ&b)ER(j{!{v}gp)098GH5g1%H%8+m6}K?!7{>dsPhb#VPGEe7j}uW?J5&6e#6Z~-XW}kp!bkC= z{;2o?mPd!zU(b7xtR2>51G`uJwBe~Z=XX$VR1@0$K2B$eT*IW0SL|4+vW(Gl*)>6b zikT%{7;$3B2WCcw6cGJL08VbchmT|ZnzK3Ivq{AkHUfrem-5wfKN3|+skVh z!ao_=gDfuh`%TD&5!V3@I2WaU>orkrVwdtF8jD?~I%iE(e4Q$t%bW0qb`(WnOV=u) zEh~z-Mwuj)yLO026=WlH^;7w;DxP96)hVeq42R6tXCRvY5|Sb9Z)SyLEY+Qvf`7=ihQ1!ibY&9+5jE3j#7hZc=(8aqLO#s&S|p|Kkj zX(C9VDz)m zRIFyI^3!pY^oLy9H|x!y38veOG|Tv;+4bpK?6oX7t8ayuE0w!35hU^|YY zSDz+fBxBJX#4q*OOS;>BJRHW+c9^NOHTsSA^ZHRg@w@`mf!i5(_~GUW?YFXJb2Cg@ ziRCS7@-c~o?UM=n#*~XYiHTlfO$~7eJ!PQZH4TceSLI~m{P7kO!=BhsZyjzCPcBOL0GNi!3;z<8#Dc#rzxeF&Ve zI9{BmAwEjLg7L$vC!L?OtXXrQZqyluo~KHlH;jYv0R6J({W9(h(l4S!JBbSr*gbcm zJ{wjGoCb$VDCrumkhPNlQrcF8{H6G!wStA}#T6`GKmvbUqc$_v0t4Px?lK||%I$0*cxW!!xG1}p+Q-hqNBjxI*ZUu3X{uh@Z zHXxP>sLsu><%h^K3oWu3Xk~yi>@Z_w*{;|+l0MDNA2=9~yhCCoBTp2hITH(N12z#o zMzJ_69$s1SaK14Db#zQz6dH`TNYT_E0LlvHorEEL2kY{jyS`fWIph4yFL>jeIyOKk zkdLWx5Nt~Ddrjp#Eip!_3owu+X`n|HyMprT%UB#N0wr{WK#2dQE@8qHS9}pEEE}gRkOhoV#9G8}gvhA7z zb3V2C1M~36yChZtQx^(=(_P$_^5Cq;kxVF8KZwWC*%XP}1kSiiSj)Dtv~ffx0MqDO4Agz)Xpx_0w5ByVaoD>x`F$ zYdM#HhplI~iqrKv6R3VnN2R%U1ysM!>2dQE|C|w2;iIo{975t6WxH$&%sr@;1+I6h zg6lC|hquxyDp2o~6TjG}o2I`1q{S2P)<24?)N5aE?JQSeuklm8v9qf#=?~BLc6M4% zsW{K3+Z**(^VzP~Z0&jvT6@iGKF8yEq?CIvy~KTsYmmeZ(d8v`eSQ7XdS$(0(T&65 F{{pfByM_P& literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/handler_helper.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/handler_helper.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2382165fe00126ac4a1219cc7d438327b3e16e87 GIT binary patch literal 2298 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 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/tf_helper.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/common/__pycache__/tf_helper.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb1bb70b850c472cd41a81a1a23713e510452e81 GIT binary patch literal 1293 zcmZ`&&uiN-6qe*430X5r8H4tu!w$<~&DwN5jBOOkV7v6vo>GcYExB=O%SM*hWTdC; zvP1un{Y$>?lz(9iwkO%RAy9#&C+U0Nd(!(f>i2smKUr|>BJ>-rH3Iet^x_o^9C4hW zF}5=qJDhOm2O7KFp*PA#mC(DKMK&F7RU#pV=T<7h2# zTu_kwp;L78Ao(nL#S*ZhKpA9;dXX&c#xCrbG zg60Mlk$L6W6sry^f+Q|<<;7ATA5}z0K;vusI=_(Gf};F+H`Hl9jLPtKm`OQ%Q=djj zc4yatj)q~DrkNb-D45s^?C0~U3oDy~XUgltfI2<=lBnlkg+@K5InWKjY9Inbg8~+y zCYZ?rFEJ;(=!PuGJ%Jr(0lI2z7i`c)dxjUa52}5d6SL+Sm_7&vU zKJ_U}!ZKl66!xt{rofDuq`As?8ET^%eV5TNOUhKzZz9y0GNmv=xbC$)pJy!16Y>6W zhtZGp^77!Sg;=Rx9&T=ouC5-PuC3GCP0YbMMv0>c0x*4|#{sjK;3H;~@ z{0Q)Mjw|z*l^Is1vLGUt&EjJ958A+2J=m*U9VbGW4_`eKvm9P7;Bi`19k_}4nUx=A zGGuz-RG3xxdh8pAfLRsRL*F>}Kv+##c3@o?k)juScnfcnJ-kEIF02PW;H->|Q0oLd j`#Y79q7|V9uCW^;WkYm7q)_%md@?t(+U?@5)9wEU)MG&g literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/attr_converter.py b/pt2tf/onnx-tensorflow/onnx_tf/common/attr_converter.py new file mode 100644 index 0000000..dc89397 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/common/attr_converter.py @@ -0,0 +1,86 @@ +from onnx_tf.common import IS_PYTHON3 + + +def convert_tf(attr): + return __convert_tf_attr_value(attr) + + +def convert_onnx(attr): + return __convert_onnx_attribute_proto(attr) + + +def __convert_tf_attr_value(attr): + """ convert Tensorflow AttrValue object to Python object + """ + if attr.HasField('list'): + return __convert_tf_list_value(attr.list) + if attr.HasField('s'): + return attr.s + elif attr.HasField('i'): + return attr.i + elif attr.HasField('f'): + return attr.f + elif attr.HasField('b'): + return attr.b + elif attr.HasField('type'): + return attr.type + elif attr.HasField('shape'): + return attr.type + elif attr.HasField('tensor'): + return attr.tensor + else: + raise ValueError("Unsupported Tensorflow attribute: {}".format(attr)) + + +def __convert_tf_list_value(list_value): + """ convert Tensorflow ListValue object to Python object + """ + if list_value.s: + return list_value.s + elif list_value.i: + return list_value.i + elif list_value.f: + return list_value.f + elif list_value.b: + return list_value.b + elif list_value.tensor: + return list_value.tensor + elif list_value.type: + return list_value.type + elif list_value.shape: + return list_value.shape + elif list_value.func: + return list_value.func + else: + raise ValueError("Unsupported Tensorflow attribute: {}".format(list_value)) + + +def __convert_onnx_attribute_proto(attr_proto): + """ + Convert an ONNX AttributeProto into an appropriate Python object + for the type. + NB: Tensor attribute gets returned as the straight proto. + """ + if attr_proto.HasField('f'): + return attr_proto.f + elif attr_proto.HasField('i'): + return attr_proto.i + elif attr_proto.HasField('s'): + return str(attr_proto.s, 'utf-8') if IS_PYTHON3 else attr_proto.s + elif attr_proto.HasField('t'): + return attr_proto.t # this is a proto! + elif attr_proto.HasField('g'): + return attr_proto.g + elif attr_proto.floats: + return list(attr_proto.floats) + elif attr_proto.ints: + return list(attr_proto.ints) + elif attr_proto.strings: + str_list = list(attr_proto.strings) + if IS_PYTHON3: + str_list = list(map(lambda x: str(x, 'utf-8'), str_list)) + return str_list + elif attr_proto.HasField('sparse_tensor'): + return attr_proto.sparse_tensor + else: + raise ValueError("Unsupported ONNX attribute: {}".format(attr_proto)) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/attr_translator.py b/pt2tf/onnx-tensorflow/onnx_tf/common/attr_translator.py new file mode 100644 index 0000000..2842c30 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/common/attr_translator.py @@ -0,0 +1,37 @@ +from tensorflow.python.framework.tensor_util import MakeNdarray + +from onnx_tf.common import data_type + +# Keyed by old attribute names. +__tf_attr_translator = { + "_output_shapes": lambda x: list(map(lambda shape: get_tf_shape_as_list(shape.dim), x.list.shape)), + "shape": lambda x: get_tf_shape_as_list(x.shape.dim), + "T": lambda x: data_type.tf2onnx(list(x.list.type) or x.type), + "dtype": lambda x: data_type.tf2onnx(list(x.list.type) or x.type), + "component_types": lambda x: data_type.tf2onnx(list(x.list.type) or x.type), + "value": lambda x: MakeNdarray(x.tensor), + "seed2": lambda x: float(x.i), + "seed": lambda x: float(x.i), + "keep_dims": lambda x: int(x.b), + "squeeze_dims": lambda x: list(x.list.i), +} + +__onnx_attr_translator = { + "axis": lambda x: int(x), + "axes": lambda x: [int(a) for a in x], + "dtype": lambda x: data_type.onnx2tf(x), + "keepdims": lambda x: bool(x), + "to": lambda x: data_type.onnx2tf(x), +} + + +def translate_tf(key, val): + return __tf_attr_translator.get(key, lambda x: x)(val) + + +def translate_onnx(key, val): + return __onnx_attr_translator.get(key, lambda x: x)(val) + + +def get_tf_shape_as_list(tf_shape_dim): + return list(map(lambda x: x.size, list(tf_shape_dim))) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/data_type.py b/pt2tf/onnx-tensorflow/onnx_tf/common/data_type.py new file mode 100644 index 0000000..483ab61 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/common/data_type.py @@ -0,0 +1,71 @@ +from numbers import Number + +import numpy as np +from onnx import mapping +from onnx import TensorProto +import tensorflow as tf + + +def tf2onnx(dtype): + if isinstance(dtype, Number): + tf_dype = tf.as_dtype(dtype) + elif isinstance(dtype, tf.DType): + tf_dype = dtype + elif isinstance(dtype, list): + return [tf2onnx(t) for t in dtype] + else: + raise RuntimeError("dtype should be number or tf.DType.") + + # Usually, tf2onnx is done via tf_type->numpy_type->onnx_type + # to leverage existing type conversion infrastructure; + # However, we need to intercept the string type early because + # lowering tf.string type to numpy dtype results in loss of + # information. is returned instead of the + # numpy string type desired. + if tf_dype is tf.string: + return TensorProto.STRING + + onnx_dtype = None + try: + onnx_dtype = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype( + tf_dype.as_numpy_dtype)] + finally: + if onnx_dtype is None: + common.logger.warning( + "Can't convert tf dtype {} to ONNX dtype. Return 0 (TensorProto.UNDEFINED)." + .format(tf_dype)) + onnx_dtype = TensorProto.UNDEFINED + return onnx_dtype + + +def onnx2tf(dtype): + return tf.as_dtype(mapping.TENSOR_TYPE_TO_NP_TYPE[_onnx_dtype(dtype)]) + + +def onnx2field(dtype): + return mapping.STORAGE_TENSOR_TYPE_TO_FIELD[_onnx_dtype(dtype)] + + +def _onnx_dtype(dtype): + if isinstance(dtype, Number): + onnx_dype = dtype + elif isinstance(dtype, str): + onnx_dype = TensorProto.DataType.Value(dtype) + else: + raise RuntimeError("dtype should be number or str.") + return onnx_dype + + +# TODO (tjingrant) unify _onnx_dtype into any_dtype_to_onnx_dtype +def any_dtype_to_onnx_dtype(np_dtype=None, tf_dtype=None, onnx_dtype=None): + dtype_mask = [1 if val else 0 for val in [np_dtype, tf_dtype, onnx_dtype]] + num_type_set = sum(dtype_mask) + assert num_type_set == 1, "One and only one type must be set. However, {} set.".format( + sum(num_type_set)) + + if np_dtype: + onnx_dtype = mapping.NP_TYPE_TO_TENSOR_TYPE[np_dtype] + if tf_dtype: + onnx_dtype = tf2onnx(tf_dtype) + + return onnx_dtype diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/exception.py b/pt2tf/onnx-tensorflow/onnx_tf/common/exception.py new file mode 100644 index 0000000..d2c73ca --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/common/exception.py @@ -0,0 +1,73 @@ +import inspect +import onnx_tf.common as common + + +class CustomException(object): + + def __init__(self): + self._func = RuntimeError + self._message = "" + + def __call__(self, *args, **kwargs): + if inspect.isclass(self._func) and issubclass(self._func, Exception): + raise self._func(self.get_message(*args, **kwargs)) + elif callable(self._func): + self._func(self.get_message(*args, **kwargs)) + + def get_message(self, *args, **kwargs): + return self._message + + +class OpUnimplementedException(CustomException): + + def __init__(self): + super(OpUnimplementedException, self).__init__() + self._func = NotImplementedError + self._message = "{} is not implemented." + + def __call__(self, op, version=None, domain=None): + if IGNORE_UNIMPLEMENTED: + self._func = common.logger.warning + super(OpUnimplementedException, self).__call__(op, version, domain) + + def get_message(self, op, version=None, domain=None): + insert_message = op + if version is not None: + insert_message += " version {}".format(version) + if domain is not None: + insert_message += " in domain `{}`".format(domain) + return self._message.format(insert_message) + + +class OpUnsupportedException(object): + + def __init__(self): + super(OpUnsupportedException, self).__init__() + self._func = RuntimeError + self._message = "{} is not supported in {}." + + def __call__(self, op, framework): + raise self._func(self.get_message(op, framework)) + + def get_message(self, op, framework): + return self._message.format(op, framework) + + +class ConstNotFoundException(CustomException): + + def __init__(self): + super(ConstNotFoundException, self).__init__() + self._func = RuntimeError + self._message = "{} of {} is not found in graph consts." + + def __call__(self, name, op): + super(ConstNotFoundException, self).__call__(name, op) + + def get_message(self, name, op): + return self._message.format(name, op) + + +IGNORE_UNIMPLEMENTED = False +OP_UNIMPLEMENTED_EXCEPT = OpUnimplementedException() +OP_UNSUPPORTED_EXCEPT = OpUnsupportedException() +CONST_NOT_FOUND_EXCEPT = ConstNotFoundException() diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/handler_helper.py b/pt2tf/onnx-tensorflow/onnx_tf/common/handler_helper.py new file mode 100644 index 0000000..8d0c3ca --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/common/handler_helper.py @@ -0,0 +1,76 @@ +from onnx import defs + +import onnx_tf.common as common +from onnx_tf.handlers.backend import * # noqa +from onnx_tf.handlers.backend_handler import BackendHandler + +import onnx_tf.common as common + +def get_all_backend_handlers(opset_dict): + """ Get a dict of all backend handler classes. + e.g. {'domain': {'Abs': Abs handler class}, ...}, }. + + :param opset_dict: A dict of opset. e.g. {'domain': version, ...} + :return: Dict. + """ + handlers = {} + for handler in BackendHandler.__subclasses__(): + handler.check_cls() + + domain = handler.DOMAIN + version = opset_dict[domain] if domain in opset_dict else 1 + handler.VERSION = version + + since_version = 1 + if defs.has(handler.ONNX_OP, domain=handler.DOMAIN): + try: + since_version = defs.get_schema( + handler.ONNX_OP, + domain=handler.DOMAIN, + max_inclusive_version=version).since_version + except RuntimeError: + common.logger.debug("Fail to get since_version of {} in domain `{}` " + "with max_inclusive_version={}. Set to 1.".format( + handler.ONNX_OP, handler.DOMAIN, version)) + else: + common.logger.debug("Unknown op {} in domain `{}`.".format( + handler.ONNX_OP, handler.DOMAIN or "ai.onnx")) + handler.SINCE_VERSION = since_version + handlers.setdefault(domain, {})[handler.ONNX_OP] = handler + return handlers + + +def get_backend_coverage(): + """ Get backend coverage for document. + + :return: onnx_coverage: e.g. {'domain': {'ONNX_OP': [versions], ...}, ...} + """ + + onnx_coverage = {} + experimental_op = set() + for handler in BackendHandler.__subclasses__(): + handler.check_cls() + + versions = handler.get_versions() + domain = handler.DOMAIN + if getattr(handler, "EXPERIMENTAL", False): + experimental_op.add(handler.ONNX_OP) + _update_coverage(onnx_coverage, domain, handler.ONNX_OP, versions) + return onnx_coverage, experimental_op + + +def _update_coverage(coverage, domain, key, versions): + domain_coverage = coverage.setdefault(domain, {}) + vers = domain_coverage.get(key, []) + vers.extend(versions) + domain_coverage[key] = sorted(list(set(vers))) + + +def get_backend_partial_support_detail(): + ps_dict = {} + opset_dict = dict([(defs.ONNX_DOMAIN, defs.onnx_opset_version())]) + handlers = get_all_backend_handlers(opset_dict)[defs.ONNX_DOMAIN] + for op_name in handlers: + if handlers[op_name].PARTIAL_SUPPORT: + ps_dict[op_name] = handlers[op_name].PS_DESCRIPTION + return ps_dict diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/legacy.py b/pt2tf/onnx-tensorflow/onnx_tf/common/legacy.py new file mode 100644 index 0000000..93e6ef3 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/common/legacy.py @@ -0,0 +1,21 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import onnx + + +def get_onnx_version(): + return tuple(map(int, onnx.version.version.split("."))) + + +# Returns whether onnx version is prior to major.minor.patch +def legacy_onnx_pre_ver(major=0, minor=0, patch=0): + return get_onnx_version() < (major, minor, patch) + + +# Returns whether the opset version accompanying the +# onnx installation is prior to version passed. +def legacy_opset_pre_ver(version): + return onnx.defs.onnx_opset_version() < version diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/pooling_helper.py b/pt2tf/onnx-tensorflow/onnx_tf/common/pooling_helper.py new file mode 100644 index 0000000..e5f6f64 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/common/pooling_helper.py @@ -0,0 +1,263 @@ +from __future__ import division + +from collections import namedtuple +import numpy as np +import tensorflow as tf + +import itertools + + +pad_ops = namedtuple("pad_ops", + ["max_op", "ceil_op", "floor_op", "cast_int_op"]) + +pad_numpy_ops = pad_ops(np.maximum, np.ceil, np.floor, + lambda arr: arr.astype(np.int64)) +pad_tf_ops = pad_ops(tf.maximum, tf.math.ceil, tf.math.floor, + lambda tensor: tf.cast(tensor, tf.int64)) + + +def calc_pads_same(in_spatial_shape, kernel_shape, strides, + dilations, padding, padding_ops=pad_numpy_ops, + pads_order=1): + """ + Calculates the SAME paddings that need to be added to the input + + Args: + in_spatial_shape: input spatial shape + kernel_shape: the size of the kernel along each axis + strides: stride along each spatial axis + dilations: dilations value along each spatial axis + padding: padding to calculate: SAME_UPPER or + SAME_LOWER + padding_ops: namedtuple with ops to be used during + calculations. there are two sets of ops + defined pad_numpy_ops and pad_tf_ops with + numpy and tensorflow ops + pads_order: order of returned pads. possible options are: + 1 - b1, b2, ..., bn, e1, e2, ..., en + 2 - b1, e1, b2, e2, ..., bn, en + where n = len(kernel_shape) * 2, + b1, b2, ..., bn define pads at the begging of + axis + e1, e2, ..., en define pads at the end of + axis + Return: + pads: array with calculated pads. the order of the + values is determined by `pads_order` + + """ + spatial_size = len(kernel_shape) + pads = [0] * (spatial_size * 2) + for i in range(spatial_size): + in_size = in_spatial_shape[i] + filter_size = (kernel_shape[i] - 1) * dilations[i] + 1 + + out_size = padding_ops.ceil_op(in_size / strides[i]) + out_size = padding_ops.cast_int_op(out_size) + pad_along_axis = \ + padding_ops.max_op((out_size - 1) * strides[i] + + filter_size - in_size, 0) + if padding.lower() == "same_lower": + pad_op = padding_ops.ceil_op + else: + pad_op = padding_ops.floor_op + pad_begin = pad_op(pad_along_axis / 2) + + pad_begin = padding_ops.cast_int_op(pad_begin) + pad_along_axis = padding_ops.cast_int_op(pad_along_axis) + + pad_end = pad_along_axis - pad_begin + + pads[i * pads_order] = pad_begin + pads[i * pads_order + + (spatial_size if pads_order == 1 else 1)] = pad_end + + return pads + + +def calc_output_shape(input_spatial_shape, kernel_shape, strides, dilations, + padding, ceil_mode=False): + """ + Calculate output shape + + Args: + input_spatial_shape: input spatial shape + kernel_shape: the size of the kernel along each axis + strides: stride along each spatial axis + dilations: dilations value along each spatial axis + padding: can be explicit paddings, "SAME_UPPER" or + "SAME_LOWER" + Return: + output_shape: calculated output shape + """ + spatial_size = len(input_spatial_shape) + + if type(padding) is not list and type(padding) is not np.ndarray: + if padding.lower().startswith("same"): + padding = calc_pads_same(input_spatial_shape, kernel_shape, + strides, dilations, padding) + else: + padding = [0] * spatial_size * 2 + + output_shape = [] + for dim in range(spatial_size): + output_shape.append(_pooling_output_shape(input_spatial_shape[dim], + kernel_shape[dim], strides[dim], dilations[dim], + padding[dim] + padding[dim + spatial_size], + ceil_mode)) + + return output_shape + + +def _pooling_output_shape(input_size, ksize, stride, dilation, pad, ceil_mode): + output_size = (input_size + pad - ((ksize - 1) * dilation + 1) + + ((stride-1) if ceil_mode else 0)) // stride + 1 + if (pad): + if ((output_size - 1) * stride >= input_size + pad): + output_size -= 1 + return output_size + + +def py_pool(input, kernel_shape, strides=None, dilations=None, + padding=None, ceil_mode=False, pooling_type="MAX", + include_indices=True, p=2): + """ + Implementation of Max and Average pool operations in Python + Args: + input: input N-D data array in NC* format + kernel_shape: the size of the kernel along each axis + strides: stride along each spatial axis + dilations: dilations value along each spatial axis of filter + padding: padding for the beginning and ending along each + spatial axis. `padding` format should be as follow + [x1_begin, x2_begin...x1_end, x2_end,...] + ceil_mode: whether to use ceil or floor (default) to compute + the output shape. + pooling_type: specifies pooling type. Values can be "MAX", "AVG" or + "LP" + include_indices: should indices be included in the output + p: specifies the p parameter for LpPooling + Return: + pooled: output data from max pooling across the input + ind: indices of the selected max values from the input + """ + + if type(pooling_type) is not str: + pooling_type = pooling_type.decode("UTF-8") + + input_shape = np.shape(input) + inp_sp_shape = input_shape[2:] + input_dtype = input.dtype + if np.issubdtype(input_dtype, np.integer): + input_dtype_min = np.iinfo(input_dtype).min + else: + input_dtype_min = np.finfo(input_dtype).min + + if pooling_type == "LP": + rootN = (1.0 / p) + + def _loop_over_output(batch, channel): + dims = [range(output_sp_shape[d]) for d in range(spatial_size)] + for counters in itertools.product(*dims): + input_ranges = [] + for dim in range(spatial_size): + dim_start = \ + counters[dim] * strides[dim] - pads[dim * 2] + dim_end = \ + min(dim_start + (kernel_shape[dim] - 1) * dilations[dim] + + 1, inp_sp_shape[dim]) + while dim_start < 0: + dim_start += dilations[dim] + + cur_range = [i for i in range(dim_start, + dim_end, dilations[dim])] + input_ranges.append(cur_range) + if pooling_type in ["AVG", "LP"]: + val_sum = 0 + val_count = 0 + else: + maxval = input_dtype_min + maxind = -1 + for input_ind in itertools.product(*input_ranges): + ind = (batch, channel) + input_ind + val = input[ind] + if pooling_type == "AVG": + val_sum += val + val_count += 1 + elif pooling_type == "LP": + val_sum += abs(val ** p) + else: + if val > maxval: + maxval = val + ind = 0 + for i in range(spatial_size): + coef = 1 + for j in range(i+1, spatial_size): + coef *= inp_sp_shape[j] + ind += input_ind[i] * coef + maxind = ind + ind = (batch, channel) + counters + if pooling_type == "AVG": + out_pool[ind] = val_sum / val_count + elif pooling_type == "LP": + out_pool[ind] = val_sum ** rootN + else: + out_pool[ind] = maxval + out_ind[ind] = maxind + + spatial_size = len(kernel_shape) + + batch_size = input_shape[0] + channels_num = input_shape[1] + + if strides is None: + strides = kernel_shape + + if dilations is None: + dilations = [1] * spatial_size + + if padding is None: + padding = [0] * spatial_size * 2 + + if type(padding) is bytes: + padding = padding.decode() + + if type(padding) is not list and type(padding) is not np.ndarray: + if type(padding) is not str: + padding = padding.decode("UTF-8") + + if padding.lower().startswith("same"): + padding = calc_pads_same(inp_sp_shape, kernel_shape, strides, + dilations, padding) + else: + padding = [0] * spatial_size * 2 + + pads = [] + pad_along_axis = [] + output_sp_shape = [] + + for dim in range(spatial_size): + pads.append(padding[dim]) + pads.append(padding[dim + spatial_size]) + pad_along_axis.append(padding[dim] + padding[dim + spatial_size]) + + input_size = input_shape[dim + 2] + output_size = \ + _pooling_output_shape(input_size, kernel_shape[dim], + strides[dim], dilations[dim], + pad_along_axis[dim], ceil_mode) + output_sp_shape.append(output_size) + + out_pool = np.zeros([input_shape[0], input_shape[1]] + + output_sp_shape, input_dtype) + out_ind = np.zeros([input_shape[0], input_shape[1]] + + output_sp_shape, np.int64) + + for batch in range(batch_size): + for channel in range(channels_num): + _loop_over_output(batch, channel) + + if not include_indices: + return out_pool + else: + return out_pool, out_ind diff --git a/pt2tf/onnx-tensorflow/onnx_tf/common/tf_helper.py b/pt2tf/onnx-tensorflow/onnx_tf/common/tf_helper.py new file mode 100644 index 0000000..d2a90b4 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/common/tf_helper.py @@ -0,0 +1,45 @@ +import tensorflow as tf +import numpy as np + + +def tf_shape(tensor): + """ + Helper function returning the shape of a Tensor. + The function will check for fully defined shape and will return + numpy array or if the shape is not fully defined will use tf.shape() + to return the shape as a Tensor. + """ + if tensor.shape.is_fully_defined(): + return np.array(tensor.shape.as_list(), dtype=np.int64) + else: + return tf.shape(tensor, out_type=tf.int64) + + +def tf_product(a, b): + """ + Calculates the cartesian product of two column vectors a and b + + Example: + + a = [[1] + [2] + [3]] + + b = [[0] + [1]] + + result = [[1 0] + [1 1] + [2 0] + [2 1] + [3 0] + [3 1]] + """ + tile_a = tf.tile(a, [1, tf.shape(b)[0]]) + tile_a = tf.expand_dims(tile_a, 2) + tile_a = tf.reshape(tile_a, [-1, 1]) + + b = tf.tile(b, [tf.shape(a)[0], 1]) + b = tf.concat([tile_a, b], axis=1) + + return b diff --git a/pt2tf/onnx-tensorflow/onnx_tf/converter.py b/pt2tf/onnx-tensorflow/onnx_tf/converter.py new file mode 100644 index 0000000..6cefd8c --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/converter.py @@ -0,0 +1,138 @@ +import argparse +import inspect +import logging +import os +import shutil + +import onnx +import tensorflow as tf +from tensorflow.core.framework import graph_pb2 +from tensorflow.python.tools import freeze_graph + +import onnx_tf.backend as backend +import onnx_tf.common as common +from onnx_tf.common import get_unique_suffix +from onnx_tf.pb_wrapper import TensorflowGraph + + +def main(args): + args = parse_args(args) + convert(**{k: v for k, v in vars(args).items() if v is not None}) + + +def parse_args(args): + + class ListAction(argparse.Action): + """ Define how to convert command line list strings to Python objects. + """ + + def __call__(self, parser, namespace, values, option_string=None): + values = values if values[0] not in ("(", "[") or values[-1] not in ( + ")", "]") else values[1:-1] + res = [] + for value in values.split(","): + if value.isdigit(): + res.append(int(value)) + else: + res.append(value) + setattr(namespace, self.dest, res) + + class OpsetAction(argparse.Action): + """ Define how to convert command line opset strings to Python objects. + """ + + def __call__(self, parser, namespace, values, option_string=None): + if values.isdigit(): + setattr(namespace, "opset", int(values)) + else: + res = [] + while values and values[0] in ("(", "["): + values = values[1:] + while values and values[-1] in (")", "]"): + values = values[:-1] + for value in values.split("),("): + l, r = value.split(",") + res.append((l, int(r))) + setattr(namespace, "opset", res) + + def get_param_doc_dict(funcs): + """Get doc of funcs params. + + Args: + funcs: Target funcs. + + Returns: + Dict of params doc. + """ + + # TODO(fumihwh): support google doc format + def helper(doc, func): + first_idx = doc.find(":param") + last_idx = doc.find(":return") + last_idx = last_idx if last_idx != -1 else len(doc) + param_doc = doc[first_idx:last_idx] + params_doc = param_doc.split(":param ")[1:] + return { + p[:p.find(": ")]: p[p.find(": ") + len(": "):] + + " (from {})".format(func.__module__ + "." + func.__name__) + for p in params_doc + } + + param_doc_dict = {} + for func, persists in funcs: + doc = inspect.getdoc(func) + doc_dict = helper(doc, func) + for k, v in doc_dict.items(): + if k not in persists: + continue + param_doc_dict[k] = {"doc": v, "params": persists[k]} + return param_doc_dict + + parser = argparse.ArgumentParser( + description= + "This is the converter for converting protocol buffer between tf and onnx." + ) + + # required two args, source and destination path + parser.add_argument("--infile", "-i", help="Input file path.", required=True) + parser.add_argument( + "--outfile", "-o", help="Output file path.", required=True) + + def add_argument_group(parser, group_name, funcs): + group = parser.add_argument_group(group_name) + param_doc_dict = get_param_doc_dict(funcs) + for k, v in param_doc_dict.items(): + group.add_argument("--{}".format(k), help=v["doc"], **v["params"]) + + # backend args + # Args must be named consistently with respect to backend.prepare. + add_argument_group(parser, "backend arguments (onnx -> tf)", + [(backend.prepare, { + "device": {}, + "strict": {}, + "logging_level": {} + })]) + + return parser.parse_args(args) + + +def convert(infile, outfile, **kwargs): + """Convert pb. + + Args: + infile: Input path. + outfile: Output path. + **kwargs: Other args for converting. + + Returns: + None. + """ + logging_level = kwargs.get("logging_level", "INFO") + common.logger.setLevel(logging_level) + common.logger.handlers[0].setLevel(logging_level) + + common.logger.info("Start converting onnx pb to tf pb:") + onnx_model = onnx.load(infile) + tf_rep = backend.prepare(onnx_model, **kwargs) + tf_rep.export_graph(outfile) + common.logger.info("Converting completes successfully.") diff --git a/pt2tf/onnx-tensorflow/onnx_tf/gen_doc.py b/pt2tf/onnx-tensorflow/onnx_tf/gen_doc.py new file mode 100644 index 0000000..74f0e2e --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/gen_doc.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import os +import re +import subprocess + +import onnx_tf.backend +import onnx_tf.backend_rep +from third_party import get_info + + +def main(docs_dir): + gen_api(docs_dir) + gen_cli(docs_dir) + + +def gen_api(docs_dir): + gen_doc_for = { + 'onnx_tf.backend': [ + onnx_tf.backend.prepare, + ], + 'onnx_tf.backend_rep.TensorflowRep': [ + onnx_tf.backend_rep.TensorflowRep.export_graph, + ] + } + with open(os.path.join(docs_dir, 'API.md'), 'w') as doc_file: + doc_file.write('ONNX-Tensorflow API\n') + doc_file.write('======\n\n') + + for scope, funcs in sorted(gen_doc_for.items()): + for func in funcs: + doc_parsed = get_info.parse_docstring(func.__doc__) + doc_file.write('#### `' + scope + '.' + func.__name__ + '`\n\n') + doc_file.write('
\n') + doc_file.write(' ') + doc_file.write(doc_parsed['short_description'] + '\n\n') + doc_file.write(' \n') + doc_file.write(doc_parsed['long_description'] + '\n\n') + doc_file.write('
\n\n\n\n') + + doc_file.write('_params_:\n\n') + for param in doc_parsed['params']: + doc_file.write('`' + param['name'] + '` : ' + param['doc'] + '\n\n') + + doc_file.write('_returns_:\n\n') + doc_file.write(doc_parsed['returns'] + '\n\n') + + +def gen_cli(docs_dir): + with open(os.path.join(docs_dir, 'CLI_template.md'), 'r') as cli_temp_file: + temp_lines = cli_temp_file.readlines() + + lines = [] + for line in temp_lines: + matched = re.match(r"{onnx-tf.*}", line) + if matched: + command = matched.string.strip()[1:-1] + output = subprocess.check_output(command.split(" ")).decode("UTF-8") + lines.append(output) + else: + lines.append(line) + + with open(os.path.join(docs_dir, 'CLI.md'), 'w') as cli_file: + cli_file.writelines(lines) + + +if __name__ == '__main__': + base_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + docs_dir = os.path.join(base_dir, 'doc') + main(docs_dir) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/gen_opset.py b/pt2tf/onnx-tensorflow/onnx_tf/gen_opset.py new file mode 100644 index 0000000..8358b1c --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/gen_opset.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import pprint + +from onnx import defs + +from onnx_tf.common.handler_helper import get_backend_coverage +from onnx_tf.common.handler_helper import get_backend_partial_support_detail + + +def main(): + backend_opset_dict = {} + + for schema in defs.get_all_schemas(): + op_name = schema.name + backend_opset_dict[op_name] = [] + + backend_onnx_coverage, backend_experimental_op = get_backend_coverage() + backend_opset_dict.update(backend_onnx_coverage.get(defs.ONNX_DOMAIN, {})) + backend_ps_dict = get_backend_partial_support_detail() + + with open('opset_version.py', 'w') as version_file: + pp = pprint.PrettyPrinter(indent=4) + version_file.write("backend_opset_version = {\n " + + pp.pformat(backend_opset_dict)[1:-1] + "\n}\n\n") + version_file.write("backend_partial_support = {\n " + + pp.pformat(backend_ps_dict)[1:-1] + "\n}\n") + + +if __name__ == '__main__': + main() diff --git a/pt2tf/onnx-tensorflow/onnx_tf/gen_status.py b/pt2tf/onnx-tensorflow/onnx_tf/gen_status.py new file mode 100644 index 0000000..62b007b --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/gen_status.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import getopt +import os +import subprocess +import sys + +import onnx + +import tensorflow as tf + +from onnx_tf import opset_version, __version__ + + +def main(docs_dir): + base_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + docs_dir = os.path.join(base_dir, 'doc') + onnx_version = onnx.__version__ + onnx_tf_release_build = False + + try: + opts, args = getopt.getopt(sys.argv[1:], 'h:mr', + ['onnx_master', 'onnx_tf_release_build']) + except getopt.GetoptError: + print('Usage:') + print(' gen_status.py [-m -r]') + print(' gen_status.py -h') + print('Description:') + print(' -m, --onnx_master installed ONNX is the latest master code') + print(' if omitted, ONNX version is onnx.__version__') + print(' -r, --onnx_tf_release_build create report for ONNX-TF release with version') + print(' stated in the VERSION_NUMBER file') + print(' if omitted, the report is for ONNX-TF master') + print(' -h show this help message and exit') + print('eg. 1. generate support_status.md for ONNX-TF master and ONNX onnx.__version__') + print(' gen_status.py') + print(' 2. generate support_status.md for ONNX-TF master and ONNX master') + print(' gen_status.py -m') + print(' 3. generate support_status_.md for ONNX-TF version') + print(' stated in the VERSION_NUMBER file and ONNX onnx.__version__ ') + print(' gen_status.py -r') + sys.exit(2) + for opt, arg in opts: + if opt == '-h': + print('Usage:') + print(' gen_status.py [-m -r]') + print(' gen_status.py -h') + print('Description:') + print(' -m, --onnx_master installed ONNX is the latest master code') + print(' if omitted, ONNX version is onnx.__version__') + print(' -r, --onnx_tf_release_build create report for ONNX-TF release with version') + print(' stated in the VERSION_NUMBER file') + print(' if omitted, the report is for ONNX-TF master') + print(' -h show this help message and exit') + print('eg. 1. generate support_status.md for ONNX-TF master and ONNX onnx.__version__') + print(' gen_status.py') + print(' 2. generate support_status.md for ONNX-TF master and ONNX master') + print(' gen_status.py -m') + print(' 3. generate support_status_.md for ONNX-TF version') + print(' stated in the VERSION_NUMBER file and ONNX onnx.__version__ ') + print(' gen_status.py -r') + sys.exit() + elif opt in ('-m', '--onnx_master'): + onnx_version = 'master' + elif opt in ('-r', '--onnx_tf_release_build'): + onnx_tf_release_build = True + + gen_support_status(docs_dir, onnx_version, onnx_tf_release_build) + + +def gen_support_status(docs_dir, onnx_version, onnx_tf_release_build): + + # set filename + if onnx_tf_release_build: + onnx_tf_version = 'v' + __version__ + filename = 'support_status_' + onnx_tf_version.replace('.', '_') + '.md' + else: # onnx-tf = master + # get onnx-tf commit id + onnx_tf_commit_id = subprocess.check_output('git rev-parse HEAD', + shell=True) + onnx_tf_commit_id = onnx_tf_commit_id.decode().strip('\n') + onnx_tf_version = 'Master ( commit id: {} )'.format(onnx_tf_commit_id) + filename = 'support_status.md' + + with open(os.path.join(docs_dir, filename), 'w') as status_file: + status_file.write('# ONNX-Tensorflow Support Status\n') + status_file.write('|||\n') + status_file.write('|-:|:-|\n') + status_file.write('|ONNX-Tensorflow Version|{}|\n'.format(onnx_tf_version)) + + # get onnx commit id + if onnx_version == 'master': + onnx_commit_id = onnx.version.git_version + status_file.write( + '|ONNX Version|Master ( commit id: {} )|\n'.format(onnx_commit_id)) + else: + status_file.write('|ONNX Version|v{}|\n'.format(onnx_version)) + + # get tf_version + status_file.write('|Tensorflow Version|v{}|\n\n'.format(tf.__version__)) + + # display the table legend + status_file.write('Notes:\n') + status_file.write('* Values that are new or updated from a ') + status_file.write('previous opset version are in bold.\n') + status_file.write('* -: not defined in corresponding ONNX ') + status_file.write('opset version\n') + status_file.write('* \*: the operator is deprecated\n') + status_file.write('* :small_red_triangle:: not supported yet\n') + status_file.write('* :small_orange_diamond:: partially supported\n') + status_file.write('* the rest are all supported\n\n') + + # get oll onnx ops + onnx_ops = {} + for schema in onnx.defs.get_all_schemas(): + if schema.domain == '': # only get onnx ops + onnx_ops[schema.name] = { + 'versions': [], + 'deprecated': schema.since_version if schema.deprecated else -1 + } + for schema in onnx.defs.get_all_schemas_with_history(): + if schema.domain == '': # only get onnx ops + op = onnx_ops[schema.name] + if schema.deprecated: + if schema.since_version <= op['deprecated']: + op['versions'].append(schema.since_version) + op['deprecated'] = schema.since_version + else: + op['versions'].append(schema.since_version) + + # get all onnx-tf supported ops + onnx_tf_ops = opset_version.backend_opset_version + onnx_tf_ops_ps = opset_version.backend_partial_support + + # get the cureent opset version + current_opset = onnx.defs.onnx_opset_version() + + # setup table header + status_file.write('|||') + for i in range(current_opset): + status_file.write('|') + status_file.write('\n|:-:|:-:|') + for i in range(current_opset): + status_file.write(':-:|') + status_file.write('\n|**ONNX Operator**|') + for opset in range(1, current_opset + 1): + status_file.write('**Opset {}**|'.format(opset)) + status_file.write('**ONNX Operator**|') + + ops_count = len(onnx_ops) + # fill in data for the table + for key, val in sorted(onnx_ops.items()): + try: + status_file.write('\n|{}|'.format(key)) + i = 0 + vers = val['versions'] + deprecated = val['deprecated'] + for opset in range(1, current_opset + 1): + if i <= len(vers) - 1: + lb = vers[i] + ub = vers[i + 1] if i < len(vers) - 1 else vers[i] + if opset < lb: + if i == 0: + status_file.write('-') + elif opset == lb: + status_file.write('**{}**'.format(lb)) + if lb >= deprecated and deprecated > 0: + status_file.write('\*') + elif lb not in onnx_tf_ops[key]: + status_file.write(':small_red_triangle:') + if opset == current_opset: + ops_count -= 1 + elif key in onnx_tf_ops_ps: + status_file.write(':small_orange_diamond:') + else: # opset > lb + if opset < ub: + status_file.write('{}'.format(lb)) + if lb >= deprecated and deprecated > 0: + status_file.write('\*') + elif lb not in onnx_tf_ops[key]: + status_file.write(':small_red_triangle:') + if opset == current_opset: + ops_count -= 1 + elif key in onnx_tf_ops_ps: + status_file.write(':small_orange_diamond:') + elif opset == ub: + status_file.write('**{}**'.format(ub)) + if ub >= deprecated and deprecated > 0: + status_file.write('\*') + elif ub not in onnx_tf_ops[key]: + status_file.write(':small_red_triangle:') + if opset == current_opset: + ops_count -= 1 + elif key in onnx_tf_ops_ps: + status_file.write(':small_orange_diamond:') + i += 1 + else: #opset > ub + status_file.write('{}'.format(ub)) + if ub >= deprecated and deprecated > 0: + status_file.write('\*') + elif ub not in onnx_tf_ops[key]: + status_file.write(':small_red_triangle:') + if opset == current_opset: + ops_count -= 1 + elif key in onnx_tf_ops_ps: + status_file.write(':small_orange_diamond:') + status_file.write('|') + status_file.write('{}|'.format(key)) + except: + # ops defined in onnx but not in opset_version.backend_opset_versionn + status_file.write(':small_red_triangle:|') + + status_file.write( + '\n\nONNX-TF Supported Operators / ONNX Operators: {} / {}'.format( + ops_count, len(onnx_ops))) + + # display partial support footnote + status_file.write('\n\nNotes:\n') + index = 1 + for key in onnx_tf_ops_ps: + status_file.write( + str(index) + '. ' + key + ': ' + onnx_tf_ops_ps[key] + '\n') + index += 1 + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/__init__.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/__pycache__/__init__.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..489c58ed8dd4ed2d803a21d751c37d9fc951d239 GIT binary patch literal 137 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 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/__pycache__/handler.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/__pycache__/handler.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..440ea8899da50f70584bc3fd5e3e904ebe72941e GIT binary patch literal 3705 zcmb_e&2!tv6~_V~NKp{=X$26SgtM5$QC=qyt0PB?Sot zklm$ZGt#B>OwvmaJ@wpM|AqV&J>%L_|An6V-h!YhIi31Ya`5o5U+?YjecoSLsqg(M z@c*%F82>aDem3xX@W{UaVFn|yF(Muz$eX~Mo~d~Yc+0aiZv$_8w&p8w#jC(tCw4|v zud2tYac#8ZEzRcZr_0{*M+U30rI!X<;_lS)R`|+k!)pLt^;Utdd22w|y>*})-UiT3 zZ1BM%Knj6sC;( zaiq8iV%dRZHsb>c@3$WY;Tca@TXs^_8)sQ6IqRqGQ5N$NPgGllD7XAs!0f>z{|1B` z9$|)OGU8dx^lV-^b-XIGyc#@9%=YT6;w^KRIjs89m=d_HTihP_2Jm&ZtjAY@ciD>O z*Z4YXuvN`(0Kdl8HNOe`2HVv97Vul_mga8(f1BOW{B7X3*;|^w!%RT!ZeIO3NLb9p zlqA@L?puJQOAcmsy&yC>g>rs8mM~ zfctT7g!slEzR?!@@W}52xin4R9e-b{qr3)%610h@N5UA{sh35sTjoRh5q){U}t6} zSu(BcMZOfC@bJusgT99t)PNYKLmXn8llAf%^EIJ~^YBB^5WL^QBQfR~L3k#ArTcgu z4a88kC~pm0G#XHO5@a0AJV?=FqJ$1bke#4OC_M@y0E|Bmd4_?8%LhRebEbWO(%mc& z!H6ahdAqa&v@22o5zr|8t2k%2?hNo6%3XS>z^4i|w3v=YscDHdP&T*mxZEig>zRUV z;A9<7@b#VF!RzTe*Crb!8n343a3BKsXgGcYi~>&r{~_Q%=9DmVYF$~EmUth&txGZ> zm*$_rr!MDw&rmkAU_Cjl=smFOkFXCwwS$L%G<^~PZX>QvQicf5Y}ul1MK2vzT_2CX&u zHT{Sy8h{f?tXx8s$jH)ECB~l?9z|nFvW2O=T8XMy0*#v0yc#7kr7oQA&t%Iz5M7|? z*kqg3$z3wpDp6cqILGo@=67K`qR0TpDaM@H5onX9DKH`C>zTkpq+a-CeSzd_rrAxM zs`c^=Wi_{=uW({!zQzhj72Hj%Q`^H8dKT^ck0-h;$|Ud_kSt zb9JsQnb!|2r{yED2z_OIMF!9jGV^8a%DhCMv^v+6ufVEJ6!9}4=)7M;Sc@Mj2z%Fn zH?%Ha8>)h%Q;QghTa3Urd|euFAn7z6@g3Nm*CSarx&j({7-;wW?(h2_A9n8NRaqp# z+=a+hQCP%rljvO6G@+J44aqC#K|JP#iF6f(&Nxg%R8aR6WP@y&E}7h$BXKjNS|7w| z2yOL;E!{0)x`cB5OL&Q2A=yQuN6m#%l%*r%88EsNF|0;)^45P9)7%!Tur#mx{wQVR z7&@uk_5Cl#L0t4zdDZt>8v4FY0Rj_lzO37`A}YjtI8rUkz&3md%;MsGy;3*E1x5nx zQ`CvO$YD1jeu3m&BtJ&dLh@52_mN4}jDvwrN9`W*2|ct+{n~ z-F02N{Oi2c+`?N9#!w&OmI4!!Kra(mNCY}iVSXD^Q*qI4WLvYwy`?y$c`;5BE{aOm z&`C@UT1A&yIE#}WpF+OZB8&UHy59f3Szh~~u)~L#lI3@SxJ3WW8aRw=)~z)k8`9$c EAA0?#o&W#< literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__init__.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__init__.py new file mode 100644 index 0000000..5b372dc --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__init__.py @@ -0,0 +1,7 @@ +import os +import pkgutil + +__all__ = [ + modname for _, modname, _ in pkgutil.walk_packages( + path=[os.path.split(__file__)[0]]) +] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/__init__.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..53185001ce3d7b1bb1dc4974b864e955c78a4b3d GIT binary patch literal 391 zcmYLFy-ve05WaJgCaP3MBp#sy4H64ORaJtSrCSBEOzfm-oF8IW1*x6Nf)GO=gIDs( z#4B{-(n@gB_uY@rcb|Pd81$#_f`0(OH{s8Gilzi}LnJ|>hWW|k93_+98z@{d1xs(~ zt6+x`E+9kcf8rhNaNd(RgJJMPx8Xj)&XIY9fN)DN=R_H7;PLFi+v1jOal`iP*`L7| zw2Tgio@1jchuno_Eh|x~WBEvjNo>m|PFG10*H!g$X;o$FHr4g|m~)%P3sFg}S`$Bs zq)?TNInS%yaz1Ka5B;&ujZNyZnRJRwx3C9o*zHBHlkJ+m`3N;MVzO(R-B}AF0|(SU+O99b=}dJ9$B8$<8#sThM4z{^YM? x`)#~xjRbk3;8k&j&q{}|U>W%CMBMYkNpz;fM}38F@MRjTB=$zseJrGp>2G#p&x`;7 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/acos.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/acos.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dba76dfffd6672ac357143bf5eeed0096396d3ec GIT binary patch literal 736 zcmZWnJ&)8d5VhlcZEkmks7_S0DcBSgNC=^Y1|)RX(4{dUc5e4Jwii3g9ca5;LqpF` z;4itQy1zihOtK3r;bGhn zat~F=WlsJ4byaVq7H=ypT4^DY7_D!)*&^&3-t2UJ4{XV}*{$n~s#{&GZ`ay~uWI9J zOm!R#z!J=zgOh`VGLTGA5!?|d9|{KLLyL0j02~fHg!T^1Jpi{S*JMu{x(~k7E96U& z>LXQcB=4kl#`4A*#RsO^2$?g_>el%XCqCZXRQAgKBz6kPem^fdwJn-my(#d(lQBcn znww$HyQWx;>Rs`1>_$<6u*LR^pL~|qt&Qf-W=L*e9DJRl?#17w%RKTa=ekmobDwdp zjM%k^r<{MhN{Ng_GEf;ydNmp7TOv}C+!2w;RI(u)=s?R%&<`Y^ z+(Q*|kyCg2rmELci+7b4tuzoxI<0Scw?Wu9yxHpd9@vs`vt8BaRlhu6-LABYUe}#n z)|l%s7=Q(sJp(7bhBA;$P!Ze_s2>Uj^+SVt>i`@MJcRZh%svFSBUfZc8@da=(@P{w zk?UhsttIcJww>XP=@j==bth!b9IIRFLY%mGeN&lB`;(X{B>VlM=+&lZw)MKe15d{c zP21i0Iq#cdIm)-ir?DMHh05leFK%)zja_w`Kc68xPdWJdz$>5sUAxF5mvXKvB{_E) z=c*Ii7V(tx&)cfqubk9vWv!C^vJ>VM5_*P54vYBaOb*r3Fh6nGKh7@b8~4O3@0C?*j&jmS_KMJ1k?nO$g3q3ht9DyigNkAoAKhi6dgzNrUWM`f?Qa3SWgq5os`` K{$nwHME?Luc)e!; literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/add.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/add.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14da2e1c9dcae3a6df3d2799925cd909e7e44184 GIT binary patch literal 1023 zcmb7DO>fgc5Z(1Uw&Nr%MM6THxcWd0LTZJCP|5`)L@(TYSzPbBapSeiu0spTExmBz zfAE*~%Bg>W6EmBnjYN=OS37?Dp_w;t#?MEic=9dhrANq5vNb}$6IkXW7(oQBNk-x8 z)t+J*qj<(@U-hz{!#?033jp^-P=_kYB1&XWgi9&|NzeOB`i6)|gx5rbGLmfRFX@tI zv7jGF(!YTy`GqFo8pGTYuN7}>#Cb7*;U2+ z>Z)oiI~JlqSDV2AOkkO(V5CbS^CS~gc-I8N`+%A79qs`J@(u?g1X__s84A$G4RnU< z9W1j4W)CU8(!s_LZRr@GBWk((}ImKC+Je$xtRgV|-S&&&^^hv4DY zi?mZ0X*n-uDdzd4lZ|P0S+|#N&$}|6uB0&O=}MY37h-(z#r8i-ZK}56&qhedvGl%< zK!Wk@&3|#%5%@`%?!!mNXa;DI=gMH5yRe4`u-zHzhGQ=f*%oO4*&oF literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/and.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/and.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c2e15248e40f631602732a3705ddb37755d0b78 GIT binary patch literal 903 zcmZuvF>})}6qYR8v7MyQP8<^hO9tZO7<%0GxWEE;Ko>SI!nNeojVuMpp@qwqE-d^H z{*qRv{sktU2*5n&q@k;ft6xQGEqEEa<{DH4o$#0DG8V~#J<4StJQ!qRKRQl4)@xOjUD4d(X>s+89mdgWL0Up39+OS#)eWcZsWyespsYw(qpLb=Vjit%e-Dyi`)(N ztmD!sT?=*TW7^gEc|W_!&w4F#h^NbMHvP)AX_TbTT_xjL2H(fPczV0DpZmjqxX*9d zKW@tfr#%T;Yt>ROw_`pbI)nf8(7BOwu5Is}7OR%PF-PrLAHs z;qZvkFRM~)cZQWHjcIvzu9$w{`na0+I{MzOtxmwDU?v2Ygrm@BCPSOuX=#J5wom*h zT|M0iI^7CNw+ZbeEFS&$*>2mNy>?xSqe{t6D?!~s(bnBJ9m9qliv9{xI3v$vA7z`I U^kctr7uVmUBp6};kQg7~zpm5XasU7T literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/arg_max.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/arg_max.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4bde5c349638a470d4f22638ecb085ec6e6dbdca GIT binary patch literal 1676 zcmcIkOOM+&5GE;!k{`R>U8I0r^bw$k!U$?((`y@SlS2X&^`$o-N~j{`wXIi4xp4#e zI^0C27TQkfuoNca%T9=Xudi*>0kX8i#j0WHF@XZfUjVf zA3;bWX+{!m=oKqO1_ssYtg)0x$w-uH#Bs z{;ghqAMX;haC|%fS1`;I5X!~9V9JwJvgZW6`hY#@I~)LpC>@5lAi~Ju5O7cS9ggGx zq8w`EB%vVi!7n;`1j7tLpn2)7=nAjo&uu7G8gH}O`tfdMH12;%Aa*awjPAkAiMQX( z>b#nz+hjAttA1Il!jwAA%BOBF>U4J9vSDUFwd~Ady%c%8n^wQt@lw?yu4`>XrOQMa zI4r7I$N32c#y}AE>~71_^glNzZX@iCVE8b;gJE8QXy}@(DPHct_Fgvw_F(3Bv%u+s z2EH4nA2wvo8k*9E{Z9A1m^V!FG1~DY8Bny~SfRE96uK0Ka~Q4=nKz=r+d z&epsM547>%G#?S^kI0@kzVyM%pI{?wcmo-G!InUI!%_F`*NF5l@!J6*lnvVx8-#mpJnl@BSl>PvfVV77-cefRy z2TmoDGSABbU6~OG!cHl^5k2!R=ouZcJBaDC(=ONDft$=?vEp!abSPdpc@MlX7d;-*^LSbBKJRauD3&p~^vv9r$ajq*Ks?%x={{Nf$g=YMy7`CfhB zzxRK>@6RVa8wpXwxe~(mg~&^}%@7ZT_<0*=oo0|gA(~v(*QM0hK^*(~6GWe)_zcA@ z_YPq(xJHCCgC!ODLw|Sy!=DUn|F(VT4?$_~x+<;H>9L7SyCx#K1&x3HV)Tz~M>Up= x#*T2ir>(>(^x$iiRZ6$j&Y^grDY@YOEovKm-4gKte@2597_lLBugB>H{R=HrgqZ*U literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/arg_min.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/arg_min.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13dd9a5606bdbd3d5a7c696ab8e4605a76f55835 GIT binary patch literal 1676 zcmcIkOONC<5VoDfNk3+o8G+P|c&x+$wN`X%mMfrPIj|Cfc$YWUkN26;xc@f-v3p5w^Z;f~{Q2pk zDe6VKOSTKV>PL+#O{LSkdg|t)Nf);r8)orc$Ic?wYf)t7y#CQn*Qyb5(`X}VT_wuE zVNu6AF3vD827<6>4?33S|G7DF8)0t*!-w$|4D&mPmTt&~;^mI);Po?L4`zNp3!E-! z;k#w}aZ5I=r73OM&-B2{Wy>U=q8(4NDVdT(*!Y{E4O?$bW%z;}!qW*Ewc#2FY}qgF zY{T2|NLvq1^9hmugdBM5OCP-a3O2%)w~(sR9OZ1V)OZC)w~e++)iNv0OJv_( z8kMW05qWGHk(E;I?Wm($$Si4Q)E%`vE9+fjW|0jXvDO3H?At}WRifXX>Z%Z~GRsOT zeTmjtliEujEegl76D5?@&nF$EO&MCeTz3{H+1)Z=r5z}YqeXjchcbUav#o;o04ggq(taNz-<|zDt z`W;xGc`j6qUi1{jUA1v4KT{{ks&g$Dot literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/asin.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/asin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92c91bff267f7276df4f25dc1b2647ed059f81b0 GIT binary patch literal 736 zcmZWnF^|(Q6tw^bHZINbZP8WGcfU8t6dFOwjiv zpWZ_ia+y=Nc+IPg)Z#7IqLl_BNvHKK>$V8{n$;rIna!vNMru*PKy+Xbe zsXkJCBUvxC?F_3;r9J^6)5VqWYansMz*rwC$*&NAv#=+MG>R$d`y38joWlVD=8FLw9 zsuQ~w@rez#z}^{J(9-Wo)*Iz`0DpWio}gX<`gSsN8cn;e~B9NY14%Mr|+gMOf631~clv IFs2XbAF>9!&;S4c literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/asinh.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/asinh.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..88b0284ed7a2bce180f79f614018697e3d44666d GIT binary patch literal 740 zcmZWny^_-~5SA?e#g`lm)eRM`3*v%`fnfp-%rJKiof}~+`I3tz2g$iRm~_5|h9}?! zcqO$|_XhN{Ng_GEf;ydNmp7TOv}C+!2w;RI(u)=s?R%&<`Y^ z+(Q*|kyCg2rmELci+7b4tuzoxI<0Scw?Wu9yxHpd9@vs`vt8BaRlhu6-LABYUfY#k z)|l%s7=Q(sJp(7bhBA;$P!Ze_s2>Uj^+SVt>i`@MJcRZh%svFSBUfZc8@da=(@P{w zk?UhsttIcJww>XP=@j==bth!b9IIRFLY%mGeN&lB`;(X{B>VlM=+&lZw)MKe15d{c zP21i0Iq#cdIm)-ir?DMHh05leFK%)zja_w`Kc68xPdWJdz$>5sUAxF5mvXKvB{_E) z=c*Ii7V(tx&)cfqubk9vWv!C^vJ>VM5_*P54vYBaOb*r3Fh6nGKh7@b8~4O3@0C?*j&jmS_KMJ1k?nO$g3q3ht9DyigNkAoAKhi6dgzNrUWM`f?Qa3SWgq5os`` K{$nwHME?L__Pu)m literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/atan.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/atan.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72cac64b7a928dfe486d4f37f58973d8d3f01ff4 GIT binary patch literal 736 zcmZWnJ&)8d5VhlcZEkmks7_S0DcBSgNC=^Y1|)RX(4{dZc5e4Jb{0F!9ca5;LqpF` z;4itQy1zihOtK3r;bS zxrZv`GN*q2T2vcl1@826qI?hmt}0(4yQb0EYt)p}hlh55VooHQCde?t}023i(o` z`bdk7;+-b;cCqCZX2z%vz5<7)tzn>SK-WK()+7x);$(W&T z+M8j{ySiA7>Rs`1>_#C#*kb#|Pd+Q_)~(^sW=L*e9DJRl?#17w%RKTa=SFD7xz9M) zt=u(;r<{MiiB|v9cYyc`hgUa zd#FM#3hGYZ@Omw^c*nJ9rGZG=X?@GO4Z^-*%~sd_c!naz%Eup}XKay+pzk zxjt5WEm<$M?F?&7r`FPgcFynZ@9U%KZ%(_vfnStUTw-|Tdzwz@N~@3 zwB3!Lv%V>pqkLO_8rxBFR5ssyag%Fl?5fl3`3%{4%E8wMUitj*+C>q&j4{oXWX$D^ zsZMNL#8bvTZ+W|4IjLK2t&;t+6Xp~WdWJ_1i}>bD4%M=#IC1$u&MxR1_rxpjoB4tG zd{3P10|tp!Xa8+GEMvP(1kU9O?vp9JP?KOF_S!v(BVyP|gX~=PauoLpUxh^xSumyk J3lsW?{sBOYyKpIgw5S0Jt5rV?hWCta0OjDOB#FJe^0{T7S16d)!ku|UWkI9 zCI!!ggc-jqiYr#mZfU)v@vbbhx6`X>pxO`+102j5?xHpB8SVl1d0@B?yuq7>2fPI)+Y-Z0As42hh!6b@boC5iLC(p7E-X%; zKo%C(IYp7BwRGTPccfdDC{!sKpQe?zk3XJhPgN2IA3{qzGYCT46H$e>w$n^$rzpA5 z-o<4iC+Y{0J0S6U7*+W!8qd><2=nryK60FumuAeWadcLvPDP*UR7OdiC58&U*;nne zw9NCeXrOTifLL96y|IW}G+RwbES~uBKik&JSg>&utDfcfzmP6W7{v`2 X#+0ed;8h*nYy8ou0H96bv3Kbo^x_*e literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/batch_normalization.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/batch_normalization.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b05abcbef0c7221d1326530f83d3d0c38fa7f3ef GIT binary patch literal 2545 zcmcIlPmdcl6t_KplT5N{x@vbTBzizXL68LjEfuS6)l!uTDM&2h5P_`O@g$pM{-pM# zT~?FR^Z*AC-1!1<=Uc!R@U>i4;)28h^~8HlHeJyc_0k#n&Ck!z&%b$oetx&vtl#)H zU8-9*!)O|3;^QzANi0F*C3_ ze1ko}HBmR%2iy>W!8OqY#x3c9|A>OX2fw)JEoiC(0+$+7kQPY$Ck9iTzV_mo8Yg)+ z`s?t~H^2V#$DVHA59K(_qL{CSx=ec_9)|Oz(5{TLFpYmE@b6ZXC=QC#q_D5T;unMbh# zM|>8_Fb(i;Y!JkDt>ZVJ4tnpoQzM4c;5iQs6X+9Y>KBMp$pqad3#+tBI)NnGCeX7> zdqOKRVHH_8g;he@EZo8tfP}S8Moie4I0bA}=~nC`*u;y_7GCM$xFAzs-Y?vVSK1ZC ze4C(tmw?7EJ+uR#W(B}LXltw0!4hpNwy2%ax@&FyjMiIg8)vlsS{syPQWv$UqyC0J zYfJ)B7p!7GP}wQ%vQY+Qy{wI#MHB3rB`uqx@f{mM`md}5VO306Q?_WWG)>V0W*cP- zeC!FZ%{nLx+r+`I7)D{y1~#q92CUJp*q3Z^Zqb3&Ha1Cl4&t}5MK%do;rgiSoY4jU z&#Sx9*NtUjaWRexiCKPvVx9N6%b553&{P}5h?L|je*xv;M|RJKtfz7V)Fx>mwOQ|N zP5F~NmY8CX>$}NV6;Ynf_FhFt=+!01y=NpG2dgyCdb>#;g^Ah&a60t_r=1|16U^BY z55&M5D_+E^fD`17v)Q~*+EX*A7-6FQG*9EKn5U!Pf5Yd`>)p1z2(xqz^I9E-vsinf z;<$vik~q`0fsPEbQLI@p)Xvh%Q3V__?a6rAZ|>ji-@47exc%Aw-B0`4F~>_=;8tHs z!)Xkh@VxS&%u{X(T$T&)m}S~qvQpjivVmM|GvZDkgmR>03sv+;dq*pN?hywz)4>IE zV%1X14`d#SC(LuPg^vgJ`3m;v<|ITy4b8sFy01z zi(Uq~NjF)G9$$L?=C5lD?lm@3TQD+kvfwlgY019FYlXs%BHsgj*D|q`UBL1U6#rpe zyB|vhw+MgdLl`v)NZ9c!&)~2&e3>k+Tz^3pS6(KItG8Z|#nqR|;@X`TWO1$Et!tli zyfQi0bk+iF$Yd literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/bitshift.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/bitshift.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3b5a49f7d66d100887736d28cb7d5267f2179df3 GIT binary patch literal 911 zcmZXSJ8u&~5PBtS@VU3fZxIK3gSaQ?nyzsgaD0i9;5WR0MhP}Y7g;_N4S$z4yb=;l z!nSF?uy$^ui&9@s%0lNhc(*7xLlE^GlyC*4L{N@7xj~Qs5^-u%g70(RCX*h7=Fp8> zc4Or|h0&V1KvsjR4fFw2$Sl#kPW&I9gpB7oQy*bFMOsQJvNy}Xk^65V3zuDdIVM!|cTST-I!SLcc ze9{sz&)g_<(ceMrZy~bnfwV=Zz5l{?*Ort^b+36>h$9f4ZTdLJ5T+tf5$WI#?c%>x CJmnPt literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/broadcast_mixin.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/broadcast_mixin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7582a39df3b1f3c5777cd40d3aacec5245242e6d GIT binary patch literal 1599 zcmahJ+lnJaw5s}&PA4;rx;itfE?HTH2quDxFT=2iiw|O6W>E+(O;1-P(@9@4RTU-^ zDj;UTSrEY|e?kAk@2FRw7WNDF$#c4s?5_J@g*rL+I@kVeZ!f(6B#y=&A^(tp~vYN>AFurlME7s+q3iX5pYE1VaSBT{mP!M z>Cgqr<=$fgc5%#&E@@6ttD3=(vMCxnZ*16Q>vA(|M<=`qoC!q!Y4)l?B0 zr^b%S%B^(RPUi$9Ky7pY107F06W4eXZw<03lRp~o41K$`-!@STpu8<5f6_j8*7Rq3 z1ErY;^4ChgVcbcuhD26A@adGuKW~Wfza&q{4bctoUr7&v2XFk1HouS&t8A0K^XO>RG)>c(HsmviBs76(uGuQMeD(t|0W`oLNGJ(;ieUNq!&r`m zR-I8PJ7O`*(j?WL^KD_%V%#Z&;2m9d&PC^;C{!tX37X!I7SVXD$X>9|OQWqM@&I(5s6nRREfOI+-YJ6UrIY zGEc_ESlAZ43MoW9%~dzFPLe6>r^Rfpm25zqwpAw$3W>IKVd?d7PnSB*qGFz-nRU^2 z=oR8Bx|TlJ)Fq{ry$sOFo3H1F&eg{N2n*uLp)TDA>VPiq z{%^$+tSugl1HK33TexZoz%X30m4j&v%M#YMvU(<@jQRX=tFe0huj2fPMV zFW$(~Jk^4~7_$#SLG1&;R_w#?fZm3dEIa=x_iKh-HW+k$8$?kN=OT)17)5!>=NaPd zD7u`-*+$YzvRJ8H=!=q9X~_?EVZ9ol#1>-f6!tJ+jJDsec<_=3GdH`Idmyl3T@le&=m*Sec@k&4OE%pEhNno)LI7~u|1He%dQ6hXE9;gTeUG-oLc?3G* z!vp<>@Bt6s5FQHm;2voECVfu7C)3fN;GdjNsTqHrW@}OLZ_|ozgoKr_uBsnd-5}IC z%ePeq@Tf_pF47HC+oq|d#$Ox7xKNoa8eP zkONITz%KVJ_5u4mus8q=)L0zy9uUx%A(+T0D12~4T)%F_?*u4tvyGAi*l*QeU(R*e%=2xwo+F9(^wl}+oauc2qUBl5pSQfvGhl1h zyf%}i&@9zjD%Qw46ABn$Kzdrt5h!EI;$Mv$KFdJ737|M@gX|u zf*ji*uRi_HpyUyl>by$~T_OS3EZ^|FnB3}lapf8Mkf2yPegUv|IGq3?E9kumnUD(? zFkL~;5A?#@d)i%jYe$~K=FjFgC`Sq4cdXlsqt-#+5u+6@3xgLO7TR>TACoQWtnOdwkDM6 z>6%sB^0|<0;(S{+*NHPO#FK=u3y*MX8XtZFv8azg5$7%)I(?8KJ)sWuXhe^l-MdBg z@O&DXh%szR#!R2FvgX?j;vr){Y|~BmWsq%BrAnb+)Lf3iy1a|(15}@(y6WB*VOiU| z0l86lUq|84!*}=eMoQjyvHjPzHXWG$_3a=}z>kS-@9BJYc}L8;JA!o!68kGT`Ny`) t&)D$NLxr_215n1x;KHy6`nQvs=uyktS6F$L{s?IAUN->h14zM`{tecH!5aVo literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/ceil.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/ceil.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2f5d19f4b7453ec341b9d750bef20044c6a14d6 GIT binary patch literal 877 zcmb7CyN=W_6txrQF_{OC3Q_hF#Ef*@lMy z;FsJ|?JrPquQRi|2pSyu`uLH1&OP?C=`>k9N0Q)=W<}QRCIU_q- z(Vh35o}zY&vLDvPTJladrq#UCZOxtPrWG>vtzRl*8BT1tJ}>mC`9bsqlKpy~b@e8z zw&gm*AD#>uD%GC5Iq#}$IXGdmkApK=2}RB~U+n0!)MnK-{OJ_MImO=B8G10k-ull% zbPTCdUyoqW35GES)H(#Dx?w)L2h)EuADyJ3jX7_MT5@g^&g)ie72*l!pSFeC?~F@T z7*oq`*$O>FqC3}YfAYGUL1l(Ph}ndtW1HMqX1%VmkDT#cH9z<^-}}b*3mT2eAN+Of xu#LB^k-#Q3yewYh)6yX>FtpyOxaEk`=xm8!3?;tA=V`E%*qc!I`60bee*^PD(iZ># literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/clip.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/clip.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5ec0203446f00dc512778d795b89212fcdb19b79 GIT binary patch literal 2266 zcmcIlOK;mo5a#kt>S4!m+z16)9f|@1TB&}(Fp8is>KJWMKsI8hD0JB}T*{V2k?eAn z$O3gzF1-}J^hY#5X%D^hX7<~e;mq#r>~OzU^N)WH=x?5;{i)r1 z9Kgpwc?OJWjKo@xz^KRi*ytGqWkzg{t)8W@8QWv0=O}Cec6+YEHej#k5iN3G#-+4IZOr}XrP zlhgA{Y2<>pOlgF1F3lumk+esz1AdiDGW}iS+wkdMUv|Ve>+~n#sDr2cdAVXd3^k{s z-?=UeA@95_3!@Xl$+oi_>7y?iUPs|*1AOH^Fiqbws>CFlWVV5OZLe)sc}6=MNagtm z@>1p*vwJVsW?>G=+$yx8&Ww@9&p~GlO=b#fXcs0FvOc$$G7DtRQsyK-3K#t>2(w2f zpDCYq1FpcxfLR#><_#?|3v1}j?UlU?_HUKFyR?71w1@f9-k&=K#;X8Tfoec?pp7eQ zWdBO|CrVp`3i$)1n+dM>!Q2JDRhWeft47IIVJmDa>?rI2eh4;p;Vg`~r!-yx6*cz~ zjBrm^cvpCZy)Jhlk*cG!A4FP@!s zr4ff>-eqpGRyGMid>ba4?ld93}iQx@n-9g#~z2*5U49IqvUCQ%No0AjIMD zKnB$sQ>mG)%|iG{Gh3p90f#m(+=^`}#K7F?7-#sJodwef&*&^1u_ZoTc>HkOG>$ZI9Qkn$gh*IfOI!@UnMqH)z zr%4bmHI*<9@_ZbL>y+^waH!6k?;_emwvX%p+4{&8!g^Hy8@!4+UNzUM`qhuCCcdqT z^w+(&yoq)7-xd9KS;J+oZ{7*-+H!l@mg!Q!u|j)~|6_Ki#=ji5kYNv2D|**brTe5z W!B^Nwa=e?aUfvPlhD~hf@qYtCuop)F literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/compress.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/compress.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e4ceb30be4a45ba1cdcef505370a1a2a4757b9f2 GIT binary patch literal 1394 zcmcIkF^}6e6ecNBl6^k+a$TCD4cfFBJoMZ{ivj_H;Lr{&P~etsS_nm?e6l6VCF$mJ zkSAs7kgi$s2fFkJaqV<}p-cOoY+nkbYiaQ5d+$;2J-+wJUmYKhFMiD>=Y;%8{u4lI@-}W1zD-YIw#e+M-%CaTX7l15UDp5*;hiQ=MqGOndr0QJ}vhN@(6k zJ?&{WQuHS>OKu@Pxt!53{WdRF+Nd9LqiSuzlC;KL%XW>>m$KZLBBbB7&Dv_`3ViRd zA^;b#-IpLV$*3Y3(~+Wzy(Ex}1CA6QumCJnJm6R*P(x}3yjCy}xJIzi@FQ&Z2MAA= zw4+Pb({0o-Mema>?>JZ@#qJZ(#9oUAEylA;u6Pe+tWtaF#WL=MN*A@gX zkGgm{#u(TTupKG!ift1>lP(5%+{NHw+Z6D$OS-gYU8LeCq$A7sI$F|BEGSr#H>_i? z*>7}#EgfBkBd?8XtyERvErl!Gq6j>{t{ikzDF0%uLsA(ypxumxxH9XFcR}RdTX*|6 ztl3H6MZ10xQl<48k)1#gdxVjqh4z8@G9)mIs~m!*MQfbTjSsx8oDah0W}$=Fc|~RX zH(!U5X}#1xZ}K{fZ?tWltgDp{lV@#P>)gmDcdPJWldrVg-=MT@BL^OsR_WO&L`Cfa zMQI%hT4Tpx%2G^;xqc`1Q!xDXbnct=yxbJ4ImZ2Bm#D1U z=YuYNIltOb(9NIiC^;|oq&tIlBoefyHOCOloq`~2LQ^`WQ}&QOpr`aCx;Z(p^lX3l zj$Fu8+yl9$0AQ447$uAkhDYI3u%Cf_7TJ&BVLwLk00maR6AuA}(J$IMxTbuJUN^9p z-JITKzH|Q%xyOg#=jT|^(F9aqlE)%R}rs*1bOSy64WBI}cY@!u?N)_|6FVL9R3p@IIJ+0ZtN0 z3ldZKvx1d8<`lM!Vvmx{mF|>gUPcf7DSb+$C*3n5-HcE9lul_JNcxgQ z{!fTY4kBt+A0_E1tK_q!l0~Lq#ILLBov6nMn_T3RDmC8Yx=NEK#a)ZW0qle6KDf;0 z7qg5@D%lwUCI>K=j>W()UFliu0rq8Ju`ib(n^3tBA_Wm_bHJl5gXw$VK9HQ+ut7@? z$rA{E%3E?sTiWsgmHaas;Gvv@l)`Fk7z#t&1k+pK2Bamg)=ue1P;Q&Fbenu-M-FVF zX1U2KT`M7nY4eRl%&_hQ!-o|L;Ej$GHPFh35a<0~Q;vK2BpvloqWiObc~KwRzG(8^ zo0*Eb_j;ykFSWXL$M4U>elgTdT9@O!Rm=)g^vKEGnX+90Gi6 zI+I36Os&8+bGuANnV9FDtGX2S&Z=5wkz;sTXyafX<6q9qev7P4VY zZtmD(YVz))n!EFA7V`mxwHt5!wQMnsg`%*ejF;N_x77d2$prn`3HR{jYOKY8btrt? HqZ{-W9~2^^ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/constant.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/constant.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ee4fc9047e828bb3660edd030d5f10baaca697ea GIT binary patch literal 2118 zcmcIlPjB2r6!+NU@t<|JB@K|K2o(eeAIOpvRa8Pz1P3Z11_r#G7aDCQVCk*qZ0x%(LIj{N8V#A8c&Ihd<@~Md&zx zIoB=*_z;?sV1y$`>0|_+Zs}HD=8!D2y-c zu2R>qX+2+PW&B)gsZu5fFoCpF8subOPo!Ol33bDBDf4r)Q{|@x*F~)w$tSX@IFeU4 zqDYzX#-%dUb__dxmdj&hVjG*|#4@tsK`GAfj=Tepe-1{vnvW)n@#)Bh`J{_GDVt~5 z=Xx?a>C&V|PrI~@#(ge!=jSHiLzqV%8rp`8G zbqD}h17;_rb$_*75fF}i8^%*l-hzj;6Ueu$vFq;479bOy6;e%`n(w^_U4?0LFE-aR zuigLW+>h?RaqdU!xvjJ)G~D<100gmmI%RSj7y!It09EFq%G{X;Dx;{f4*OPTn#}?j z4*@eB&El4}e#@4f*1RK3vq{uEm#XN}pAI^GSzb|Aas!YFrnQ)k3uPFJL>af9gCbFF zR7@)v&=Zq9!ARes@Y3LBR<>=-yVmU3n7%s6;k4h#RlH8d-be73vWa)Rm<&-g2?*!n z&Z~*rTeD}+;rcB837r*tY75R<$K!`D^C-N2`~VsCR*YWK`e#9VUxq$<%~uOJ!a*86@#AG_vzD1zSi2l|5E=fih9BJ6!H&=+3$V9gM-h1`h&+OGuK&it)sH2>rHE&#cQZmFDWgj^>Mb*dAgp$VvxErhR~=BNGg_}5A4AE zU`&8hJ=ixs1b+CLVcne-QdOZ(8i6%MzGGMVt~I#Vk1e`dGa_4C z@JC>anz9^)G)WQ)caq*RKK|3>Js3CCR?eIy+A5fB yzw+A3ZHtApnm5DMJ6*-?{u1G;7~@)Bw+Rz|(eZLXAd1=q6S@hp4R4Q;P4X{R+U|V- literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/constant_fill.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/constant_fill.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1acb5571b599fe20541ea05a743b1b6559fd73eb GIT binary patch literal 1603 zcmZ`(&5k2A5VqYv>0~m)Y8HkGLZdz*nG>s_gqAISFX%gfZW=DZrL4 zi8+@PR=P^fxnq*G^hey2J~5AFv_E+aCo!H#0%ntmPwZT*)y)@ILhHumR=M2GRUWjt zFtbgqw96srd@Zca7aC;1^#+vttD;u9ThwagkJL+N1mBq)9hf}O=ht(k@jr~p7dF?; z&e~`g`83$IJ`v6t>wDjcYNMVR(-=66ipu&}H&Xd@bq$``--tPZ*#Ev7yLvq?H^pj< zCHdGXZ5vZo&2`vwSB~eqs@d`PyDE;0eVup-g&M72`5s#2#atDuK4!HCK-dGyXv$9M z&HIOi9lg0*P`n2NS1ijFOp6wNSi*i_CZFEFebTnQt@Fr?-Pc0u03 zJFxYGnQ}ZNgRf0fC<}4%wJ@T74~}i11H1X?E#Ln4$vu0pX=0dxJ%50(Ws(laZ6q1; z1^9D;t7M>y^;49W6v^2FcUH_i-y)kp9*_Z9MlD&!Ez$i$?QJZRy)EaGWx9=n#biKc z$Uk-)_Fxt04ZB2U``f?6?GDTgUL}}&2q;|`GWxr57 z86Hji(XR4bE(&Kb%IQg96c={KNrP1~9fVVW`x^K}x>sujRlvNO3}DzZU08es`3wr* z#mok3`wkea7S?&@N}mFk3gLWQ2++hxDE~n%R*LW4DNR%J@UcMl4%1z!kt609;avoD zH#qfg4s>5AV;7C)pA6uNJp&*tV?ElBQu+wiGj;-a!EVmp;=%p1$*|)y&NZ|t=f1~z z-N;Raa-Z`bHlo^}92FIGc&*&Lk>&xq^AO%q~!2l-xMkjB&V|6IE}#;!8RSMwnPeh3d-37&;!$v)i$_8AsAv|z^i K6n>DWQ~D2%J(ZOJ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/constant_of_shape.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/constant_of_shape.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93b2e3ee5dc8bdb2ac0fccf5d0ac676bedb99bfe GIT binary patch literal 1070 zcmZWnJ8u**5cX>yw|6;E3X}^C?G@Zf1R)_sQ3OShkV27e8*5p6@3k*%U&5hHb!lkQ z($FLRl3ObN0u|%k3q;`6%zPg2jOQEA(cWHk`Z?j>C_+Ebz2yTw1<@HOfdtM`+*uqG z*pr+VEN0mGXzmq$?6;WZK@rAbi#@=-xQCGpg}=qJC&@C};xi-y;ol(POMgqZc#Gq{ zz!zv7{)D^G`54xdD(EpPL%}-Kpk=?o8E)7NgU9#;J>)6Ou z!`ot22zkFFH3IYNY-);nnyu5-)Mb0xrO)!}s@-#wP3PSl=;`}zE~e@3<$0CyHv0tl z^)98-i>l-=A3|RJ2oxd%vQPK%kVe>jLlRPkKaKvGoXMZa^RZ_`&da2boZE==q7v)e z;Q{9#)=9oQ>8E+3bs^2X66!Hr)N;9}4xP^p*8oJjK89>OP<;S4`b$v_or5{zU9+FG z9W~kHj`L*4neQCRO?G_n-*0!v433o>V#~5cp0_pJtIM@qx#Dbi+;KZ`Q>0zXLJ~s1 L1{gl-<9+-adAt^L literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/control_flow_mixin.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/control_flow_mixin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff4ffe041dcd5751d6ccc6fb2f16437455d50c31 GIT binary patch literal 505 zcma)2y-ve05VqsA4OL2cjSLVZR)i`TV1O=cSu8h~LR7~tb}GsYOCN<-%F4tmFmdOo zofxompYA)~&v$n*nT%&UC3lRmFSNsp(VL<9a|B?(HEVdmIlE;Lf%sq`D*i5t2zd+x zk2`x>}x zm-(|YpeyI|g(_E-fxNV)byiEtk`3uSTfaGhJ?R=gLP&Vv|K4MIW1F>dwYO%!ilb(3 yKrkdYXzsm)Vn+z%>}L|6XK^=O?9bWjbEGLK3MGH_>XOU;Tvv2&Ps3Aj68{3yQ*BWI literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33b9ca5e5fa1e4ea9dd143ae8159ae193dd077c7 GIT binary patch literal 796 zcmb7CJ8#=C5avs=EI*R5-8yv9Pzy%4q9}}XNP(bUx@jR)k#1Z|luOEa6yBUAd;diK z64y@o3!Qo=*+zm+rEsT@ulv5cUgx)VE^g{t?3B+(I5F!vgqCK**EW57)nyCc9R0E4O)2Py#O z&|)qH1BU|x2(Swl0%RoI^P+TKm|AHc zuC8r1gcyI`rA@U?7n@?0Vm5EO`-`%^Zs)RDq?cX7F8$gSAjP1Q^{ww;Y3r7? zk<&hEYK5|&V@!Q=-1;y5wg-U{Y9st{i(zeyZh#I2cWwm8$48DS&JX-2&-thGB=nJ# zCa<)VK9;ho)uu!|l=8-2 GO8)}=*$aEIF$gxkUqMroGR zcR77S+U^b5Bgbv3n=iv?Boh8znDAIg&^T$5oCj%kLtzWZwO46!_T%7ukmx$H-zT}~ z3mKt>+s^>z2!?tBL{vWdOco71Jg_Ck7U4nsaK`ZpMr9-?Lt0Rv ztYmYXX~C8fD}di2V1ypG4bAeNHltAG+UdnODKT@3ciTqG)$aC%zFLEh`0Ebvg>_X~Ww5riIq4UD~$ebD!VFw5c( z!OD6aeaEN>Ytkm2Jzhhr^U3ar;ZFGQ7@n$*`v7{uINc?4qcE=M5OTdsKr)w-fzma* zB$u?uFyj~Q+{!8LEGf4~rhIz^pcS|KZQNh7q>&p#voL{L0H}F)!WpsOsC==s?pAl% zg*~)~4re1K|3qt7tguUV&5}QsD@Jwdi$0k<-00Iw)}y?}y$d&YxdFD>5UQ_aufeB> zWbU3HvOd;*<5<@h$qx7+$|aV#G=bb@ z0|gwP!B8haast@GJ)8m>E#v_YplBJryIV)Jj@H&8Q@CF3H6g+UX8}hCY|bEd$Zvt= z4VlIlaeRXp-{3R2!QxnX*EY2gi$vRlB%9<)+ft0vGXZ4}MG1>mBBsH)UrkfrMG3?6 zYgN%EDHm-fJusLkp-ZOuA+nhroirz^iddI#}97iPaPUF$S= zMU40P8@KRRx5-C%%u6SEu&DG3wYIUkKt6^Yi}ZV|Y+|z1Qy_%7koqQTZa$@+u?c(w z`x!Io6S~75&~4y1jV7CI|2NpjZCkrRkc49q1lkLNampt#@{J%korLjnr5?qhQe%;y zqVGTmb#7aCXW6=gr9xtn_&c9$ tyIsbIr#;BkSun=GJ86NUx_ix^%Dw98xCe{C4za=&zAl$FDEt7ke*p-P?v4Ne literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv_mixin.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv_mixin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8022b90addab34908479702e28327b9ef17c5ae GIT binary patch literal 6223 zcmb7IO^n>em1dD_b~mS|=SQvi(^#fu+1A+7$cnvAHY+=lrEwy_mIO(57QHrTP8Vl} zJ>6ux$d<-q_C@W*^c)0efnc%NQ;zXsPdVhY_st=PoC|wcBqv>h9D*EjNb8jNTL z+Gf*KZ4>QMv!vQ3w5_Ivw#Cbxa<|f~sCK1O?b=Nn?P_!ChZ?u})YlrH@+(85S>x=k zwpM$B-L#u)OwMfkiOapjbGIVV^%9Uy5~=5luDc~7+!Q^gxpBYOi$oH;+`k{Re2}XC zUd!(#K@>h=;0Q|neGz%Q<;BTI!Cnx8Qn~GM)s`o2U%l?$`@p?%^V+SCZeP83mah)4qvmtAm+=Tp=tX_-4`-&`#LMZtFvB$OdNCY8ylCa4I#qzN8&miOCI&m6B3w4%w&rVfj!SX>E(6 zH?VlAT_!z$4cc|^7_!4s&c8zZ2jzsN<(z*dHN?Lsm88n`v@+C(j8{0@))%!wHC#BJ z&a05sZch!hT}%9t+Pn&>^^7M;3LV)0sxNCJeOHhFkkt58dwO(aoc4Lh!p8F}4)vto zo=MATb*K+)wa+ZC@ya$ESq*KdAF`Y_eS}uYX?4y>_I#$vXNbOAe$3(?wfM}k#%Fi+ z$4vY*H9-B(kvUnh3ySzjGS{9T*&`D>*?jKM2u(hV`zPb|^J@Js_z6(2jHz>q`YW~K z^)a=fsJ}^QZX;>%lkMqZjI8pIjf~{PZsoBq9LS@KMsl*fz!&)9P-j|LQ@y3EN9)?N ze3`>WgDL1}F}2evevz*{G6uD@gw>xAbwt#PqE3frNtYu#SsIl`&>cVZ2yZo>^=38; zJ6pmW!S0!kp$A?3N3zUUNy2SyP=9RfJxo^8>9jV~uWOHu&+Y(m_F(3qd@!}8^A~`$ z%BVz0JFKM&w+gKpN@n?KZbRnT(bT96guXZg#<$sEZe%E1nBsToEVrQrL!3|N4%mTy zP&ue=ncN}1guszS+9Lkn)dq9nSt0#eOfR3n}n4 zSV$Mh2kJG>B>APLB9rHQ~F&QY3UMK9c|1l@ba{(+5%&w+d`!%3%bz4s@;ABV z@z`2tLE1K=# z_W@=-LqD$u9Or712&d=q*a>1Mj1s3$D~W9o_WH?rXS1I;+;4R};m6KS^uX!%TRTqF zPcTYru$KFLJ!khLU-;*X(XJ0siVhVS&kEr@*a^VQ>j>ZDUlOZ)wo6=taN7yCoY+qa z?sp?6+3}rT?Du)(_9Xs7s)Bh#-%z4*|6A^Gfrq1imIi=~z@CE16n)8OU>x`_q++Nw;@#tKZta7=_{9g~SizNNjbY2deKT zTNihLyN)m7i<@3+*AMwc_5NL|3)g#J{>i@F3F4#`b$jof1;?1gw6y&**NW0^o#wA! z?nEuG6TgQ>FH!dg$m!`5ui#~MxhIM5oEkp()T*f13%c_ zNnqWWP@WK+0O1H#u!7O~jNMlQG_nO>4P=!E9W@%ua&9+ilE=u3*H0pXsT=PQGA6yT53@==A3LU7(K<1jb^7?c5J3&^a(q7?je!xZyX$}dO z%9jj*3R|?_RuFQ4a1OJ@JZ_M$9w(9Tw*CA_BFlT36J($y=AwaH7gvrYS<5^*pGSy( zN+^Pn66!Jj_?XG*e5w!FKu`5dnng%O5-uY9 z6f$MJ$ye8mOpmXjEm;h;QV@`}u_!S3Gm;E2A(Mo)$S>(fPm)GyY!!_}Yr}v;rI{33 zxl9y21qGpm-9$9elPy_N@ePjzQ2=|tij}guNiOIHd=JKEdz0PeauzjQ{$=QOgO;03 zBuqZU!dM;l*gV_6M7UNbz-Pk5x2}Ie!teiJ>_J)hE`kGPimwK|NOwWE*YUf4m>?bm zp)+wP0I{5BAvtyAC`i={NI{zjvf_1`pmN4o{-1-CV;rh1ZTj0mC{42OQyQaurGPep zJX}+`UgnbIif~T_z5?>cxS=4>Ltf>6(^;I4^LRk4pONl=$I`Lm#Ub1)12)FuC=nV* z1K3eBW&-F+0CCKYzdB||vZsyf83knaB(H;)G1yW^0WOk9leDM~z zVdxD!q#lNHiehyR{lc0TY0%14v}VdWWoG1_Jlv{KCM!U<+l{!Nz0cF8{R0?erY*w~ zFQND3FZhWo)cP~EuA-IQh^7YC)}*Bhomd(jKa^Ga{FH@^vKPCQ^98w&Aj~WDNwXah zW@t#3kPo+gS)zQ8bhYb$8O!=rq;Wy@--Zy8kXDXH_4d_qnI{cwB`RRsoKxStvf9$c zu2E0Wmn3O_;&uAI;vxu<^5m`C?#DOpB8A_&b8q9iyYbK0Hf|%ot8^*IZnAc#A0|OJ zTP2PCpoh<7NUc;$`1GzMn=HcsDE2nRKhc_5GRGx8DJ3(?cb=oXb(C`AW|Z8R#Hs9M z4XQgzaR(phq~-N`sJo;E_AM`w^HdrKtsrqXi?4Ljz+11qAdOZB>I-36X=imO4_b-% zh@`Xj0HSag2_yRe=(hUYYfcyVXi*q%VwIb_m#h_jM$5z*;!(~?;zjhDxg)x&^oXUt z7dNXJBJcZLyo)JWnwTSEUXJHZ`z8&p6O&qAb-7#pPA6NBX4qpk=caW*R!1*Bg3`H88qhtTGEZuEs3g(r3}m zFWq8w!$#j^Hrke6*JtsZ*GT#%G$KFCnuULZr16XgL4h)jczvzvw%b{pT#E?A7;jm s<*IXzC}X@?RZ)}9Ju2L&*rK*MP9j;koW0O{1f7_~tpFI~ziAqO1;flCS^xk5 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv_transpose.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/conv_transpose.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bded52eb2baaf4e6744aa5ed2d442845f17e1d59 GIT binary patch literal 1271 zcmb_bOK%e~5VrT3q)A&I66Izjgos2FMQ{XEK_!q7xscOdtYz&q+wR(ny=hC-TYBNZ z58*HEl~b=AIWe<&s1d3vBy4&7*&fe$<{LlnbXo`BV*bk^a0rn#wurGov$ipb4M7koJQ|XBYNMG#C={q9YBD^Fbl%b?^ zZ%(mC4bk~Ty1Q54k929Z{U%OMq!RCAB{FGXC)7%vb6o)3DPmKmamMYmD6}b2zpz|L zo0zmHQ?0J(!c6n6R;M4+^HfzGgd-CxTWBjsvnLyCc9xbCCekd%>y|xw#RkuqHf;8^ zT-^~Y0TVi#q6!2Qcho z5RybxkjQ~_QQ=$?NQej66<&>f;X`r)gR~^TRo&2l590$2dmqFFIVKnM!V&Z#uq52? zE?n}4)mB+Qfr~ULN06)LIwDwj7*p4++$6J=r?ik&aB>!#Bm0Ax9kBZQuwUjye>_c2 z`bfe4!WsrtuX#D{PZliM{^td2eKg9~ZhFPns(C7ng}m_r8nty0&g{Vk3B9$>KL=@= zU=@NhEtp~2!pSvlm`n%7HVSmT5W9e?*4p3T9;{c7+PmRVgJCzQ8l0;*mz-BE&T}oM z8R9nQU#4-kJlRUJ*xFo{6D`ag^m%vfc=HK0qsXfDKs3U(H=GSO+}~K3>+IfEmg@i7 zyRFE(&5G4uwH)_Wb1z(^=dA literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cos.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cos.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..43cd732ab80d4ee33a390f8a08b692020029bc7a GIT binary patch literal 732 zcmZWnJ&)8d5VhlcZEp93s7_SZreIT0AS8rVP=JK)8oD$l#Ln&B#_?ijxdUyNYiKC> z5Bw#!RQDICm~nQGm2fnZ=dnHW-q_D(vuyFb;y)=Nzsb=^058DoM{t4&+LDsOKWGER zN=7lp+E7JhyBPPEcMB+*@W%k>6f-|%MJ)%U=bjGOJMzNq@;#p-s|Irc`| z8Z#XR1F!(IXW*n)PzI6-DuO!#)kDFcdT3B>9e~4uhtS@G*+<}ZZt_JMyV4zhK0|JvaPVygs^}RkB}dVNM~PXLsbVgm28`P%91d6PNwt>w>;<=U#Q+%nzjJ zd(wO#Fi5jJ`)}J}8Cz{aa4u7DlU(6dnivBNbbAU%w6KQ;xw-V^DD4%#28$BXU`qYR IV)~f=1s8F;F#rGn literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cosh.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cosh.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d6dd6cf82187f3f93e24251954d9c2ce4599497 GIT binary patch literal 736 zcmZWnJ(JTg5S1+XBfccVP~A|`x*#s7U>GI?169Abos3mKPVx;$jOKSFTvagaFR&ckb=TLXada& zMlr@3uEQc6Fb5nJ5#UfpO{|k5p+to;?x~6ty`J>+4UvhA?}&_5qFB#++S4MH^gYQY z_fUmgX4KDLmDNVI@@?75Mp=l&rfqM9*&^&}QSaL79@vs`vs+geWw*Lm->zHFUmLfo zFx7D|0821;4o(dcia;?*WpGEJJeLg0bBl7T02~fHg!T^1Jpi{S*JMv?x(~k7E96U& z>LXoll;~9Jj1{#tS`18EBUQ#cs~YDyPJFbvDeaZ}N$eDo{eGTzdYjj~YLnxECu4@X zF*n0pbalQO)w}%T*p0jbVT8u51n~XH`==r&YHy(#|2@!0*IijiEJ@W3hy1XFmPM*auzh9}l{_dU2$^ zIM5b{fJL6g`G4Dv%h+to!TD6fWeSbAX(J49R6cMx;e~CqNX{oOMr|+gML5)u1XDVE IETRwTAHTG_+yDRo literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cumsum.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/cumsum.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b38b1aef52362f41b209d05c35d2fa444a5e1806 GIT binary patch literal 1691 zcmah}OK%)S5T2f%*UmodSORPm$btZA5An)&WO0bVO0YmeaxCmf(Og>N>0a++UUc`w z&T4(y9N@q|;16)&2lbUx{sJeeW_E2OA~CC~{;H>@wz|HmKInGCqhDk8r)yb%S@)g* z@DYgm1r)b9Nv(*$YNvKaBT8_OrcUNYZjGJP%lyc%u?skef*N~(TT!dVKHxA4i6wj< zEQtsOnYO1LKml)oZt?Dtd~fj%58hfl5blyLN%M=koSa#M-aE*~IvEht64!|+^`ywb z=sk;*naKGMan4gAVaG4>{F)Udz>PANdJ?BhRb^R7jsB%#T&P4&))9O?VxuZgjQ70C z&Z_Ku{-^={NnTc3!P2iLxjxt*;&S+;Kkvs<^z%aZS8)YLr*o03LXOhnYB#}L*AE47 z1fsqGCF)v6wxFDF`>nMkkpq}=r^YUK;jErS4iXy_K0uJw0r?R`<)E}RB_K8k1#v)J z5D&x$2|!vPAxImfbJ@9}3!9T2YeA-6Ztqw-){V1pro9E7`Esf^rkkAV2e`8&A6eW1 zahEnyhv}S{wyqDy_$1MiKnnBC`$fXz&%OTDc#@1wcvpzQma+B71Q$@1SnnMgXB?*^ z3wXAYA}dpI4KQ56y?ywyAp(wPrl zoU)fEXD?4rU;K1_{2e=f_5Aqs+)$Z}}&s$@3A{(9Wh1Iey!rbokZ(}HSv(X`|+sWMe%yX6}bVtAH}MKarhXbRc1 z=r(z1Z;_BVWd5M3=I))}E&JFC*a0>Ba{vvKz$gVaVJz2dUXmME6Wm)8PG^pMw(_90 zhqrL2_QG2dVrl%+nY!HJ_R?OGTib1H?)`4x_zUQ$1zETYpZmYjOB}-BM7AJ}5)|NVbaP{^r5gB+MN^R*FD^?MT;p66MJm5SFM27o z`8bPbg01>(B#VsI1C2xt0{IXle}d{$RCP9w5Y>O<#Mcv5$EsOt)MxP8gqRv!8EkJ4 zzg9?tWe223JiBN2NJuxyhxC?*JMWW$X9C9ZI1`MSkg=@bRf@R7*w0m*uHLkhG*&7T zdR%b%IRuxFQT6|=Fqe9`+W?dUD)2k)`M39n={+~j|J^r(o(b7nvL87GVN*mzC5*Qa~mu}$!_Dcv{N VI12d+><+p8Q4dDJBR1*T{{TND!S?_F literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/depth_to_space.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/depth_to_space.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05f7afc993e2f65d0a576d063a5ea36d27ad2bd9 GIT binary patch literal 1875 zcmbtUOK;pZ5GM6nNvmByk|wtMNKQrfP;ZT1gCeL6v_JtLk{k*l03nOizVz6VbnO_@ zX>;kJz4p>S&_B}t2VUEY|3Xil;jSI0O;44;PctKu!dAy=u z5#Hm$Yr+E&tlSk{(X`L$b219A!529lQL{A>n(<6$tY~DFX)q1H%<_e(`PW&^OCiD1 zYwG%vHA@tA!HV-bH_3@u>gkK-`7+Bzj@#WlE(lLysLucdNhv3(BV10o^P0dBJdj=P zS=k5K$0LG0;5|H=#DwG&03ZC~hQ}~e0)X3acSdIzhj(fMDe9~eCORvde4%Dn!o*f& zDE~^}%x+#P8N*r&f1QkVwHz1c`C^Q5eX2#R8d;Rhh1HoZ#?y7^YJ9d%#h7ETOgBtn zxQEMEW*-xmX)P67$|e^I_F&6QX4MuR)d3*R)yH?Uboif3ayuPXgfM&<-@s7c0<;dN z`=q6FAi_S`C!MQl>&~4OWUTYF+j=Yd(&_vz(B9mKc~JhY*ZOUbyH7|<=Dn5{6f}?f zzc{V)v-1<3VCsTX(_cr<_$=2F6K(o;nDAoc7~ckHc5+tCq|z)u=NW72^3^Cb!K_}M zYh~P0)F#5v)HGWPiJ=%TZy-k@7h;K$+(zR;l`RC@I4xvT!B)Vly5R!K-nZ*eF~Q;@ zlM`j=r3o&X%<6?1D&5FzA~rNN!@Q}${f%xNys5E7rkLn^A=Rv@+0i{v)ewL$%!CU3Ioqk)69aw=SvE}#^g#THN-rN>q<#b^Sow{)3Z!Ow-P_zij8ou<966a@FwkG62Kl?VDGnE&<_!hdC2=bnFM_Bqtk8M729@2 z(nj}5J3yRxD+h}Yv`99z81k*VwBQ7&v3)8rSC$eI*=)QD%96S#$Invt_}PiXoLpm} zuaP#_9s<(#8e0`Q&I2A)K%jM5FpHys+=Y+CO33>NxLm%6@BqOw#044|-}1;fx-dN{ z)=H#-1!~zSAs@o*(T=5y+{2ao2nPu7BYc4HAp&kG9|5HPnY|eNvrOkx)61d1Yf+kD zDrS=@c)XZ#Jx%=_XQj!;sU>DQy!CALe{w9oCCw3fQjY=dkc=iy=)`mg-#vQZ1a!{_ z+C6+X?T$`IJrgp9_Zed*W(?APUZR{Z_T70_ZvOQ1GE=G&dfIR~0EhA;gfYVHJ-3#y z5$uhM?WOQ)4ZXxml2KxFZ{jz%pZo;=nxXAUT^vG#RZYEa=f^k3n~U*qb1|}wL1N+4 sy?;%+`Hc*b$PhDp`zp0(d)J{&_+%aZ7f3OMwG1Jb>*h_|fbP=20kR|9s{jB1 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dequantize_linear.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dequantize_linear.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff8fd92ccca081819e4a5741067efe8eb6f330b1 GIT binary patch literal 1479 zcmZ`(J8v8}5awfFI;~~-6nI=6@5-5^zVrb6kqWb9Ym78B)#YoB9PM_bvr+2 z`Batix2%+f(x8c}vOE`6?RI}rf6lYgju-01xKx?WankzZFgSr`?gJ>lkO5O%Qpw&E zNCXKb$J8(mWr#_20IoR$z%Pb|ir=A`F91s>={|YOEm_hDT|uBJ)1Q|dCCT>**n(CH zycD)l=%r{GPS`SwM>(1uJcF$CITz2h9bxk${z=?|=zY};P#3E_qK3M!u7-=tR)r%Z2 zROzB|SIxZWi(RJ(Q_BKJ9Fvg zX8t1j4mkYtyl-c9e>l&leI(Vxrf|cedgEnbhy78*JJUaFc-WU;Nhb==x}*BSbug*O zM=GCoAh0>U7P$m|5%9^jFw3YUdFHd z-8}Wx^`z2xNpysO%k6Dx+`eOW=z=^m*2PfF%pO11Tj;Zc#t_(a{MaRCer9!+TbIn{ zg&o($MK96U(QOyu1_BE)k*xHVff8Ld+^TFL0a+0q;!FTDJ2dGiIjjsFHdQ66t#g$fpg!b@}H6 z3uN#aNqBmr7rV|C$MjuLyRLuE?C@yKw4;`3qE%?TvxB?;aa)`H4aW={>HTVaZIUO= RKAz$AH+V=1OKHk?>A&w#b+!Ni literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/det.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/det.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c056ede082bfcb4d2adbb58b7822b677c7f8c56a GIT binary patch literal 688 zcmZXSv2NQy3_y=MNmdmn$j~9^)Kx<*1f2>Lg;5kpfC5?CNy|aiot)UGlY1vMY2Zy+ zy7WK#OSg9FFJuZS+lYZuAjKnf@Pcz82ve_`-(;~37Qpv??49) zFE~()>#&K6X!Jw$<01y8A{h;!Vg<{|G8y24$yi1YOh$?ie1HLp7ZSd(Z1N8)v#SjJ z$;Yxp-ZHnQQaw;4O_Ae)UXMD!-BYgkX|+AN{LPx*IH5Awh<$dX{E}z=aqIo zq=S!Fx20XUKg_0B?D1XRHS4_Yt5r@H-fSz>y1gCGqO0@k?UXM6ww*ecs++BU`t*mg z?xr>3{CrAqBQd`}!Leu0sjDpVi4dl2ln_1@qG@HX$)5`Gy)X4Hb5!Zlxkh!@t+Z5c zJ= literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dilated_pooling.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dilated_pooling.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1492b1c90b906d38c36dd51ced65c2a9b9d7c2e7 GIT binary patch literal 16990 zcmd5^TWlQHd7hcQa=D}^iWYUVGEr=Y%g~f4$(OjcV?~$5h)t`uVmDOP)oRa>Tyi

pi1U{RBN5 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 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dropout.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/dropout.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8bd512fcbf2b2c3d9ac3bdaa17857ff76bd6fd06 GIT binary patch literal 1507 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 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/exp.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/exp.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c3586dbc757611ce2ab3b52cca28b2b7fbb9ddd GIT binary patch literal 872 zcmb7CyN=W_6t&~LCNr}gd(J)fv*|RMe=B(G5%QDVY7yW$bn^j%AcEE;r!ac8 zr&!J?uCdxzK^{2l0}k^La3I1uQgI$rA_EciRECnCk9zush*(6IL_{){toM7`(>xLM zJxNDbz(P(_YL8wOA1lZp}H+LcI$T`{3 zitfDc^bDm_RQ*sDE6F?Am{#*jw~9N_O)F%|EGuhceVo{Eby4Uu^MmLKB>VL|>(n}{ zHsvbAAD#>us=B>!bKX_iVlcvF9|vPHxn0lJU+n0!)MnW>{OJ_6Il2` literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/expand.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/expand.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a569bffb05dad55f4245be292ca69a8e9801b8a2 GIT binary patch literal 835 zcmZWnJC74F5cX>~dr1zh(19)uqD?`zpt&MK5fTCkDGl8=*52B=Jobg{kQ~}=$TbxF z5dM-|s{0F6jCT`=ge89-e;$u#=JV^z%l_bW4RZ57)ejC1AdPLtPe;qNe}dZV_)D;XzV{i1T-IG`{ZqsZe$@oB!$SN0;X3M z#h#ay_22C)U{mLM8WfBfOnnU?+vj5 zBh=8E)_4v1kI)DmZR%`-8rFC)>LZrc5_fDG}FhWHO-P|q*` literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/eye_like.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/eye_like.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d719e8ed17cf97fd5f24ffdc972ebcd1138341a GIT binary patch literal 1379 zcmZWp&5z?W6!%BInzWtHY6Km`0g2_%m6%HG32C(&Ayy!P<^UIziFDJn8uW_)$K>NF+Qw;4cu5c=#IeP(%lMzw_{FXGdc75;54&3wm`m7t z4n&|FbCeT7Ip*Xw0;qsffC`jvsU$%Bn!%1>e+65AjuA3wgDu{W1Ma9L9G@eQC@1IW z9Cd-E8%Se=O?V((*h>K?z(=5qHt_*cI#AfgddGv;M<74i>I2p3rY>rl> zn^=zyC^mw~K{u6;ZF=~uwdJK^yg(w*27OL_7PS+tp1Tw$=B z+VKj5cJw<;>sRs%Uit5tUb)N&sawVPx-<&rid@Le?M^tnee1;qahcpVtZeIjBejaX z4)=#kb_M5axzY=&0v{T!E-qC+?F1zh8J}KV;%h^n-}+4t`?z77?VXK7;`COP0RPS=f{kFzc1>eB`fPf>qeNHmaC5d zv~TADdF*xm`KGY7f5Hh}WNHeG3*j=sML6?(`ftbTU9b3{|8}Ojxa<4k*f%>Wluwq= r|L1mR_Wv#YRqWv(l;j7ld|fViHnjEJ-)`+|N? literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/flatten.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/flatten.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69ef543ed1b5db91f234e85cc062822e11a3b3c5 GIT binary patch literal 1427 zcmcIj&2H2%5cXf3>~>pPR1hscf&+&|qN|D%Qb835Ktk$;p7vs;vD5Bueil0mrOKXC z4qSKu-hfx~l~Z4VOBp-cQmGQRI?BxF8E0lZ^X0|za(DN8EY2xHztNS&0q??V_CZJ_ zafXH%G|5O#hZH*-%~&1`1CJSCKI9mwKn4v~T;XvzjvD+9NiKs^Bm+eo+TaEcI}(3H z{qPJTqrE=1D{tatq6+ywE@Y-OSi-U>jzu|juu4TbD-s*N&El$3MdCiYSWtFb<_-Ym zOB@nKC6?qAK`I8AO6D;XAOp!g=72*Pc^t|Pl+)D#gh6ictz|Y2kOWBY)ueoFsqW9|nGy{#syv8Z6$q#%8Jpexe z|AFN5uy_XX!kS4^^KX!$!R@~0pre{KxV5Ha9)hJ)(>iR3i_#DG>=HD_lv>D9QfUn3 zS{5IV%$b8{=dk)jyDRAqhmuW9gx)>}DQMlvo5# zb(sr4m7rai4s#?O3TdXMA=X)AE+N$nqTugKb zn_(x3GvPn_h4cnk{=6Dg`E-!ZlF7g&d){VGv+|4Iiz*!)wJb4%gO)XewB^Ot^s5a; zQs#MCxK!pY2t;nt+`dhIHTif}pv>BC!*nS9G<9S6+)-DoXdT%oI%P0R!{qhDfx^XDP{IV{%m;mC|=!KY+m6HB~=y z!tv&caLxC>vZK3kB4WL@9_ulnefJ-q^b)x2V^8TS-MV1a)`C@HVbE@H!+Y0`UAP@t rG;^VN7Jr42+c0hU=!>{gn6J}QBid>2`r7@S#&I$bX~aJoNi7S(Cl%}*Csi`Is( z8>MuGx%SNmFoSNMLJ+Qo!V^BH+`A^g9{~1w;Bd%8&=P5^y#hmA!vxshK{tmGHspeA zXiYcXcY2QEDe8VK%cWqQXpPdW)=DxbyH#9dzV)ld*Z?OsT3(j=-25PV1j&BA%saWt z>vgrv@rP%9hPqLgZqB+opZ8Xn{9|uT4!cTES6}Slv(RRtTK0U5>YQZn>w$A&db{_Z zrRW55WxgK3pi>M(45+pb$aP13^Z=&+pguawBAYPQmQpZgQ^us?>jv?Nu}|x=+3gIg zrZh&1ZmzhVAk)Du-Jitna!{HHASA&k$c8q(bIp2PZJ#*ryL!5}Zo0FM?G`jzRXqCZ y*nS%?TqA)^CA=;s@p{9QQT8!Z&KLmc$!T_xTZhNPhz^8q~M| literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gather.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gather.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ae17c1eda6fbef75df2f8759ae783c3f00bc55d6 GIT binary patch literal 1414 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 r6!ke8I6{Euq)FY@Gjk@s{$^CRE literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gather_elements.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gather_elements.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8bf5004bd5f201746274de13bd47a8570f1d9826 GIT binary patch literal 1974 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 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/global_lp_pool.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/global_lp_pool.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6942522f4213ed314dce1832a496bb59039428e5 GIT binary patch literal 1179 zcmcIj%We}f6t%~m$s|oHR8^&wcyyZu36yPxB7{^VP=y5QA{%QucG5{a!<7Mt^VhPeGd@&fo`=B>^^jJ0KgH) z5)CknfedmoAlUneq#v8J#sh3M+m0F0o&f^NnDRlxBss_+;h+eN!*PQb?Fz#q8?=F}2PZCH_U zw7~wGhgAp^=o74-M=%3^9!;n|t|$*Dfj;I9*wq-v6{%tW>&UHHQ5dBe z&r+)~&^ug?VDPPf=`VR%dz)gK%8ZMoc-JA0D9s&B&NAcTi4Y~va?@$LC@adTH7-o7 z)y9#Lu#U>iSQqM~7zszDC|qbxlTx_A4jnC&&N~f9Qfd4T7cQF25=()VEE=Zl`r%ieIBPI_LlN6SElQqAgrW{17grK+ZPvQ)V@swHKzWF?5& zEkC*jOI4n$q6J5q4FD8u;tjls+jt98e7<$N3c9Ps*W&p~@Vyq#@2=1oq#NQY`05jk zp~mzB@OOybhC$!;u;anUu!Q?yx#kCG3*!yWBS2Js=OpM8eJypC;gMR3v-t%x1e{K0B)DOeI2ji8G zNxRjiz|^`?R{P|*z50pTVfRYk?n+;_a%i8v!OkDcuBN?YHQC>8;o^g3IM00Hn;0Mt J+PF>b;9u>b4tS>D*~X6wYkPH9=Cr|yLV z55i;c8oqMcSK!1rZJ`KD^OKo)X1;Iytk>&Iz6$;WBlHs;oe2C1h`RtKk;ED$7%b5w zrwPR&Mm5W$B*I8Vl5O!Nl3?$UWQuO-7ALX9@6j;6hYDyq#QwnxkuFprUx`9$Wg*fs zMX~0l^u0@Mu7rLg)^Cl`X}EDX6r2f&>w{9w6bVsOVoB~0bYYT07iJlxQvxcS7D#~b z8pOQ=RTGH^sKz${VSol`Lo0kkKxhr4Zt;eJ&uS6ZxTbY1 znT)>Cc>`?fPb*b8W4X-I$^wPxJ`C_-NIVnk%=wdrQYB<_H*EPhE6Qc%JgH_rvZ9zP z&%i8vkv6AVQ{bYaV4(%89PFR>3hM+>^`%D}?^ z!N25{ss92K?>TpE1qFd4zkIe6`}@B4{A4)nO}^ypvq#8xa-&6nC(zA12%K4JZEZwuqj!&l*J{5uVK9VQq_xG&y139 zX6G|$qeCt7M(6^!+cqD-1iEQf^^3~bKq@Y5I6uqv)O;g) z06YA6mNxYwEtkbSMXe7TA&t^yrOw=#HD!9z+F{b;)}D0Q3LP&#+U^IT%}h!5c!;DN zQ}5GgW5xJt^>z(+e$gMWNiQ*b_ zuF*7&%5La(4xo5fFldhnA;iG|o}_Pk*J-t0Q`!g4&88f0b35MTmTe|9W-`0?+h^Nl yEJGbYuzQ7)jaC)Inqf6w1&wFhXj3MR(rsLA{InJQ9Iuos=-3-j_xK^*qdx(l75vKp literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gru.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/gru.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e537da711455caace2194a532654d4a9cf92e596 GIT binary patch literal 6347 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 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/hard_sigmoid.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/hard_sigmoid.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d3da18d86cb87066f0cc4a81992cbd38cefc14f GIT binary patch literal 1151 zcmcIjxo#UV5aqE~q_yDqh^;Q|7Lj5EaAm}Xn-~b7#+@2sy`+xS9tuhM!n%^1H0hH+ z$fu-C%PK%B|3az^SCTCt0aAqkABV%)d7OFNHyay`laDd`P7wNu)`koA2~2eaz!Aq8 z>SI_*MsnJx*!pPZfr%e$9tG61*izeZB*eD3TvY_x`Sk}!xLW~a%W{}lG4;k-3p2t zLP^%2dO+*W$z2@+t0^^N~=}aq#)>KB zL!r$^l8vYA;)Y$u*-S*9p-HBUQ3mh>U`QA%#umh zs`F}b=|NUr)qAD~-O)lo)m_qq2XB%VZsFVQHL*L( z$VZK=;C9v;wZN!Q3LPKdihQzt#PE{j9{3|FpTi=zENok_*I&R3u*|bdA=S7n*uf5L zRs9Ia?e04HW5oZYKivNp{b4WiO~6X$>^Z)<= literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/hardmax.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/hardmax.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85ef71c912490c715d95f0608fd1826d6708586d GIT binary patch literal 1345 zcmcIj&2H2>6t*2Z$^4Z8L1__}3(Jw9LtzUDu>lFG8+Nn63bE5pCO?Cnfl{Tbfdw1h zgLmLbyo436z>0I6X{p5B-b6nBd~Bb;@A%3MCevk`a2>2-s`x=BIiWX!> z{mf}UC z_W@`h?2PF^QN=zIaK!-!ihC>o3l(}Cst7`ejeu(@+gOWW#tOWIVZVWBnWDR-r8#82 zOLoa=0GQ?sO|ID~Z@FR%VeYoP8aF}1bJ6+?TYjD3?nRyAJ7mF(YDpfpG@~v1LJy%1 zP1M~w6@cPaDAw{%;B8I2HCT!AUJF(2v>7`MLDO%8HiQ@g#4rZ=Fdw0JILXlNL>#z5 zqbpk*spe^8C?w=~ay+*`5l*&TIIotg#yXKSjj=8`)Qt-YT{%`Qov=sAQo9>vve0s4 zCo^>^JvCLWv|~-?21ct@s^!wu%5ghC(JnH&yBno-)tLDk7g_!G0Sp%%bsSD27o>%C z+}jBk?-O%q9X&Qkf!V@HdudWgZ|5s9H$n63@w6$I(`=P4rWnJ$E~u=i-}|*}vguLR zL3aA4>nKq8p4nS|aFI;wvaG8S*s@na5O#%b(OYbrj#;0M=?yw$Czm!|wzoNb-W=Fz zIDB(pgg_*;Mn@!+n?fg>TcDo=<~mGf2gNQ5jJ^~90CK%|+Sqwr$$eZ}-+k=l@|olF z-T%RL|J?ZgoeRFN{N;Q904R#3tddeo>H1QZwOSR3hf=;>CB&#_ryRUAa*h wEa7bDuVZK1NSom(kalwo#Wo6j{r?rEiyw9AKEan_k?okqY)Ih`Lb^?V1Il7Wn*aa+ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/identity.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/identity.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98a75fc0c6e11bd7d4c5686ca9ef70b80630c889 GIT binary patch literal 696 zcmZXSv2NQi5Qcf8BrA?n6q$lfSvAx`(X|MSE^SdDL$hfiRFO;^OO#8}O;dPNmM(pd zz7p3?eT7cBldZ-;DctFJC*FNOq1PuT)5VWU7+~x-J6I{k3pDo$on#UkRsz1GCTe-f zfpWZw+oVi}IL0_FQ(!8QNe?Pja69SY9h0d{9+*rN?|BbBl$nGpmQVg*Uv`;8c=ooc zSIWrum646In3;6Od=uT8La&A1m^x%1q%wZ#?`t|YE{?$h&7GlB17R5{EwSgs>O{w-Im?5Eoj(AKjE6-fVf_?)k+DkjO(n>wrj-3p28_S0vxci*Z=?k literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/if.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/if.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2970622c53e85db037714953ce621aacf8705d00 GIT binary patch literal 2077 zcmcIl&2A$_5bo~z@p$Zn5EfYP2Jt6AmRLIx7Y7Llm{CK;^ zyAU}iM@n*7Bp!oD;T8JIiC5SYRXyXxOO{0(m{HeMSI=}+ef4$CXKQQW{$<2}_X+uf ztXwcB`!I9@LJ&byGNks&h76u8buxG8Qe1OVFY|}K)!np_1;fDV9_YRgf^qj%GA%e5u)Dz89AKv!nbneXExi|NZToFElZy}`Cz_d!4>q2oc zj!Q)$46ux3&JR_T$0O5{sh0KR1uQW1H!$>1L6l@dC+xx**GXIeBF|h5E`bC9k>J9a zIQIbyaOw>d=H7Kppl63iDw>W=dz?>aC4Um7GpX&e@ocqX3<)oU&4pooz6Ht=nUf#a zPw9n)tV4cfkKKplHv$E8^C**DW>|0A&;ks%mX7#pwrjA<^UwQbHti>~__&V@xL3W9 zq{UM^=Vj6#RV2~<>4H3$V)2EZdP7} z;9Mc|ZLJjs^It1nWlz;QeA{K}HQa0i^*Ut)$L6h&G9SWNR%rWWnI=%De=d=_g}Whe z3c07=Mp419Zlm5r(E+h^ZxIicyS@V}HzD78RUnUmx4u0Vy6dYg*uZ#ESt_lNXvV+) z;JYsl2Bz`DSKmK8crY+`Y>TV;ov0$?mP2_VWVd0QIMr}2U}B>*Zd~L--GQAHlGpgU zRM-J*PVV1wvQ(-$R8t#K*O((=n>2)bgKY#Gq04-F5?-fu)$Oo#;`kPZ#*d*V!NE=F zoc)4LfkKy7AA!B=sQ2NaK0twh+K?(?F>OAPN{@@2@7#k`TT{YL+TinQ;eYTNUTwa! zv*LDb)$PszfDSmv?!&nWInN3)OHprg{&*Ip^-3#FBds%8jtXIuRv%-cpS+muHG#3$ z;)&6y1aAA?w%cu+@VZqQRwkCBriDfCjbu8Nsv^pJmIh_gTeh)Y-DG%eP*|7Y?HjKx nm$Bn0@2+S`gB}Rq`Bs5?@1*b{It0JJ47#8T zMIgd&bOZXr0gUE$U}UWu#YB-Ag`uGJwZpOi73kM1>s=OHTW|jQ`~%<~2yQsb8&z>L z32ji+>(*%Nb7PdYbRmr;Cbv=5mZn&jx0ckkja&-Gg_uN^W+h~+8zF75y5?%3ZQLj6 zTd?>>1yI)pO=}>t3gPk{smCCGpCzVRCwZH#68HMgcCF`SbKT#W$&;(yfOK-X8(31f z>98J>nyzo{gU?dwqN&;Q7*gtEV2DKc2)-eX;d_X`JUSTZ^l$up;@gO^npcuB8#7il zqAi_1Wb9MR%X`ltE4kK{G*^vKV@TgOf56;6^iy}(w3~cH;VI*PaMTEl_G!OjCZFy> uP47XmdxLWSrYHY}?cHtz`$7lB-9swZfsIag0A9MOYqxk28R8*5#(w~FtKn+^ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/instance_normalization.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/instance_normalization.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ff707afeeef26749f9363bd194d4e509d6c2fb6 GIT binary patch literal 1913 zcmcIkOK%)S5bo}I?!!w2!HJQA5ggD;WS0oZ2V@xwkN|;vNlq(Jt3BPj-rad@x_g~q z&7L+$Z~%!Dm;3>K0RMw?U&F;mZYU?JddE%xgScd*s`;uP)zwvB*Lz!A?ZfW`{~#gc z33={|0Uv^xd!QtdG$$hpf0nZ%7zGr^f;=puQRHz5I3C56s7OX@s$xZF$t+#dPl$|V z^oYnv1?yl<*L2j9^e*Wq=ir$f^{MN9D6+XK<)@;QxzaF_RAu>)R||x8%*V?zbFY3@ z8Y{|79aXvz`SeWKX;o(Ey!{bf%hSMfLynH@EgT>cwXQC_@)@s8Sy2_LRUwk37D7tu|5EKdH;B0th ziUHF zIWpoLudfkZ5(P()D0e~3HBb{$ldsYhJe?oe{SX{c{SplODgzhT;9W=gv%+gE$kXW9cfsLH{9US%RT2LLX1-vef~=1MIf=)$<}1x1h{aC$r~ z7fWkgh&1eX^fsL1B6A`Z%0;E$5~42`X;DsK>{R4S<(M72M61m@R+cU)szR0E=(R%3 z6>su1)>Xm%LoO?+`dhk#?n5+OJbxhc#OR(saUzOBxbRq6v55f!#lZOHh)!cc5OddU z&f?;sGH%-$@RUDD+21{`l*2Sr#K^=OavXiQUfo%ZNW z)}`HGJLs{Hp56M-%wIkOtUQW;26#0f6!C-t8e#3B+v#^;ydU^v=r;lDw@_U^ea`^b zI#t?0d*gTZVAd0Wu(RE(!?;}gA_Lib|NjTFchpZ^$~n@CbJym)sN^z7+~xfKQsm7{ zC(DH~g|a7=)YwFPcJysT160q_;t{?M-2nV4Q&b%7}^`Sp@AD_(m>@#V=OswV#`5N?ln%8E1;p} zH}IF#Qr%ymV&&wxW3XpeyPx*0eYL-zoP5jp8;Z~`bngp6J^?bHfC(gUg;ESBsYp#z ziakcFpk^uS#Pet#Z}2-LLcy+)V3Ka=25)fM6Zj(+dG+87fIa}3ufSR&@Bp=V4&4pV0Ig|D=Xf0eCu?TuJZM=PY{)tU8#WIG z6<&*W8tb&UjRaW`oq~PThAjmP+QuEG0E_=(Xx?jafd$x1afw^mXD(6M+4kkl`15uX#--t< zDn`pomz+s$%0}^*FZLjsc>)ZPM>vGPj}PzxiE+Q9tB2i&jP4vJL*`=6RaQ&RUBY?Y zh*jm~KIdOnS+%>_%d5Lqr5sfnJ#`*LIY#J*}+NCUZA*7s3eonuoCbcHBrk; z4&>ua+$Lob>=^B|Oo6FHCIhHc!OdiVcTA=-xo0v_eBc8NP-YS?SU&lKb=fip|Kx2| zuauGRDq2kpRY3_a#|paXZo^&ly0{wWbj9a!?&8`BQ}(ROmvkUbOP%cg2}k>k3loNHBo)k#YQ z1LA=?CLe7l+jq<2{K!xLLHnrJ{zVwQ*YiF3d`B*J4ojfr*?*ty!?bT3qw?uEYiN1^ bLaVbxG0z$r#osj?@fSK3e1QAq`jKVum zK^bNt#ko*LWt_zxM}U(op+v?aUQ(GzI%!POB|Rb{5sh;q8ZumlOS+_4Q_xqWn|_Cz z$#Ivu{YN~X%1S)tl~7W{Orx%<_pF{Fv;`~XRqmQEB%dx`N;S{%;AVsX24Ln6IO$1d zfeZx|!8w6o5#Ufn9>;)Vk$4QGkc3O030c{(UE~xlz=3bP^)Z-fgTuQ-IHqHy9UZ%d zkOiMB>te2EBR>3a@a5?1>G{LY1o(!zGP((;y!$ce+j7<~=J~Xbnr>TJnOYaBKJnko z7X8smw&}lFrJ=7-DAS;{H(R*tLunbeRvR|cbuJB@XEUyOiQEhnj*#H=)<#C}uiJCK z6?UUIwC7;vGPpA`A!oFpXTc{rM3EHBa--x^$yS6}q3e?Qs#LX*-B7pSoQv?oCDRkG zhdZkE9xgWDNo~e;#qMH^4biJxqTA*FB&IuX-I{^k2dpol+vfbY=!XaYjDC3BZMc-N zikFfx*J7-!#atn7Gxm1Q)p}(wSKOFV+EFbure32gedX8Ko(0O+_y?t6#)GI0kDu$d zTTwn`#(fjN5VezRlKpCFB_za&YYuEc9I7IOR&W3b=!IJ@CXJnTyLPTz!;`|1V(rbMIb^>d2mS}egrt=k;fgtz~1ASC%`K;n1>3I;|Ds! z`39!l0ka@yWI=1X2)>~ViVF7RL`_=3*|E_juS(lyp$jW%UDRkUTs%E5&58X^%m6(6 ze44jvme=!YnxoK%t!S(^wbbW+&DuIYUFE{&$E)1r5>$?6pI!HpFm|FF_IQYlJk8+C z4klrAeYBnZo!{7>T=T!L%Bf&08mu;2F<$`Wo`t3h-X3G!@GZte0Y>4E@iAKm0-;E7*m?hCE@{NALpf9pY$tPTB}5Rs=2{B8%&o$ zO}7+#?I_zf2`0wIVA5y+Pu6$6n^L-N#51ldU%l7O=SY$FV literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/log.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/log.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db3aff9dfc5b04391c1ce98759da7c94f56ec61b GIT binary patch literal 872 zcmb7CyN=W_6t&~LCNr}wZA~cz0S<;B4}{r>*Gi6IrrGlrqg8pt>Cdo$WL;sMS$nf%?AjA2wIbz!syjr z!*WJ(jn#e=_2El*Y#tJbo2 zYEfdQLt_Bu(9L5A(p8Xqk_jrjO9JdZU?zNr0}+6dP-EpK*x?!`!2TAxxeH-O&d82d zbmx7i3zSY#^~0uEOWw)WD9tOa8tz25O30L1R@TP)II-dSywD5tgXjq)`}I8QnoU-1 z%XNl7JQ*@nwK{im-c{LhFv4UX2V=5YEoPf9cJx_lvr;X8Iz??xu=jNe4$Q81{<91n zL#CAJ5ez!PFvfsNhk#5s#K-qw`cLBH(=@a(=WWqQ&TYbZqr|pGJmLJ)wy5_z|ok#ZyMh(XtXJR@Yk`! wHeR(x0-H4Os(6FXN{6_>z;`F&mLE={GbMg8RQM8Krol>LZ$jP2LVBP62KAcINB{r; literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/log_softmax.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/log_softmax.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..998477c4bb7e60d1a4543b50f5b14117b9fff812 GIT binary patch literal 1364 zcmcIk&2HN`5GE;7l4U0_inK|J-EQ}2pp7@!>!Qf^(gH1V>CGrWXhq7gEm1BhZ+@Vh z+#Y(__t^K?r{J}xyh2Z%k(|UpdtDhEejIZC_znI0&Q5ajIh8j7Az#SW7Xm(k;ogH# zMA3pwXgjk>05dCiDJFvAUQmQ(G>KZw0mqY=5*;bAraIQayf;tQ^c7K|5+8{YTC9UL zUDHWl(RXAN-9Q9#I--8}WtuItQLj^@3T;6XRmNP%YKgGUWxg_*Pu^D3cU4}O=|zT? zw;xo{W&9fe-DW#sI#5)xj|8G|z=7f|7J!8cTO6tgvWTq!vy5%LMKI$Pyn*5V1JN)= z4@pDkQ2HS`B-a68I%nu|&8~UF6?xrR(H0{7~e0dsdOEKKG_@w zHb;>Uvch@ZdI}fkshv7cFD#N_cQMyqmKL)0^e?eLf#&O<SKlJ6xqXK{01n?@%m>2(9}T=Pt8#g1kt3hnlWd2mc-l5#ogdv& zeYBxkZWIUD)Uci+6$58kY^A(bS6)$lI<<^+~OtOwKeh1c82+YkP!#4-Ug}F~Th;i=f zJuWAIhZ7!w&;yf~(3ZKWXO^^b(y^gAL)M~~j9b#p%^`hA6@#jAYb+#R?h@b_UU{ZDSd)BT!?54FrFX=TVR318&b z&dHzz^J-qoU2f)PZnq4WFL01Gw{oXt0GFi~)?bZ5c~BYH$-gyMYS6Vv zPQI)T=m_Fuh5Um(H+RUth^PXo&J=6hZdO_%=pFd&q}P{qDoQ}ncZy!;AZoYMx=Z3kJ*YJ*ua9BWhP0vX+kq@NuGklsvSUMYH{X+^gP zE8-e-ZzHopp1FfC4Yk=CFwkauZ$KsK(8B#4NW2x&u{t&+g@!TCUKoWz>xOp5ZrxB8 zM}Sdg);^0=m7gX-w;lR8tGkNHeO1}jF8o-C;8dV;1=idFlAZP?I6;}3#l+WoQi|fJ zTVU5jxi&bhT0dYB=0|w#z%v)%Mj`9up=2Xd8o4#*dmH$gBXgMy z?40E`aCC=c;Eczm+yRV%bA}98Hpug@z96}Us0=-DLe$Jz%Ye*uwzTI3;$%NHmCSf~-CEF#_yBR_~^Wkt{XK@61tshPM7 zOgEwFNHuBQ{7!7~0j!JPLiZ!(5x+wQA42zo#P~D3I2PmVgNLa+@Sb>3>pTooubt>R z<^>}1l2m$d!Sn*@$%DwtAU{3X?nY<#3Y^EFZ@j;~)9~8+-f7zRj=|8LOubMf3F zUjzCq(j}wH%4Ur%vRdsr%w51HL?jnhmKY!so6J{@8q%k8q$7<`n*kqYv$N_fZcM*P zFru*i5n6^~z;^&tqkZ@y`3jR9ZV6O;3hR(bpTI*r!VVMnwSZEkqex_68-M)(s5+kr zJ6qJJPD%fVbIVia>+#IN*X9pi->N&x^?j_VzOTx@-%WWx#&Om65wXUUN*D)O){W#r z%C+L+F)I6qd5xzCt-tW}2OZvlT%+2onh1mJ^ozQ7 z%Kb)hOV)S9BBH$sWpeFqjO(pGUJ&@n-CX|OYZEfcqotd1)KqLJEQS8}u{dRTnQ<8w KxbfduqW=Y|b+pz1 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lp_normalization.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lp_normalization.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99b62f1b1f261083850518724cba31e314fe9ec5 GIT binary patch literal 1089 zcmZ`&y>8S%5Z)i#=SwaGB7`_-K%#NMoe(WT5lDapx&o-&tc-Vk@tyzJ^(7&4s!Kyd zOOqGimA0k2SD=9z`!0zBtTnTwc zf3iZ?6$AA#;MR$bQ)6jm{kc+=Omn0AaAbL@Wx#Atsw7%uwe_?rqFk+h!}vj4iT;r?~#Z^Q`)fYRQs#-*K zt&OO387l*~h$_-iK7hB34~jU9GV1Y@;2NT%|Hj5xE)K*DQW2h}i1hoqr1AjXgk z$tiEhj5ai(4f{q(B2HKH3ZjlHm5T2zbL z1dhIq%X@h=S7Pm)=rR{AO^Q+~%j(2(nH~nNzKOn0yX(!5B0V*B&|b6-4Utj^+$H?_ z7RK}sl{UaE@ni_g4lA}tZ*Yg646kE#;X4UD>kEP16~b-_k(Y9jp*;}d^CHUDC);rr z8I!B}pp<$K9?JVk9%~F{sHmn9_0W4 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lp_pool.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lp_pool.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a6b2366017decf7c74c547193c466d9679db7b27 GIT binary patch literal 1108 zcmcIj&u`N(6t?rbU0OOo2qX?%bD&knb)ae&kQmh@IOSr6*xkA&ab~A%Oucm%F8m+- zOTKd2zrcz2oOUW8ahoH5`RwPs_r90sSG`_$@-1U4hmfCSX9U0}F!d1tC!7|fq$#Dy zox&;I)CKNxukcDg^(hf9_t*3-;Q{w=2=|3A=-OM;G~nS!l0>)Qha}YWkFtCrD*i63 zcp((*gtDrxn5=JUd!ln9W$|HtHLpx?T;n3gZ@0q*GJ&ZN0R%}YC#eI`DR*uN#Pfhd zUY7fq6%Q;AfQLM?Jmek7sjEx^g&u2BKHaIYq~7XYIkq z{?zO>qS8_^KF=HD9G{p#HwyTt#4%nCc^mgsG>L26ywJw0Bo`)FTxRN2{~+oCMELc3 z)RgsTw#*kJtisFIErK~!bvIjt%KE3X@ zRU2-Me+Wd8R$w1UD{ux9zf+JzrwLX2u%EaphL`Fg;6a;g3j;kI9fn|@)N w4TXOxefrO_trEf5{HvfkjWwb{fJ9(O>00|Bn|x&QzG literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lrn.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/lrn.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a1fff88563f11f9ce42cc3953a82c301f9dc58b6 GIT binary patch literal 984 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 b>-1I@k?k$(wmLU-PSkJE3k{wDad!U;4ffRF literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mat_mul.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mat_mul.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d1d2284bbe4d937b9a510aa182480457b6f9e8f GIT binary patch literal 832 zcmb7Dzi-qq6t?5Um%HAfsuN;jV9CHmh^Z2w6AP74JHVF33bE7Dvy;P4D4^TYg@ylv zf5|Ho{{j>5Id^RlV!)9T3J|`v`zC#v>T*dE$Y6hJU=bF(_UA2Yu^}<6?FFqKm~n8q?n{Kx+ah* z2F_$0IH-cG+$M0eiU6=-0PL@!yF-92xg=X!({1#Po})~P3Lltqtwg69*IH5A)`%dm zX{E}TXO(t7#);?atJ0pk@5Ig^*ste#XEu4=SL+-vJRT#|y1fc>(bf6IShUOEjV9!# z?1bs{a`V|wKPv0qw~cr*M}0wb^yP3gVtKRqpVe4=*^Jo<3^qlWBB0^1Va5Fh$d?{*Fq}chO3V)!4;NzCSaE2SQmc21w(1 zoK5}g);S+_wSO4=@9O2=zU9t7v0JccR&oEYWBYArqG&-9 z3Og%U$rDZy<3&)4M09olc9?{eXrV+)b*SkyYUvB2LM5(<5}LQXr7cZjMcVY8e8pIMxNW&D}BbU744V^-rdjz~-17scS#mnK3U#nFa5Q4_9_ zF@v08$AB6caF3gy2|MmJo0u{4bHx^RY;hNb8l!NJ8_~pIi-t^l4b7>FAdeWc32oR{ z_L+|HN8%H|<#c6hBh@5x26{rSJB2;Fh5;eh*lHh6s`H z)aRWqT|PQnPM;l}E~jx+rcRcNLPBnwxc&J@-+!--oz#_l^l$)a?R`*$#dL@6@RiU3 z-DNic86bi?yV(6_boc)zIT;EcOIf9*meTj7ENitW&>l$nZjlzNldY^stu3`XtChJ6 zoLyBL>JDN!%`u3@?}`IxU;l5N1|RJ2brGJ|GTz6#{V}s2|k4W iKzlmYjhA4%4L--mPnOj@#SyYdAF~0pXTU>xgZ=?{YbbR9 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/math_mixin.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/math_mixin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54e889f6bb97d413000759bc4c6db3a69943efa7 GIT binary patch literal 1053 zcma)5y>1gh5Z=GD&yMp`AOztFt{^VxP=pK(NGL8ycg<>ZyN=JkAG5nw9CWFihK81B z;FY$e$}3PYbB7^86s)wP`F3XKo1K|`vA;i@d{*+D5%QhfTLSb6Z1)a?CYlx`C7Nko z(2}K$lD9+)9o-Tg8Mfsq2i((r!2K2rz_A_x9<(^p^qeHaJBUW6cNAno!@(O{E1fCl z&+<)PWoX2@kQ9l`4&tVJKx;>ve(pNXn0E zRdkkb#KsV-6+b3pU#`Zpb+#PWRkeBUP33AkE9$EjOFtXWRiz7K-S|RfOH=7_352r5 zOixzV7Aw@l1fg^!rY-*O7aYE}xu2KD!!s}-Ji$ho97eQ#6u)!rv;m$CLEzqTqW*xB z!@&d{o`Bd@&2UXMyCqwi3eBMnA{=}$dY$>auDZ(O8*pI`_^|h|T?N9E1#RepZRrhf z_yQx5ExQq3G{Q%|H)C67U;2I{w!pCjy#bD=YHgAz@T_n_APBwXm9m$v z4Q%%@p+7yrc7(pn>awh>BLMCI1YsjOqQ^9*F?&QmJ$_i_lV9%BB>Jn_VJ|C`b1)C{ zTH9w3=pI!|+O~fW3`o(Q6JQAW&7Ls;U5qNoAHomik%H2^{tThn{$Uw0%8`ClEM3R0W z&B`B$OLm*o-gqJ61C`4ik;_zRuvCgXAM&D)uuOO|$YaaiiD8UeW=kW9l^?}^XKg{>$j6Ze9*?;9+fILg-+7q*sXb) zwD%_MoA##(9qmjETm8>=rK?IV%2FHN*F~%hY~+2RMTYel4;1lE9soV9D?MZ91&%%l zHdqHS&p>@433Zf3Bf3vs0dc2nME2>3f}NG#J{!TQb)ny{`_we?BYT=wG9(bDv+*LrMOFUO+}4~~WIPFbr#sPo!p z+B0QbWc{rrjE~7ea`F&+g1iO<&)F9d12w6rNu5n&VYV{Oz6cA0H-&h2JfEJ_FI6_@ z9Onn+4T!k`3it(L5;_7tkr=oH`X1Pu%vGT80-hwB56~oS^+;*cD{}q>nVuc}0w$fm zxz4of_peI3ew}GI)~-ssvD>WLi1S=zigR1zJS*fNMcm;0a3Ip@n|hoIV=`6l6;k8y zJHj>6s8>*}qPn2lAv|jLIlz^{RpdAPMg-zR-rB__);Rul&5c!=v}RYiHNDDwYS1{q vo#lVrX0LHdG~Om#(@G9v#WOK<75uL>8*NUy-NLVq`#MElgTkMMbcy~2tN>0d literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/max_pool.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/max_pool.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..018e4375019c3f94a90b7c1e310a6aaefa8cdc00 GIT binary patch literal 2178 zcmc&#L2uhO6ecBEk{!ocvaV}4U=W63fPvL+vL1RUiewnj4nvG#Gtfa7LKW#)jwEU% zy`+YBaxXn}|6_;!AzgdwU)X8y(Mr~#bv6tLCV`(mk&k@jdmkRZ+}`dSzDU?BkC0d7 zjVAxW1&t|1?&MD4#;)Zqa4+^O_kg$J7VsALbH51UfD+;IU`2(;L%8U9B|vOH(90=iQr z%4A8-^t`I1GH73E#)VE*R+&teujzW3_IFa|$Ju#S*1>Udj(_9DgN8lH%=Ac|6v=sX z1~jS?9%VWj$x=j8MOm53qDoBmG#61Jx%dKm7k4(yzV|f_PqUM$z`51jp#9>r4d$uL z=S3M6$qW~b5+$Niny5LEfSr`lSd?0-NiNR@DaPgEae*8{(_;WZV#-PEK%^;mo)d_r z2i)bJXXU|?!ASWqvv!Yk&EqHch}W1jB^})w4QaAc8`c z@8QXD|HQdTdvvkWq;=4YUxo^EgUyDj2Lyrw!J0r=ex(owI_gt(6Z-qE+J%qWLwFwn zH@t=qfYt4vh0>s9wvXo8=E7O*UO2uSy-wHnKf22G{cCXDxjfh1Pu}po_tvrRUaRx{ zPp@>of340BKEKlW!KmM^}F8s9WAmZ9sj9>ZkW5FfWF*d{;#U_hPm%{ zwZZuBmHPJ$R{zg-{^{E2x9iB>n`Sb&sB?p+&atLLVP%PLy=8VWjMYrx4WL>8b;s7& k0`F9XcY>A4yYy3s57xSTh?lX(I@hJm>-yBEj@zSu0)j0!BLDyZ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/max_unpool.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/max_unpool.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a86e110be792a04fdb71f1c9ab029af126d36bd8 GIT binary patch literal 827 zcmb7CF^|(Q6t?3eP1E!^2?p30STfM4VnRZwy5*42bwMmytPs0gspAwoy(_3&Z@Hhs zzu#Cu6o4&8(!zkIfn?|tukel;G)v)h9Iq=ft;_eKbK2GgEF5JXT#Dw=*|=L8QFXAgEx1hMrvCdE|z5j!s4pf z@=Yr)Wsa4~I$zg9x^Q(}n9ueHF$pmJo@Gt7&K8?;m0@WwJC=p2uiG_m7TIN2z0E## zZe)L{C+lx+cqNTp)|$T_qP|wN_xb{^-{jyQKWrGZDu4Rmv;G*{o+n)od4)I31hCa+yJtYF WrF9{C)0OfTFQ-N05(*DHrGEf&+s0A= literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mean.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mean.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..882205b2486a23a9e6fd1ddc601cc816e4b004d5 GIT binary patch literal 1507 zcmcIkOK%e~5VrS~&7-9h5KVDm|qV za6#h4Z{RQa%89?w6En`Em7vEan%U2@<9U4c?9-*C+U~cAy>kiqO|JX`z`G#oJt$5% zO-Yx+(@CAo?Yb0gZt7)z*SFXM9CQOpgwOp66@j3G%7nfqJmCI0;l6Mu?u1TgH{|pK zX;uC}T(aMyX8A=F4@J)RqMWBff~8XA`3WmV2zA1eGLMb-Rz!J>d*(l=cv|5e0AZ`^ zI>P0YJLd%Qcz|8*Sq#~^&jX7Cz!e@^Tmf9=HH$-Dhq@Zlhj1~SWx*#VdI_Q$pfEgl z`?QZuc>AWpMG}>%HePhnR}%ey5h&b^Qzb)KS#|Neqq9*bDdS-Wn|q{1t_qo?#j#y8 zopcVS{j1KWDIc8-I&P0Xn`TdF7HKUN8_6OT3U;zlB%=%qQVuBMoIXT?+Sj_q)(t#8 z5NxpyqMm{JLK1383&(UoUIBGy?wAbdn1bEa&cGeR!S$fyujHrm9gyvOK@kSVpm#9f z8mJx_laDKB;Lb^tjA@hna1K4#L`{9#H{<Ic@_7zwtoEGBTbv%07xLVqR zb-Y6;Z$Q*CC}0?U$vYvbCyTl=l52^q_yOfY6@jAaEcQ^XC%4$CN=y{X4(q*NyKLBSgkZwPfKCt}WMPp(1O+i5iVs03YP%|#B;D27s><%V zbe=MTKKKCyzkpwy#f!F8+Jo7H>c4^cUHKEzg{g zLw6TMfRCjGw1`d7+}k@5^0|hWE9iO14mtlu>>IG@kFQ3)T8*abVmU%O-rp5qTGr3n zx$x5woE!miqsKd-M(F8ycyXvl%g@E?`_Op`n}H?qK@Jhz83*vInZD+>tVO;lkMU13CdlRdnkRBJ1D0p zFQL4Q@(Rc>w^%*TllQ&^>+m?s8>M(_U zTe@d-0PQ*ZUk!OU9ws3Z!pKSs5pp4_TCGbQ_k?(|mgRn>Ta?ndO8cu?*|#8=eFx<> zt9FE`wLc9+*5ThH7V*FYasvt literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/min.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/min.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab01e88192b0f6413b13c1abab4e73b9957431b0 GIT binary patch literal 1498 zcmcIkOK;Oa5Z?9Lj`Jv#0-~uv^qK<+2vilRswzOD63_$OBB7P>u2Uy|q`OXAs`Qjf zzy*mDzk$EBS5Eweo|xG@S_yh=q8WcXo}I_Hvwpg?RNMI$^0$nT-{jKI2fPEK--8lF z(3Es3Je}0ZSeH?>vDD4Hu4l0e*zfw3NKbeZDt$@&l?i=KgfF}^B0R|^Y(gir8wmP= zv?_lfF4=2QbK^xA4P-8M!(60Nfu&O9`7tks2+NqqqdYR~U6Mz*W&VSLrv>f;khZw4 zBblJWIU|t91xTrM|RE2 zxU)ZPUw1xD>F8uh-X4B7&7LfISe8ojp(-M&VIv=gD$KAR?SLZA$pfILeWhn)y};20 z!3OIf`WdJ%B&L?KU`+eu6%cpI#-vZj6zr^Y`fLoR)`Nb(lAq3ZK(_A%K^Pc=-o}8d zpn7CXJ}#evyC6+6rcLt0IdEYUHT7xNTqIFxX=ypeX+JhB$?>TD!BMDsGuCPl>b$m< zCc2D@Y`DFG@iCcCP99>f9L!mfx3|(F3RAreVD4*t2skQr%T>2vhgr+Qf#kE~u_`id z=PNISG)@^CPnSSBcvsQeMZ3C*&_4{*k(^f4qSmIcFjJXjUxtOon?jsBj!RGKmnvIu zj`M@^21MTg1^farF&zV+NDN#8br0+}~ zt~2e%{j1V$TxZ(N^{diu?zO5W;5-jA$+@X7f5 v-PM2G=C5%|6y7FNQ&Nl~$+IN475uL>6KqYp-Nvtu{W=9sgTkNrbcOx}d)!VM literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mod.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mod.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3984ab0d5868072ad51863fb04f217627ca7eb9 GIT binary patch literal 1691 zcmbtV&yO256t?GgCfT%I3AGCaB2+5n(4_5FtAY^PLRTQ6O;>a)p}Cl0?Agp_eqlT9 zZj?nx*$Wr0{0;m|zH;inz=>ziWK&cS2PS%-KR$s#jzZdS_2V}J*Hk@$)4se?~hP%`SWjx-2 zsfh)kAFs7hBah)(L>%x}SsSQzuq?uX#Bj`EM zgA7>W6jNvEWO!-)X8np!bdk9e<)pB!O?Z?qQ@6?H{nfwOT&(a4>b%lXdN4PAD9YXGA^LV$%FfP zScCw`>SGTFV2vD`DHGUVKu8%Ej1UzP0vnm!0+`JPY(b6IxrW&rv4wB@_+j>i2wHz|8<)Tw^X>vz9vw869Acx zlBy`GvZ;Z=+PO~5QJa{gb#Q$bMYrCXwjS2HaGic!-#IEQVmT#+zCOAB=P&~Pld>xK atclL&`W6s67Xqt?uYR@%0fvhO_wip!Qp)!L literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mul.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/mul.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15155fc02162bebf37446059d5bce99cc01365be GIT binary patch literal 1028 zcmb7DO>fgc5Z$#M+i{YXA|WA8Tzw!0A+l9xSQw1wHRC>3hOM9^4Qfh)}poZ%LOl zjX3>8;{Gi}Aty04d+)M*CMy0RtGE;zPJ+6su2?-s*cPnls{EG1YuN9<)nz+XqAl~| z@~W(id)&z!U2TR7U;?Xo4o27%Qb)L)a_5FXcn`44J&SvQfxN{&4}eyvQHC6}u>+mq z`UtDp1G6CKWI+qMaK2*}6cad*r7By&*{QBGo@Y%PyT;9BW4x;7!uYexOrJGBh#rE6 zU$2r@&6A?bX9?!{tQA#L>q6F-cF)=(nXaU0lGBwmiR$Eder@_+gl@{ZVlPHW$g*_4 zjzEI(-OYb-*CF_cUEPO|j?fIyAkUS-IQL->4`919?BVXP58(Z_WM_AxJyF?AuvPA? z(6wT==qT8~^ErC-H$F!vabQBms!R#SOvIR~c_$GM8N28*xxN|XGHV)WsA>_Ex*Q;#b;9q0=Hgty6PS>Xo>2KMf@hJcR literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/neg.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/neg.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76282ef0e32eab5e5b6f56cb374eebded5bdce71 GIT binary patch literal 877 zcmb7CyKdVs6eUHyEZga0Dmr!OqM;Uw0s#sHg^{HNig@X!g;hn$b}UgYDK}~0%~`ti zKl)2tJLMNT^UA8?q5fCCZMQ4{AeB{C4vj>=Hd^TCe3B_bBlH4%}FCENKsx}$j_ z=m(MxZh(c%QfiM*i*hBEcvmPAaz3_}d4v=7L1M|}JUrvD^9o~5CUIafs^IkyStO)EAv;t}VcH$}bQ8J2Zn zOe4EREA$caJh&zMlh$1e3Nt>0*dO`n&?a|&S+A??Gv|6&O%A3__NMXuf<~M2Cx0C~ zY~xjHB(O;XuZlPLtaOMAG5B6|OYjyS$URe>PUlQ~(wF%LpQpicVsAv<$3ps;{subw B(nA0M literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/non_max_suppression.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/non_max_suppression.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33a1cae43b8ac70f8ed7be92f270a00ad49154de GIT binary patch literal 2481 zcmcImyKme!7#As>q&uI_XZ!p(I|;hFP5elL4n>-}MbHO|dT53O2NZ%V>Yh63BJz^6 z!RvBaI;8N_xod&^H61w>=;Wp7oTdGdI@?JT6kRHTAHNrW-^Y)ns5^^`mBSyx;J2D( z{cgSXl)xXN@p~Z5VkEIz1U*gY&~Dj8>+HlCmRcoZ#Ua|@9Wk=Z&n_!9UMa}Dn@4;lEmgJBT`(a#MuAMI;2{yCr}Wu$3M zZD~u=#}u0uBxf$!Mk)!SZ8O50fs;Qreohk;9@zO~LHieDp=(-@of%E5=u3PJV*Y9{J%i~PTY>2f zoa|47=@pn~B&Ty!Xf9AinfWs^BU2x!{sk(0-#56hAyVU#({?%1sIf=(;YEy@aXc%fUuBGo(C9MgqMi)}2+u&fx1u39k$SQxVkOT$-S zczP~XGncFRInwDP7wneR$t$rUS7+pb_1z!S27EoVRq4n^hs^Z+7f_G2OMU4L{kmMA z<7`Y`0%ybE{5;*f^k0{oui-SIZ}ivXnruo}deWbjrd!bI3fNL}>#X{MVg#9PL&7dZ z#VG0p+M&>1gLXr1%WHCzExxdgS0OhFnbpMR%o@07cD@haWqDn00|AxAF4&%4Kci26 zdSrnfJ+kEWjy~ucM`}UDDbMnN^&*iIoUe03^vP4!xjx0``Y4_{w|Z$?)uT8SaUP7a zUMhm)Y=SR>Gm7(}?!!rsqc1UWGK#@0MOn&42*;;kGLE@&@u3(e;`}c>`7%)do$NG~ z+e=4d!IhoFsiLB-oG9c%l@R^TZRKACP$k|CN3rtwlW`oMf@vpNs9j2iQKe9b959_& zsIthzl#enVV_4FQV&(JkF_e)|F6%w*u~^w5W6A}56e1e@JF#**q3Fgrf)7K8t7(=7 z!*CMtt1qBQ?8Cdt9)%d5WKo##og2!I60V#y1F$=I7UmtE>yNc6p@6z9Jjzg+)|N)g z#sV|erHy%j$_7yqa;_G8**FkgxOKCHsU^2r6O+-E%| zx?FkPxYy~Ts`TVQ(FxkgZS=R*LOLD>$DxS2$i_2F&};dkU8K{h%~e5>aN%$A)Bc7D z`mHkj=MHrqCvhZV7W7hVFg@2|e#%FMST98->d5>TEB_eXtFQLNaJ1JRM}s|m&D<*X zCYJD-kpt1*>lQZ=-#adDroDG8!|v!rc|nv7hgn(yE`JPSQJ>UE&8?BUl#(sFODd+{ zH~lqIqZQI1Tl2R8e*W4O*f#MNy-R%J(oM2X>ZDF@($nT!7vb(a_T~MhkCATX{=&U& zNvm&3(k7DrsLvt6U7LRb{f?b~fG)qO$t_KET?%p^oT@yHbA8ta2m42mxw#?f>9x0W zxN`ho(>VC{Kc;bTwBsp12-0vE2Z5>t!7yXvMDx`kcrp%?xn;p@q+u+&88b!64-q2& zRFkV}7*3bO{3&=~xC`Rj)dy7vkt$bvCvU)@-ZMWgqP=^ugLdaTD3~j9UCY+yTW%L- dy?`dzyRuOJy<$4|_2-l8pB0~0N!6~CzX38emp=di literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/non_zero.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/non_zero.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0675da9098aada8c34d60d5f6195eeebe8b21683 GIT binary patch literal 776 zcmZWny^a$x5cbb*e)e*37n(~)n}TdX1v;G~8jz6E&~0NaYv;0;T|3wgIZm4@*W9D< z9K3~FDqew#nN0$bur%ZGjQ!1gGk$%3o=l%|@q-fblboy=>?w%51|^B470D>nVP9eqzE?2kl7itqT2W*tdCk#Xl2AduOZhG*~cVyU$JkZV~f3!bjg z`d*k-=+2DJlr;t3JuVK$6vSPDQf>Z>DK4pGj|A`|$pJsI5rhi{3RedN9Unp5TTl&? zbVM3@2gQ%bh-|s1cdS9p8z^(fwh`D-0~EF~SaB2Y=q;AcXW`5%?Ti(&EWCv#0iVz* z^=j>1V16F@+IXS9tn(@)4?w_)s$8lNZx+g`(DydiZe^T;XS}Ffh_sO^be5ak-nuYo zk;Fbn=od!I(wESR=h|q56D4>G<-QYp3CVxoq`qFI^L4RIv30NZFXxrnv}fVx>0;kq zmww)NI|V3#Sd-Pa(EqBeg9PGDg8k`%B5X*9G@%cdhZ#)%-kFW#&=W%EwGtvELexgC zE3^kfAm>Bmtf+G5YULM3+7|%X7JH(G=)HUy!ck~AC!<^|@K1$|Gl z(F0T=%Z&Q7S7o)4TD&Q>P}0IqVzj>FW{YlH^LnSN2cRXep1w7!bycc&>$|n~Y-!pG z^BjeNvjBCMU}Vo<1d<6Vf_nnBL&2bSXtCES0E2>uP_IDUIhZ}UA$wZWeej*G5SAk6 zqo&+Q-b(F^<+U{p?=iIzGGm@q%J~o%KHl7xcIAE&JB4JwpXY6}&FfvY$??FGAw#Xq zZNKJionH^FyZqxYid>s^zWw4ypQUwcqxsVrvh~2h*BNv@{~K9mkxx0-Wg|KFW6m2R zb_)F|=bv_^Iz%RwDxGU&du@b0gLFOJiNO;6U`EGUX_!s?_#dwi+S)(vyKd|G5qf@r z=7$Z7n8oFPpB=+EY8!&_7nRYiHHzafc!O7JV+>5xaLXL#&?B8-;!G{F`t-%n>P!4L P9JZ7OQ`$c)rWf=Njm*Gi literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/onehot.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/onehot.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a37d203919d2d345c5d04d896a8744c399d0995e GIT binary patch literal 2740 zcmd5;OK%)S5bmD$j@Nb)@^W}+5O7!ty!e3?kcBM3A}Eq=5l2FEX^p3Qy^qRK`a8cw?21Ro zA7t(Une0Hzp9A59(}aXoPeTJ_BQb|oXi*$96MN`{j^?ez9eSasc^mjf*wDNKydV0S zcY$9B7bp=P_oh@V2&3PGzQG$neg4*zeoOc=_nr~%31@0fY4wJSoIW6}>o374ve%+z zLp+JaNcFN5gr%>dcpy@KFG_hLB#gLOnm%FK2-xLOBvmg;SUw(&GO191lrt{!SoUTX zT-9NnaT=G-ek$%|>Tt4NF+nfoy;$VX2jgC<*0$Q%ZLI5VYqJf)T_i9uS?MHMgq-f% zJR2V+;^QEb!Q|8090#YnGh=tPk&8`E-mi=TgX!%g2c_v}S zoopHxXeENYplPP zCbf(!)B(;iCReLyt)A(hf)Tw#K%Rn8kv;_&8dC~@tbl117L1rRFae5Ms(|U#l7%ou zjT86W2xy&nh1Ul-b9Sxb_m` zE*F8c4B3RPv?HZt4&k=q4C3H%Ax6l_cTp2nw0e1G7!3rgk=>Emkm)*y>1j12hD+W+ zg3+tiVmRb2B)5T-jjYpQkD_EON-s+*PG_zncTmS=aW))g=|>>sxQZA}S|#Bcy+(b* zq89Zb6_cep4fTT49AKrvrgN|a3`B|OC_zjhA`~jP`~b#V=BrL4ispQ2JQ6a8BF{eG zf{9#L9Ak2&-uHC!U)b578DCrbVs7gh^3G=WT3+cfmPSLtSm`r1%=kD#zRB2+<0z?T z7UCqz^Py1PjLWz2Gcf}4LnIjLxish?U@ml>#q{S`a6P}d+`QVfCikoFhZ^+8chf}| zNOd#)^bZ=VO}+Ug_u@a?97-Wvy+AL$Uw{8Ud-r#De``s;2cRkavl=Y%ES5{UW~k0; zb@I0@j!>SUsIb+;~xNNBf;t`T_E@`OfabJ8paplyY#lJ)AA)= Y&iOk)JnBKYIekqBN{>SglR)MF3j%-Rv;Y7A literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/or.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/or.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f10b43c95876cc1ead68aee3197ed0567fa2c737 GIT binary patch literal 893 zcmZvazjM)9f44n?Fj>^dDkVZTfNts~8LK<%{ix|EfZSY$}6B^$j8ncA?n_z=CxJ)Vj zg!0j?je<^dY!2R3^@4TuUDZ*}l--GC*Ig621lc#FS#|X-wqM(I_Ce0uy5b+(>$WrA znX2KK-SDlL*{Ppd!yJC;F`r`U-5?t}u-d1A(;*ElMx-F^+SbAiH~{8*JN1DzYjla$ zxWQ}hCs1PmKIE-vdq&B*k`=8h-RHjXYpzYuNy<#LxT@4#|3WIWC;WL;^kP{wt9nsD zUe9~hX{j16uiTpSO>r@#u8Z@b6opjN%9L(pM_x>T$3c4EvokflbL=O7^bh&` zj{S+K7K{uCq)}23S8L$TeKoTGsT9l@4B!t2;@{&OAKK+Uoa56xG6^AFB^V(lB}7QN z;-E7^zN{*~^^9v?X)RcPA*q5oD?ok_(1nJm?tXwv2i7D(7UW}--q+B0ePf=wB>HB$ zE97)rNV45fP`mQ+f1mB#aOVmFn4?;Dy^@^31rY&lrXp~peCRwPm1EimYm(PP!Y9zK Pu7MIS!|w4Te1!i3)n40W literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/p_relu.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/p_relu.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..873630e7b63fa0ac044caf0d3b35f5a87062d33d GIT binary patch literal 1566 zcmcIk&2Aev5GI%VXIZv`!foU>2LbIxhidJ{j_o37j9wa`O%SA)LKk9p$(2{$1kaxHYM$Ez zt_J~d0^*Y7F2RY%3B$~Lg&?R8m@wbr05GKHFeC-(#STY+*I3Wtn5{#SeHp@;xd+OQ z7{pfNcM$a#sLo?}2VIhmba)08*+H=KHJ*8$zqAo+n|fFHGSFn^&w|be9Ck44(Bc8w zhN^9&%cu*x=q{St>I4`6_J%N?^MXq*ay~5Uw&FDxI@M((hN*V`Q>|O|bCOI;eLBy^ zc~d94sCX*HYR;-AOZKz$C_iF{M_I9#Wvs{#jt{cpVE-^n+5O#vquo5)&wtv@R{u(K zUA}Ok)VTfU`#<)M_gp};uDMW+q^!)fwEdC57c>Qd@$S(mGGQs&xmMCv%6!Go+p5e< zO|$DB8c!F-6T~y-ej)$;cjn&rP7JrsamTjWR^=>02bf z2G@TN6J57SG0)EuOPC)QnH5#@(ygg3lG6pJRFW+?mbBCcg- zyom?6kGJu~hNIYcxo5=yOEW8u0h<6iG(#OOaOb_TeZxR#c^B*>BCT6)S#`%MoAN?^ z1IVns;8H;+>D~aA%2CX_*jj{L`EE1tgL^jzesG(C4~I7gKD^Dq$3NU0`1t8)&BT<7 zwC0qW9;J1|=9R^LO8=gx)zY(`SE*7p*QX70t(LZda>uG~t@_TYkKK02w%olX_6bov zP%-Im^nLq-xV?|mmDXv7?giAv_?p1uC4uSEAT41ggU_~IyDdr0*6PmD+CH4_O1d<@ Yl%I(oE%rZb^rhX literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pad.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pad.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58c25902cefe655dcfccac89733c668284185922 GIT binary patch literal 2367 zcmcH)+m0JG)b?C6xpcc-N?T}EZVy2st8OW%P%Rauf~sn$x)l-;k~JMW*(7rb_N3cg zWuLNAvq)6D@eTYC4}Rroe}NY`$GNZ-MLgA`bLRNiKKEl^uh*m7$1!(8LjEA9h7a^@ z0Nnv3h@dIyQ2S>c2mUN|Gq2-OTys)C3p#EO^&Y&`-UlZXA?}!Lb zdQ)dgr?e9Zx$7#R$o=%e&(|G0wwSBzR;w z93XB3=v#oKHL}B`BdB0U1k|`dJHoZJ2ec=AOZz|vBD8cMDqu>aJP?sEKsYJ@5EW7d z&|ON%gb8|)96A$cLI)6miv(tFNl(uQYzj(`DeQ0tE-Id~LvKO`p74f5{j}iwf=t;l zEB!%GhJy+~G-FdbsES}ldq~xQSI0PkG`2VuiV8^c^M?zK5n5oSG(b`XpgLm<2_OUJ zby58p^`Jdqm#7Vy`h9Uaz|%PsAn`eU&bmz0MdK(u3?|;-%#?^TL-q?*UoE7b>(Pb9 zYiQ{)0sh(Nq)Ww`IC~UM0>LJ34?SA%fhPQekLZj013L^4U08*DLnO{kD4bfKxHC5K z1ey3fuTLlJSN4M9j^;+&R7;ubLUGYgN(GT8#?1;LO_&t9F5|pB!K4^>6bpTV`7++q zI33F#kanElAt)P9l=~xjf;FVdV(brf_LnY0gp}Cj0y)ln9m{W zPyz1LIixeF<2MQT!N6X>ouD=x_+N=$hY54ee zM8w-4fEo=z4sJlxw0KfvS&_GHr9~2_db`E-ewN8n^%IUqSN!F9WrJMV`ToI!yN@5; zyJPKcx@rwX8b6CiyqlXqNxd77q;Wt-(@_{zL!Wgbn2LVh)4UH}2KhLHY-T20vYXUy zRd3+_#>=L>4?K;nN9YD!qYZlS-oyWQz_?QMsLlgw0nEdB`IXiz!)E+`J{p($6POzh%0ns>DJjN@9cJp%qZy+nP-r3ckhv0vpH z^NesGKsNxvHG}O54f_JG6v#GJH-Qg^eGET!1JNglY>ronHkGGR>3)&(YoEfZwr>GD zsH4)=%Ij3S_4$9P-Fgjbqm@tBzBr|~@shjO+Re~}oab>SIX4mKa2JoEsJN+d{^K}K z7c12yjkSgwWw#JE+UhfmFnXl$aXuC6Rlx0&i!ZJ1_t33sW z=k}ZT>{VN8nu5aypO#c_&uXl_VB8rH|5= z=!0c`!N*3~t>~1Gi&{7bbraXtrFEXT!Y6sFtrI{o5!M}`ECRmEH=cGvE+?Mmwe@)K z8BA>!>s`ZT*<`URc*yt|ye#$RJ2KBf&#(8XYr3@9?{u1L2+ z%UT(mUW@!jX_*2AZ$hIlx`ThVQ7%viQZ6iSyBK)w6L5$;CFgiS7+&Bh{(64(ct02a zLDtL2C!A~1D9-(q^QM)%I>a;1zwAW)xN@4;!rDf;Z7aLF=?+WmAkR_h%fZW1X7>8{iEq!xJDaZRe}@x8`0gyt^fc4 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pool_mixin.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pool_mixin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc98068d3c8bac76ed52ed784691b2b2d11dda38 GIT binary patch literal 3146 zcmZ`*TW{OQ73K^@iliv{ez#M0lf8J`l?!YicY_#-n-)zRBXODqQGlQ|luU^t+2N?M z-O-a$BzXvshhl#~-}=%YP@pgU8H2v{$$z0Jik>r)9jCxb;P9L?=gge>&Sm&@v+3P? z8%KX%FpPg0H-0ss@4-_^7?{CGW`qRZG^0Z^GzrQ~ple}G(>0*2(9*O8v>n<&+pM0| zhfe5dxs$m=FZ49+0^JB3n)ZP9L!THA4c1`(D}(t-b7F=qMxGhF%}emWINT-5P0l(= zDbgYbX0Dfrh{Ym~x&VnGp zgp3{OFmufqyB}td>YJ>_tR9ihvN54!Zzi*E$Qq(HlhzrTP*}^K@eXsrra9w0W&+oe zP38_L|IbX?U}U;FGxZKlY4xqXJuyI|d2?=Hg2d|ACr00y7~?tN$~k69ms#t^AK@gj zE=2~*_89R2lL0xYwut+?cIVjS!+Pw6Ml=$jTiGa@SqKRn=Jr;3;0FN-(^d{ zw}4;P{3Et9UId(02Q|>ngx7D#MYh)Wr8^;O23wy{Vq9B)558>-Owj!P2Q;VnZlYg| zXwARPG`Fr+6HQ$Ew{*NTUY1M!7TcbXx8x0hRsYL&s2XOJFDHmjm1@GLq#v7x*G%?=O>L0T9p7Otn<^Br$u~@}(z)EXk zUD`J-*(W_m+Wn1*IbMagjuY7Z3Fxc1tjRS-n28Y)n?Re={SY18e`155>$%4ah`YNC zv|R0P$@K{V>{feFornRuEf?WTcdl@FZFC9ylzsNf8E*i>y8|2c{ioc>YjB3`@g|&j zMJ`R~Tl$*3rd`TDXJ3HsmfV~efZq0aM{db&xig_NZig8I=e@~4k=s3z+c?*waH>_P zsxJ>YR<-g63D1*kTA!B`MfFPXlqD6nk#iXqJ@k%Bxt%1#%GE?ItuMaCF);d1GtzAUczkfhw+0T z&7s|d-f@yw1@C6X%S&uDVY3ni?idxECH!J>YS1aN(J&8&alhb-9^O~vP?7u4yK2}D zcU@)a<+u+^@D>hpFhJXj8G{bU=aKVE@B_F=oP*UeYAwQW@#1*}(m-&BOdg4T%HDWJXmZ-bu&an6E^jUeW|(J;wH6`;k{7TL!=7vsAGPlX49tTHBWA9X3@1Hp^J*Rf8R z?&*KQmQPv9KLy=?-`f+za<4n;4EBmVKl@5twoxciT6e=xAlo$2azV?fuVzcmpU4qfeyq zhA{Gu<`gJ{wq@@zm%nKP&J=cQFoMO=MhV~X%6nXczaJL>v0ujDI|xB>mp>~ z%9Eq$`QbAt$0tvZ4<1AZ-`zhrI#%}dlIK`G%Bw`oMTI5Azd*}f9PmKAj`Ke3S&hoF z;BfhKjDo7ajCl^(ts2iEGhfUY{2b_x@(y=U$6~r5Jfz*~%E@r+D!za*A|Bzs(G2rj z%Isv7s^w4=%F~EM3{sun##QWT-Yaqz+67O0(V4Ey(66wbV(4N}Aj&?AAgY58^{UI1 zW9I0>R8E>t0fVjppDNgvu$n7fyWw>?=P;*QSAAm&m?9B;=|KICL^AtOQZ`SjQ6~7; z=%Rn~dq?Md=;0}`KNKbZ3Z3{8ho9hpr3Jb08PY$+A;3W=SPiYP+f;vs!JsWtqaJmL zLp`z#|3%UwE#TM9ZQ=vx5eGEzZQppnhSXqoc{ai<^+9H9$vmax|NoA*u7TX9Hmq#J zjy}9s$s*XHJ+26=)LO(gJ=(H7@ME1`v_8&zsI=oqpwh|_}cUn2sD%Z&j6;rO-JghyAJ1Dp literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pow.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/pow.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..363d76607a491607e3c64e354fe6bdad17832bc4 GIT binary patch literal 884 zcmZva&5qMB5XbE}UrpN;%L#Gfz@-NoAr31fgeoo|paBa> z!h7&azH-`EKtf_BX?IspN1psMc09is&x`RmnSIasA4E&Qc-x3jv=$eQ~#*%IQE#1;A z5%eRO3~nF_Ih#;-^d>JBvJvm{M%2=PC(=!G#q|+%6gNOi`pvc~PV;ttT3uC* zV;}Uoz?1faftbOxPr=A8gUpjmP~lw@i0*@C!tZn-0w4(uW?pz;aNq$r-@~*=U^e8E zY-mY0-VX$)$b4K^s%oX+=SJtE$Zb1ejuo|aexrqS;bNVe3;UCp5uEV*W!kD`TCR#k zim5$oWn;A|YrXEid0VFQK6{&<_ti+3dOcl!b%QU`*h)A2`51vZO7Ghk(w^R~9A9!I6Bz%mDr~37R1qOrSRiaL03U44(&iPR=Hwi#cy{B{_Eq z=SquJje5lS=T%da#u#@wWWK~ zWzm+?eJ!WETJoL4VD+*`|83hZB! M8`17zA$>^y0&ug~qyPW_ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/q_linear_conv.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/q_linear_conv.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25f83473a661868b22272d81390a804a18d277a2 GIT binary patch literal 2431 zcmZ`*OK;mo5Z(u0qA1x`9<|dnaMMe5h@CdKz(@@zMT-QlAUuq-=*u9B(pbQZooCsJpN}pmYyrOUFwc&^9h?j@ z)%@<8K^6xBXF}Al_&5x9p%r(5#M;Ili+MyN_ME_}28?-R=&=c7uuhMy$VO`f`WYHP z@WUPzK7>|$45TCpl@utOvl;eOvYKNO#_L4#s{|C${VrFm>?x|kMcoQDzgZKG=51$8;*JPaJw9iw)^Aoa2qkWQ^r}53s5rAykGXW zpH(mw+fOUlwvYT&L*j>k$=2vpb^Itk8V6Z9n8tpkp^1*5i-fmnn@(>n!MOGI_Ddj8 zWC2F83(Ofgqi5`l_YIA#Q<8H417LwH*Z`a#L7N#RPYh{99KbSRY)TV%%^3h>?1vat z{19OW+7)QU9*_ef$&>qt?>VoPl1k~5+cS1f6Mjx4-5`=}zz$6r(mDT?AKf@I5PzX_ z#!#jRvV$1leHM&jWd{YIRFq;Bj=>0R-Bom;Xwo$VVk02!iD)75kYF&x3XoUs4$6i3 zaP;6B@CBk_QAVeC-UZ=gYbVVisKo;qEMzOQEU|`)J4n!LVFOVX1TG99SwyU@?OK&N z+AwVn8m5|6D77ET&BtXOTW#z+{6H5}YdOFZJiI{I316kx4UbMY-swrma36eVEat-3 z(25%{D_I1Am~qJ^O`sZVK%izu%|RvrXV#pdIjiPO&Dk|)Y0jxRTXT(?b2R7HTtjnB zX(V*!l}t7gK8L$~$i#1@0U2f_aKAUm0hJBNx<+>Mat}W=#P6jQxrq&HbWVS!u;yIK z|MiBv1M-fRulAt)KOo-(d8d+>Bypr6EosgU?1aG`U_JWF}_PB)}XKm2bir4|IHMZZ_{f9mecj0+$X-elR znXLfdmTkH6KHkSR>Q7em`Ji=9DLL7U+Kb{s>nwfi>BhGmP$R zO>10}E^3s`_sFaxJF<dY5-Z7wjIF7Vc0Xx79LX4M5= zgXxVQvSK_M<)VzEO{|ccxDiOT%4B)PK3zC+<2f!`Aa>~i#iI1Qwy4SP!DhYvgOEu6YU)w@YtNM0X zgMe=DhUbEX!?(4U-D!ZHdUq;#ATD+)R^^5A)69V(KxBk|)#WH5Hay70) g{Bt5Oq4nwiXO?nyD*qnf3svBQ<1h~(^Pmp@3sON+Qvd(} literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/q_linear_mat_mul.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/q_linear_mat_mul.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..462c7494349d6a97036cd12dff6844604dd8756f GIT binary patch literal 1465 zcmZWpyOP^B6b1MIDN598ERW2aP);h%C-g6G#7Z-e%=h@Y7jQ)`z^bb1uV!&5W)pIZ$ zaa^MUgAeLp9Tp*WT3AQxxQHUw*C{!Q@M(Uv_orMjXEoz!g+=0Y>;;6oCji=D|Azt3*76 zRU#Qda~Xhf-xH`#_z9}|3nOF#j-R53(1ZrB;22L4u&8IDXK~LW&q&W=&yt=I&(fYH zo(+1IdY1KU;Mvd&SNLIM;#IIit8j-Na+AyVCU-mF;aw!(>u435_^8|jyWk=A8hNA< zlYN+DY{u>1W_+CEcPvvsB0Fk+mdtCzN7@iHVj{2!tm8Z}q-V|(ll07aVg@~Po)|aU zjdMOVks*N301wQWiF=%y#0&sWygo5$k2B~q0elYn(43nL@D%XKOn2C$+)T}|SI2-y z4x8zXOQP)B4z*}hD=Du^E#XGd-Wzx0dzT}7ci(%Lw|n9YWHg$cSyDBdPAeO8z1;{q zxDlGFTLv&;iq@6VHqc9(NO4f3l7W;g>z3(f-`Z4l3oTixZMyDiU2W>EC2OXESi-B< z6&E&^ZP#!cGR|$TnC>Lgg1UKTPi$D$%0^8K{m9)LCU2Bb?}cpX zrmY%n@uEl;$CkxuOR_!6+fQVFxFYW-JRGpd`|d}|#jB1ry1EyfvLZjF3ya@cy!{i& zFJN>3em~di&3xIFcXRhbzdD2-V)Djws+aTI!y{Jn#oh zNL95B{pRZo=2b7ipdiKLPYQ`gc!EEJGQv~m!w)^e5ol0CC^&N{xW9Pxx48Vc$n`9? zDWwft3rcN9>AK}z?eK_FIDFl=49l7+wHEre6|lRx%}nK{iRl*=OJax4vJiOoI+ zLY{+YKleW{y}UezlZp%++BfmJFw~V!vVf?sjgBmY2acp G!T$l|1A|Wh literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/quantize_linear.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/quantize_linear.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d2bd16afb599c992218a966a9f3099cdcf271cd GIT binary patch literal 963 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

$M=vW-ClnyZ2y@@ zU~L&5#yhp;U^A4#dMI+e;E;EI|F3PEFgDU*fv|IZjIsQ`c!liQ>Tb{Rt$Jjhu`Y#= I3woRW1{+oS6#xJL literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/random_uniform_like.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/random_uniform_like.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0450ae9249a72b2fb6a9017ab9d2162a7c2f09c1 GIT binary patch literal 1064 zcmZ`&J8u&~5Z=e#*-7l6P@otZ3Yrtb2GJsjpa2AN5kzy%YPsFB&%TG*JtrYDmDAAB z(&P{DL--ThQqfUUF|)QwP+(5;*qzFDJmD1gcoCFg5_&rTJ4zx-bg055)sd!?){;IaDpKJYQK9BbzNAZ|FwRF~7nON+Bn!~;1T;8XN@sFjG%hl_lBNDiATyp8)^s3{7r$N( znsPSC=IL~R+23n)Wowf`SicrcHW;r8WC!n71sfP&5;0%ZL=;ez{_KP6jdUYq(-71Eb%$pM(_cn5oh%D?v=9k|9d-y8S#X5LVg8o?}Jz{MSEmHComs9(jybP zBqREfFUW)~Xhs!Z@SHB#7xtNsu=~N#?W{5sDo-1O)pt=|&E}1bx!J?z76P$jIn(ZD zDW_VjFJz`Jg`beBRyqz$7f%PcaMAQwnvwMZE{bb*eY_)WY+hI5K@XM|6CiA#p5D4z zf#nGj)LTvAGo7jt;&{&%_$@RoD%ggBE&g+K^p0W~EvRIxddJ62)JjQW39C6qg{AdxnKl$+1w1 zp>}Izo8T>46h`tM#h;_vv0JtS4ZGwgtcVQ=>uKMtl^B%q)(P!wFCvw(Qk6XLw(}vS zO~}`Gja&I&%$;Gfzb~ty-&A_rt}6<7zR#dLdl&a&(ACYpQ(t}DcV0Q_ZL#?lreBov zpR5s=movhP%*prj*umoA@T$y0A%tmqB}AAC(ObFg$es!DdE0b{le4yKyzkX;W2Kv8 z#>jZ0sEVU+T^!35Y225O!t?<>B!dpm;s6G{IPxzJ{Nmtngj-+yckOsgQ+Fwb5VqsIHoJQ~M1hcyC}>i!5kk7^gjO^lp}PXQG$zE(?cO@cVrRJnZMWCZ z@IUxVZmI4sP%-1|;}8-Oj%NJXp3Hpn*)PW9Wcsb(k3B+ul3ODJJOwi!zzHI#A~}WG zQ(nz-MsbfRzYg-iVIOdqhkyeSs;G|hm=YO?XhUTv>BV3}UlS3F=$eQ~#*%IP4c*W@ z5%fJt2RBfKoTbzry(-FuY{Z+Q5lU*$vfGYR`W`?HFw;bR>+iDRw`qCT-b1NS?F`~gXj?? z`!&tFdYM(La*^Q=&-x6NYA@ZIcU3m)^)T7TUY|_wTb(Sw*uiJ1&Ae^+^D$C%yuGgv z4th-X0sq;Qjv-;n^Z+KEpc|q?-o3+uhx*6&VEM25$7gA1W6qnRmYmy!^STu)g?PmI zr&Xc0C&N+|#?-Q#wL%|ZxjXxse^z&Qh5U>UF7`)$I<(0_MC)~xed4a7t0p@oCtD@? zc0;3R`NO}$cE@=C8VlH@h8M?cd~!N;8;8qqTyCl3m^z8#lfKcH_;?LA6ni7;J{HpZ F^f#pr-s%7V literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_l1.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_l1.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b6d1c6058f9c62a4c27e3ceee77e48bf3fdb2473 GIT binary patch literal 1053 zcmb7DJ(JTg5S9ELCpjPtGte<~DM-j%%Rq)JUGWI9PCP<>l7kTgp2E~0z;ME8MKTI+ukxgy z`4sp3Dv)6oIvfCwvIua97l=}W>B9$yh2i$wVAU`^LFOF4Z{ zhMjB3LS{p1k6z@(xv2T8yylfquoE|ReaV_7LQ}G`t&3|4-st>J@U}3ErhdD)T+}vk zYw>1MV7T4z0Zd`)Ct!q=k$J-BlzUeMCzn}}$5zK7NMVYsiv3{et3c=$CQuT{Us}xqw{CYk%ayc&B;(Uzq9ve~XMwL}_ z;nvKQo2z@{4_NDh$hwQJO7PQwR;8vt_Pw*+*v3PC~q|k9Gwa z{nNd0uHcQTaK47AkHD6R$_z<41Hre*-hw`g{NY literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_l2.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_l2.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72e628f39cec8cf3770d110da4c87aca12660a68 GIT binary patch literal 1053 zcmb7DJ(JTg5S47lcD@eC4KvU&bSX&4(K3+X3YY;>K<7pnOTOe{**Qt(4klf$q2Yh< zm()__FHo_od|a3t3gprHNm}o|w<|yEc3b1`DLeHD`9%&!1b7Tne*(h^rv*tUyuHGc ze&SQy^NT<>l7_4 zekA?o8nTc{pW35WX*L%nf0LHH5DIppsw}TqwLoZcme*yrrr?dv9|W&6Gpow?v#VKY zW49LXPBIL)8$N(BO#Kv$a5554_?&X@ngE3Wu+IaB8-PK8!y%7=TCA`X8D_+RZwz<} zQ+L2%81B#L40Qw(8*!1Rbz!VuDZYlXlAlP`&kC*DuyW@2%b}5rVP0qRAnED9JlAMzz&FRwnf!ZjxCt_J8WmWclh2m{cR$SO{ewnJX1APif z*yb0ZG&F~e?qSR=r{12^{`kK*s5=mBn_t}ptT6gbZ8y1F`{1Md2g#3bCm&7vk&PKE zQz;m;EyiTU>jH6yv5Pt_wkPeZNVS&2Oe?OiK&pr4`0wnl$0*<3nNj4 z!9PO2a_V2;#LOmXi|7@vX7-!$$n*H@CmS2_!Pi9mWQ6=8S5^S{0K~ioC5fat=~4Kz zoE5ysDf)Qs6@JeL>`6Zlim(?_qI?-F=u09)8JrOrs8I2Rx1ha9(j(H2&fz?A*rsmt zd6JG*DPJX}%#{XDSe4~WRFiWGAsF#q$!Th{s(hEtveLC`TfMCYN7Ew3bJmLkH~=w^ zL8-dZ9#dRW$<7Gm_5gF~)z}9NHP$$gA=ad^+Z0AnFEmizfS3=U=1kH(GN&VGe~;{u zQx2GpnB5ti|Z=+EIB%brRH-`eg@dX{=NWw$c zw5l|f7BWk%#_pY$%#?A_SgDE33Zp%6wi&uJqZ?>6U67TNsWr||tkuTxfwIoaGh>~v zlX9RO&sFIf;1*_>Oq2@~BkFx-`>p9oM$7{qAr{s_A}QlH6V8ft;ADGx_2|kyb@f zl}$L(M4$-Uq7Ug7J-Kz2=gunZf*#}=rKV>Sz?_VLoIahi?>J5hmrLITf1B%V_~{)~ zyQr}GrMd&iH9jkC;C6}qEig^ZKRem}EBi&rf5;zS9KMf*t_#??zJUG1cIYA@%A`<2 zxLAmylG7YyVzPEvs{0*{a%s`Yw_3kYh1$vu)l_G zjv=hc1zFRIuDx$4f+GKzl}bw0WWM#w+Ss5`T-a!FS?H{bIbaU2LquEx!8GYFLG14eiuv$%-=_C`Y<#74g_C5)1KtCG~kd>qAeR=SQ z55vQ*{}Q7UI5YEg4+foLIKqGuwgK<7>EZD4U6}7VJp3nz@mUtxgt4ZOf-##iCKc~$ z#C^s-c168gIV$VI7%AGB;u;OtCx@$lC*cZ(G)({@3Hm{HWYZg4t=Crek$XsOHQakU z+h1sh; z>E}MhJ--fQC+|2O01xvJc!!5|B;!1$M09wxrXm#dqPwOq36FVnO?V_?;je==UDG__ z^c_jNH(-UFr_>(3D9V{o{8gcNEi~*zjZ#b2%#pSgs}`!fp>P{7zZHB@w$nzPO_x(; zyKXJcie-uK?V1l{48uGH5Kc$#37=E$T@&yj0Pgd^@eXiM;CRR*@GaIDixL9l8a{^O zH4JkEup$>^MJu}UzM&L~Dk4@kQZ_2}tzXv02CCu0hO?_ee>C5T?!$LK$5|`qS+yu< z8A^Q83S}By)y4%jl9p;<)Wy!C%v*RjFF<9G+bkD^&Ny`goAp=Fa)kJFi0i@h=V@#v}cn;BCXd} z_OUDAwi@oTIoxKGZ8tO~E`RjLwcRn6n+^bMB8zsyBo@0yn>INVg!AS$H*NfUqxTel Q8&|Wj*Qc)gA-zX`0oWt%UH||9 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_mean.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_mean.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a9524f0b264b1bb5f0700d597cc1f888615a7ab GIT binary patch literal 888 zcmb7CyOPr|6qPK$;v~z!zzih?jSJ$*&@xP*ff;7EfX?&UMy1W6l1UJ8xqA$BeqfZxC3vClO zm#4DOB_6nM48RO}`xt_BLUKXh7*fz=j84e*?Wefv_g$ zWKAo&_P!y1iqs=sHcB-*WtNq7Ykl1aX~X4ZVLrCsi5bCvzg}dWT4hyVE;H2iq?5XB zOjS3RZqBk!IC@|1-)f&6HvE?W6T@*S zGXoe*f?S9Tv&rG`>0Oxb%Rl&6`RQ32+L&`)D9O1^I9HA6Ys4eYKlMeuTN##h z(Y8u<^F|o-*W5W&{j8i=z%E``3zDpQ1Er0me zw*4~RwZQ^5QAIcB3ZIt=F)=*44M*n4AV<}?6hGT4eU2~Hy_nb=QTMTs-lM+(Fp<}^ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_min.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_min.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..529420ef775d8b9090883e8804a1a25d11089311 GIT binary patch literal 1029 zcmcIjOOMkq5Vn&vNz-%~K_#gZw zUpehx;KYpkLSiMv0bBn3`4P{2Gn1#IQ8N8nus0qdKge$_0zQRd-UD#LX-#qpvsZi4 z&wYw}ejUhO-g7(v9_AtN9uMnC#(7MM=<#SxMJVW5e@$N!9`opm@JPhMUk7Wtrg_5Y zJCgRV!3sG|sXcm8lnbHwt3vTwXxNDwr7l^sMA}xY>Qs46;Wl1=D|lD7^G2P_FXzhk z-CCT?Rf+HInh#_O!#n{HPDkzupHuE#5%3`Z?(@L$9&k|Lc*rC0E!G%|5(4BJK8E8p z408mqB4=bpE4uQ&p%jWLB33q1HY)Y4U)IJ3s^P+hi;F^kG~bCH!goKXSu2-W)s>43 zB|dJ2GL5e4=EAL6TV=CN6ioJE6O~M(V8P^EjhCNo|C7)L)U(M5y>TvjU+(RrFy5d4 zllwY`*HT~iVbTf000Eue09v!j{_)8jSnsUgzrp(CznVXO@E7yPr)gwk##A8%V>V$- zHoU8m4;ee}ih6r8DC@!)DcV`XHRe{|Lb#1^Q12Lqz!e4t$%FuLFod2CY;s7X_1ell zas}L0<6Sn#+ibG!hQ`F@5C6EfJH~R;0f0?p(as?IQ0y9Q+T>6W&YPRuwDGfz-skw+ PxSEZ0SB@!td@< literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_prod.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_prod.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13437f8a1cfd8b6d8c4b37dc2ee6ab5d8a2ab548 GIT binary patch literal 888 zcmb7CJ+IR+6t&}gHEkaPfyBtbl7U7QD?)_@B*YVfEsF`UL;IT8#Yx_Kpl*E&3;%<^ zd?aA|^TuLQg7E098Kqk^kU2?rb*j2phRe23;32uHXMPGIctzIuK7s@7X zF5eg}N<47i7=Rh{_8|o6gyf!Nf(q}700|#36TZWN2!K#%(16l|fDI48{t9|~0%1+g z$eLDk?R`W36sbqN)J>yR$}B7E*7`~dX~X43VLrCsi5bCvzn*1Xv&yQzTxO{2Q72Wa zO;zg)H|JfI&9~Cq?8DZI%%DoiS0HP$`fLa1(zKwNPsd2darD02z0p27Z1^t$CWhlu zW(F{r1j7&m(%uFvXOqL>)7voLm%sO~^3&5av@z$ZXe8%0;k?nJuMv+p|I`=tZe>{3 zMcX#An`>dvUvukF_0Rh5UXWqyLx}y6pAKzuNZ}54U5EH|r+i+x#402SROYxJf(x>=R-HVC65p^F6=^gqT#tPUN literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_sum.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_sum.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0965c11cde97097ba39681091329f77a1f3acd16 GIT binary patch literal 883 zcmb7CJCoBe5SA>zlN`gNproL2K|C2+hRM*t48s*%=SCPyCb?L4kZkT?(&ZW&{s(_a zE!DM@RO~8`I|dr$(dyGm-u=GSKAlX``PY*Fq=ft+w?+hb4%55?BZ#04DJZO7<0)1! ziayr(DkuVneZXN60uDsjL@F*~N@O6SEtR39=gF47BqA2k6%mn)CENO2x}`-b=o!h9 zYsf-QGipy>l+{YM;#Jv-Mr!axUE5yrZjG?7c|Ek%HLxXk`K=T~)i1mD&GK^D+QjYU z*`O+ncNh%79Hw~;MmimZCz+tayCT5B2h4=;a3BKU6Kd37d0=p00GzL3niDV^a!xk1 zrW@}Y(x=Eg;#H?q*JjMJsxj7YJ0Wejx+wJr^PT81{P$~~_iCNjL$%6L){|bgrqgxP zUAR5(>wK|OZu0lLO5_?vN^S-$Xj{&6Uq{mH0mN@JAl z7oE^pTz%)5^w0F}QIMeV!NmU9&qg-ADWUcH+CFma($~{N9jE&`^1VZ2$%==6T{|4( uLu*W6Q&sj0uCTRq=o~js;keu?k7Md;6hGSueU44)x+V6;)O{?Z_vmkjEY>gp literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_sum_square.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reduce_sum_square.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1cf00d31242ae50852f0d7625df7680d90d6e658 GIT binary patch literal 1225 zcmcIjOK%e~5cXqV*`$DqM4R#u;+6vm6<35RE=3@Eptn6>Eo&#)WFNtHXsEWQ^uhuD z2Y<;o#HoLQ6JsZ7QGp{~&Fts#$TR*v`{~wJeDFDC-w8rL&~GCEd;q3if#Znd0woy! zq#z|tD7G zqAoh4fboQIs;Tz0-_S|0M3Zm{rQAo(ymba}vn1S~k~3dNlNMOq&?RoX23q(+N0ycF z$h5VnR4p0LGc7Fv#!DAMnP@7+jOV429t3;DhI1ubcG5OMUd`rO89&upDnmy?8?VTf zHoi=&kubCnm1#kksc||JCQKD`>qHMtEG@x;sd;Gv^b`VGlFz&{TMx||J$^K3e>x;7KH)nb{7_X#NgZC?`2Uqpjs$75e$%HJc z%d)Q8u&au|A+n7h;ca}nb4~F6I`dK|E4nqO(+vO(nt)0}+>o!9R}2?T-h+6L$~*9r zJJ#)5XV0*5cLAB!MwvU0CcA&6ZI-QcCN5JwW~F`M(uaVn{@I=^M?OA&-Fxn_@@PKKmR~CIof7hc+-M2#C3N=&KoUtcDJhIh zvzC{f;u_ac8<%n55%8o;C{eMD2dWZ9SCdsb(C0)ZGQK1-R(#+C9cVd~^fk#RKOr(X z&8a_rR@G}|^0{ z$P)qQG7212LC(a+aI|Is*f0S0m(blUfE`(p9c}22eWhn8lA^x5ZM9aSSH^W#G`4F+ zkY_rna_)JposV$hll4Vq&)hd+GYIzUanZM%qS@B#0xvumBQ(0Z2y@Xl#rasWE8dP4 z6c&nHY(Dwv2W8#6&WMLI6c-e;&&TM&;%e(Z3$gg9IkyuSY>F^NK&>Mj0lUt8f{y$< z^T}zR_*4i}wMqz|3DI_PtC7!yc)zXme&?vxm2<7?&pT~`edx? SDf}G7q571~D11Djx9M+-rp3De literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reshape.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/reshape.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e516800b55ec219c76d55dd93f08bdfed944e393 GIT binary patch literal 1535 zcmcIkOOG5i5Vqa!$Mnp;a$y%OC<+g0keDG#!U@m{6hVZvNLh(PU#zC>*_}r}VtZJ! z>N#~T9N@}@Kfqt|mD67M0bHQUJ(ENNal@@De^qvstIFkmu(y|<{g{hsM9A;twE;3Y z12P#fNhDp7te&+}rbD*07j$(7QeiR-HRLDUUGI}@{YRk--6GFN${3N+h| z0KgfL`3RUI8I>esDv(sN7X*&tfCI@r4grTU@;H()gplYE%nAk!#}Ft1`Wndm0jy<` zo{*L~ccy$Umdd)6CJ6!Kz73R1N{O$;L zhkz2G0Z`iFY9JYK@2g`Sl?hlypc%Gd8v%|1k6P3q#VzkB%;39?yI_;FyiML9n}OY1 z>|<;l-K1^0IFMYDj!^>9AGUNx+n^m>vNo0RudHRiu%GEA-pJtG4Xvt7t%aNyR#Pa! zEixDS%EN7h(mrn#fTUhq;W2a3ylU3gxG=X?o7=x&jE^){)9qb6Isf9Z`1bMBiznZl zJ7#AtDeB7Dys~=aUC%4~@k7Up+*pm(cd>c4R_aE%@cK$=nAEd%zH-rJZb5bjrpdKY z!q!4UunJ7;=DACxQjJGJQ#bC-GGD@;KAV}YOW|9ps-+qaT~Mry<0!ajd7bM^%=EkdSxj}`_!G!77DZi_b+r$^%w1rF-JvNxW~cO! zb9#@BXhiSOC`jmtju@vm2is>e*;>Brc6>TWzT43sbO-c0bO-bUbOVK_sow?tIMAms z>9>%*jSMsC**k#T;CrRbyspIk4?r~jIkB6g-N7$c|IeczP5$fXN9W_%B|=nrsf2K; z5M?dbE5suqu)Ve`!(x>iQ!0B^OP{=c4|9DV*{iHQ!qol$BgK>PubJ@C>4=Y0eGGz2 zUtO&}K*e3(fp#|8UGQXk!D6e>Sh?)@AKP}zcw3sIt9aWI{``Ln%q5@n8GeTE*WmRg MEP?KTFTf7@8>XIxh5!Hn literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/resize.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/resize.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8550f557821e5a0911146395ac140973937ad0d GIT binary patch literal 30375 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 JFG~3X{u`q7|K9)r literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/rnn.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/rnn.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f13337ae41ea3747a42428e6602d73fbe89143e GIT binary patch literal 4019 zcmcIn&2Qtz73Yu?MN$$aYi+N+@ot0`X`!~U(dLk*Fcyn!7fHXo+ucpO5Lys4hq5SB zlrp4Ojyt+Uivm5Q?Wvan?YThyjH1Xn$2k?~$^SqPivsQM4P~#Lw8xT|$2af2nRzqw zzW7$F<=^{F6#i|)F#cg&d0gQ4(273*aD%hVn6Lq3gqxW;u<*4qdr}+JG|dL?3>=Nu zviigwxEgmdZ{iPpjn{!U1`Un7z?*|6aF6?0YZ43sW+XmuELqavO~58^E!lep4|wB+ z!5c}CxJ!G<=pD4V`NZhA&!L;qXR1DnM43j}0r0h>qzq5;^uv=REKY{Q^b|xdIgOK9 znND+bf_J0%ILZ0@QO>hO(D-SdpN7*J(DrI7jGfJXnr3)*}QJ%`sd#{uqgPvdpqI6#fN+`<91L<1AXCICIw zs{IJx;uZjBl8udHM{JgCY;u!ZOOtK~L+t})(>~5x*S4knS9|DNsuq={C56j`+sJf(L@36YGJ(1_TvyYTd^MvsziH~Wjf>ba}pPdEJclQZR0 zii_rDA0C2!3;num%GQy-wM8I{+@|p>5@K6#{J_O`ahEdyBK$&Y2%tc z?L1g%py`V?NuoKjjXAKNUzm%|Vhxm<>_CH##@2ul&66FuwuDzoCe0y}&Yw(K|1JA+ zzu!K1$@Y{voC|U!WggCj2juMi`%$i41`gc&)uK0?ir!($Q<22vxKXy-djRiBL~l6n z!76%(^9v_~Yvs`-=@s#Gmh8gH5|Jm_IoZ9k57VePr;9%)`#=9T9&rbl27O=EidmMH zs`>aNFVji#K!~YO4pyH;r83K*a?*TuQWnZ9MU)q_X_2UUf$)-?!Jy-59z)K`62yUs z^L|%!XjuolC=&s@hhk!lNR7(8L!QQ^>ZC<@ZFkBhqZMSOsz!qfRZDZ8oGLa~On{cm z!+G@)Vw=R+p|a*7fCvw@Lsej%ctIGS6ytG<86X|)+NunKJ8^_>0#yoO^23$;ozmo8O-037KIpYlBq3hX^+{` z7@JFD0plhP%*Vmk<`(#M!p1d2e1S_K4SWle-IV#r3!eE*wkNv~io_g{*P7 z4R;~^qIBRGF#CngjYUH`ym4F;pVC^~-!`NLC;xP%75Z4Uks5F>XY7u>BRCds(mKZu zoaM)*Up9D)2QOgO(2?BV#LU4;lQuVw7_YB`x@fOxoh!7CG{#LC(C#Ht7GQ_q(xP>w zN8y83k*#rSC5c@?l3<76(pn-z}ci#4<^_P(K4_zZ!d2K|smaZ04^4S9nb#~xPy3>b78!i_IAA{tf)t&6i+2OTF1 z*}uy*xz0EDjr`W7>`P6%xo^lWcw6{3@ZE+MxA1*!pR^~=4mig6hP3rbua7qnyw+t) zx=ROvWn;1Vb7=NcK1Tlt?}37 zhW_s03)Y5aBIH{~7q`jFD!?N7`_HUEyDe@9E+);P^@Q|`#ykaV@= zw)DA)b1}s~<+j{9qTsi6gpk+2b0EG6XQ%>PW0Z29sryaZFj@imy=j4eFYCuIw_(N6IEaWlf@)>Y^5*_!_?2xpJb}47H^So<|~$4l@*? zl#~SJ9zh97yiN1fQ3OWiTi-$K#>_5F6en4xn(szM8sp&ZQ?HSn&XDPlF(!rh8pic| zI=fUyN~xkc*LyT&L#L_Lj{H>zHYdJIa_^8xKqq}^frZ#74%M8hL92&Vb*6%Hcx6k4 zxJzR161Y#`Jpw-fP~OGWjFeAXSdFh&c3UV%-yjlMb(3tQoQkDfO`*$NVYozZW$qwe zprG0#k^)4XK$YH=99IuxZJwl6@oNCXbdkE6I%Of5nL%xf`KHY_Szy{I4x4O?t+REr z!uZ9 zTxLiz0BSlzl8KRXN`_L&q%ujnsF;EdkD&_U${l}U+urj;6mb0T+kb>yK}Kbmx=!D{ z98I~v z?`P#1`Uu2~x*rmFwReqCZKHo`=mZNoC%4wDnKt4cYrfHZ*0lQ_>#+X-Q+NiS literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/rnn_mixin.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/rnn_mixin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc1bdb8c28e1a1bba11feabbbb51f049aa7de877 GIT binary patch literal 2295 zcma(TO>Y}TbZ7R{>$Q`n-z`NxAz6hOM1>FvO`}j%m8cV?E~+e~?Z&ffuf5)NXVy*P zu20E@13e)mD*gZ$#2tw{SHx+=0mP|N51f1Ay@}(P3M6JVZ{E!Nm^W|Ud$aFXD( z0{_Rdrv0fcGz0Kk&;z$$dBztmr5J%2!2b8yf+xQpm(ww^l+%9mNz@4jAqi_lm(ZYB}KBv?2)Jq@Dw0*7UCeU5r z&=)vv0*3_}eq}aujfq!Z4o~9Sv>qs;}?PQYQ2#UM~!IQ88osq-G3(!Q<3o~ z$@bLT&!a{!NLd1QGQ^0AXyz9NC&P|S@|xg6UtIDdGjQUR)KeQEy+4T zB5tmpu+}X}^GMPZf(4az!X%O2y>XJqAh?OMGCN3vVchY7E-(MXOa20>zAW`lA|%;w zyQszQB!LjJtndMNu`8sDTg>qCsqcj>&0Wvm0OO^tq@ulc`NSxHcW<_eNH)&FheBE+ z5Asm(%OKQt@^~1cM`cyHSezVE`S%!HLhU*zy@oz|3xGyF>X9mShzB2zmxx2EfIHOD z4dRju#HAB&(T^RxdTiFLtF-wGCJ>5RUmMuGmP48_0*Qhv#vx_&kP;241tiwgh_$I% z5S2bV1;qq{MAKn3VKgA&%x7e3q|bo|L%t{|vj;kVsq{KZFIAc$MNxA)0?ra}{s5fr zKo?&@@|Nck-b_MQGR9114P+`H^GiWTKd~z8zO<(0ChSjU`(FW$W#D+JY&^4QTVX($ zuQVsuHs)DWi^i$SpxV=E4Uz{2>9*#9+_r)!iqlY<0>Ti7UL55dy~xi1m|Xu4ReN#X zs|CrZ7koTd%&~TLpMQhx=k+d3p#8o+x$%E=yj|N3^F?J22zQ^J`~J=!lcRNMs=as> z7Nwc@fE5zu;#RZy(BIf>-TiE%b$6@j-`m*UzT3RRF&gCgt!@87^ZtYF?X8{G?N9vM z4>xabx1^a`aZ|RtXsT>LI$q!hC?F!~XH_ZLh%=rk| z#RmX1>JkHD)`EC7Ab#g`HFDRYh^hPTvo9*LoHtIWW!;W9^bu{?e^j2P#Y{5 YrtDM|$5}h};7xp11iHkd4i+B$Z-wS-b^rhX literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/round.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/round.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f287a8aa7c034aed3f14402c3375d5d0644072dc GIT binary patch literal 742 zcmZWny>8nu5GF%f5_2D058DoCvbuY+LDsOKWGER zN=7lp+E7Jh$Q%2OdIu4`$E6?Z^$;(T47VpY$3D zQ{?(oRcpz6scmO?V>-n>Row}hGso)Ix)3KWUf)*c+WsbH3d#PyEPAymnr*!<@WAsi zL(_J*e$M-*SdQ{-@p)`VVNlt8^UY;nrLn6{^NWia(({~y?`K~6{BiLrk6g;Ru9W25 zWt^){Y+J-r&cAG{cE55`x0SU@_RCI~Q^@E!9yzSy+cPn_+PUYMy?OKIW}gp-{ppvCe{%@=L2fJ`@D#Q_0wai^1u1Dt zDPpH^N|rLfOt^(xdZ|Z=WWsCdYa)E%T@m3)Ptw+HY3hsMn8e{V$1&@`rQ8K%{)2n8l;mCUBeR0JYIb^0nh8Qtg9YY>VhFoL@y(3)p#4ar3#f< zRmj|_nuD&d6qL|eOw~U4W2Of1P!XCT8a&;ZJwT@SNh-alEB*ol+P2NP99h=ip}XWg zxc^_?gFE2u??g=|4{s3f-4Z;R%;M05oL5;XIX8XI%UY}p#1ZEo*IBWR4Duq=x|Gdn zEo{TpJ;LnMnIMQM|;PraW+1zJC>B!oyD1E4-q%nux-W?bBaMuk5w} literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/scan_mixin.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/scan_mixin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..792ce4166ffb2b5fcf012ba11a0dc4c4d8e5e7d5 GIT binary patch literal 4764 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 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_at.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_at.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc8455fcd3eb815c341d841d73a1d9f1e1b3ec82 GIT binary patch literal 1579 zcmZuxPj4$V5ci+m&32nc1;HbgI9PyGMS4wCxK&T6Ev#C#)w=I5FD=HMVX|0Ctg5TU=(vjIFh2Qsf< z5=h_zO);#bAZt3M*vn`Utix%Dkqkw!!QUeR>pLU@NjG$Zr;)%{XcWDN7trMhyTNy9 zwvtNxkSb9~4U%4|)bG5kTyiCUtEI~1h0VPBZcx~q1DUU2lC29U$o&HP0_A|Nk#4P>S;HFycp9HAwCpbZsd73-m(SICkj@C{i88}dMb3mXD+ z)IcO431HuA2;2yU2>1~A7-+8vns7rlKGHCKgAqy?jMod9t(aX%R+T2Vd8t@#SguZP z%32A-?sB_eTAE5`mf5n^G+PM9?F$!KCMzoi)2W(EHY+td-o16)J;r`HQ7@TdC+zgs zm+WpKwFD0AfZg^DRj+TPX61}osZ6Q82kbakRc-ms+VMDPb~)vcxNn_Ajht21`3YsvE2)1Ci-0im^KSs~RNaDhW{uhMm%bx>$P z6q24gL4GjTGPP23fHN&ztmHhk`K@$GA&uEe z6D>uZNuCyk+b_y_o}~qcv>Zi_W`%Kkk2p9A(Ygd+;GKIe%t|FryXEV@kbVJf{c|y~ z>uNHqv(?1s^hpQ!tSIkVp4-`E(WSka+;n9y*+I)wJFf2CN7-V`?PP1fE*#mH#wr2kLo4f+|{f-i(ix8DK4MV{IA z|FrKY*MM)-LTmI8c@1tu|D*=fhvV`(dsVM zbEA*EXz=(~Z3l7ju1s766;>B^nxw4(4{rNg-SnBioZL!npgj5M=@-CvXpVYC5tpwJxcD6}&y{YZc6m3rF zg#-K#{*tep_zRpE?mAnuN zG+`y>l2vni?@U}Qgv`Y2N@}APnaNz#c0qM*HHUB!O(h8tlw(e=5g>V-0+OdZFlS^F zwF9SX;~i}M3q(yg?xPj0X^p4QN+0#n6t6r(rgZA%sD?B@$;w}TF}?|$&l<1s8}#}8 zDgd9bjjIC}$H|(k!rGrkE)OR&q9pk2OyfFS<5eX0;nk`AI?M?t+=IMP9j*L}=bum= zEVcFZc{&%i`=N>W*r3_YSXCu!p=|(3veXQAEX@jSJy~&K zgV|-Oa;@C>THIb!1k;;uvUp;DO9egp+EQb*1z=5YjtIl~m5sj%r6-kSPoKt+Ss#EvG{Sp$j~?LrxQBaW zA4lZ-qdPnr-h`eGd>b()(^4>IW5&vgFA8_>GIp^@i;bm|6{*&xFy|Fl4*{uZ=azWj zbdGBwZ0-0K(LreAn+BC5pMBiW+l+_XHiw%w*+!vUY;t(VZEJSCZ-8!ryU{9FfsKyZ R23|Pk=m-pyKYB1;?f2ZW$LFgCSJ3h$AK=Ly%h8WIKjP32jF5FJ; z6@Khv<8$+%2;7aqC~A~ZtMlE>#H)=gA0DMT@WO7dT1<8YPPPS-twES~;)DOfc5bu6dbo2ZRZ&!BJ8aJw?RHpD ddq7Rog+Z&M*KM(HFlcfJEW(k~$M$na_%Bz%8Q1^- literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_erase.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_erase.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b614716b2b00340f7b5cd6af0987b4d88ab28195 GIT binary patch literal 1687 zcmZuxPj4JG6t_Kpc6PFfLaEx#1uTRVEoyeP;eZrXD5XUpfg(YAK#Pzy8GCmpJL?&2 zPt#VD)0P8=iqF9p;G1yql~cb0C!S|!n^eV;pY7-8_s_rgKHuGqPk&F?-vL7Zpj!jZ z=oF@Y2!tb!b2P)SlANr)nTH+E%l&mQ3osG^_c!<(#9@7fxG%hox52ZJ<8w3$-+%^m zHo|uAt0Y|s$-hk`&xHa`uaNRND@wb2E`F_qOvTqK(IRy(w!?$XDNOw-5Yc!sBf{gD zlUE3=fHm$pyRZ*<;4CU1L{s(VK zpa%Chfo9!Kq5*LeP1k=;2n^VXKV(d?X)GNss9C zmk0D}DU^T{*a5qZ4q2@)grdcq8XX1S0Hv$R24NIq?s<3EwQ2TuL_WMbCkWL~AKi9_vC zo85U{Ts3EA=96U$Y(2SXfj-&hkqHOuarwf2kS)yguM+BUxj$n`fIL4^a<%&uP~s=g zGd+rJ*!-GSJ$LDnrusmv2Op<~ZWlh%S}0?K78`frCygp{#zhI82Rck9v<-oqCT6sw z_T3v_7F^hHb(N@vRtJu?_ZA&ZS5hB3X0$Cu8$uOVxv_E5SaTn0iJrndZotx#`|eTv zOehVlfK8_#!C5;jArj#|dw;Ig z+YcCXHPGGcq&YaW7G_!SCLQWCFm}r$XIweAnhxobs9k4_yusa3&&D^9ZW3&1)1J+I syao2S12*dz%6-yo_@3DI+O^=u)c^TlqlaxAU%H}iN+2QwJn;7Me-LieMgRZ+ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_insert.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sequence_insert.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8727a12ee5696b24d30d5b25fcdb5a0c7c247bef GIT binary patch literal 1798 zcmZuy-EJc_6t+D-nM|f(L1k%gkS~y`NNu7n5*O79by*=6Ays1A3lu=sbnGOPOlAh# z*>+dct1K5>tauK10-nXUNJxDJt~mB2+rnbW9{(JlAD{0#^Xbk`eELhu{sAdzN8>aZ|q^a=N0}k7zY@MfctCw72@!HjkqtowYSFOkmGYS2ya0H zIvZfq|02y6qU6ugk{3e4PNyo%YgW~!e=dGni82#kmr6*T*(=-T!Q>RW`UD2y+!zz# zam>kU1ZKb-_pD)<2RyJQr4OQ+y=WW6hU~^u=;|2^8qINo=VXl3@iFz-N*8ovqFWNl;f($6qLG^Ws=&P2ALdM0RHsa)q(NpnT> z^60W!m0Z!QT+gT!sur21x^j|g6ZOz(c#>tJ)`C-+mQz6|m81t-T?ef)`u$OPNXs7& z>D5d~L7fe2(M=}9}KTfzH6 z;Kj*ZSm1o_(&S=jO>J~ap;xjzp%-!`Xg;~SbN?yYXd(Sk1&-;LwUF?NXwWr8PfVa@ zX)R1wS4@G6N|=CK8M8B$BGp1Nc(k-IQ7NXW&R+-<7ecAcZY%{~WrC$eVR}V1&9k&% zfVV+tysS{B`!-(VK~yG&a9JVBsh*i2t4e;{ejfdXu(2%gn-GxSfzuFrr|ED&e$$y+ZbYyXH4)75uRmY}t8No;VwnP(JgbG1 z1(CnQNj&cXXYft8JZyZ9n($|9BewcEa`PTYB~9D}O>YW!dH9ChberxJSoSS?j=qC> z1AOb8nO>U!#`8=&*xXv|+}fA907&`ib*=_GCUkjL#)I5STL5Io4)(p}M=+T1iL#Z( z1TC6&A@^EV1>>TI5(T9w7s~X+bq&b{V@qX{=jn7R_=TgE=}ly{WUVtMgxguF2Z?;o z>h{Zu3llD`QaM#}&u;bK;?9*hleFv2{b);b6GDYp723q9bI(G?#6Xh`NexlQ&>uN$ zw!=fKK7Jvjf|A3Ik3WXBvI8O!?&Cfo_|Qx6L(<2ITPN_{C9n4XgSI;jXF!&Su`*o> z#!SrEvf``4&J)Hg_ckZJtN<^ULeDDh9#xLO>OI#ifu!}%)nl6gW$SR{CA));iQC{U zm0X4lb${C zQyhF$Ms=LW7>SriTl@}j*zXaK1l`gt&U+kRp>gjwWI(eq_QN+txfY7QFBF%;fTypO z`pk6Whgagd6{-{;g_^rX8J-*#1!D?g&q0X}Mot9fn3H=1Wgxrv;Y!^i%{3EBCZ3<(BkC)25dI{HPDXou`=EC>Zw}qKo6X5w_ z_ng^%>pzh>1NWb|nX8+uYRh#N=y|pSQAvHcKqd!P_W@Q{2N{mb^`;pPnBCXA_~7L56nv0C$127AERbz8`No7eVDkfxr2lNd81@=nFCIA2c literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/shape.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/shape.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fdb8c1c8d6d3abec28f66fb76956c233d126e8c7 GIT binary patch literal 872 zcmZ`%y^ho{5Vqqao7>wxek!1Wf+hvKLLeFtT0sF4(iU8o#xk+9fB8Gx;W)J2UPHrs z@G3llTPj|GiWz4YRzldC@x-3-eBb9h8IOmvFM@xkg!~{!BZhbeX5NF7MADLE6xN^& zDwZ*dd#ntrD2sd?LL6r?B`T89j;dJE^rcFCF|-9Qx;l5!`BJnh$D+ev5X`{LLvYH&%L2tDmBBTE zMj^yZhCT*R&@|Q&q~^fY4_xt**I?!h9F|(LrYo3`&gO0)RUx|4x}@nWw^yx70~grB zMXTCAdkP3yUYc)2pF;Vs=Tlp?)1u2aQ>5_7s@gQVD4R?F&22GV_AJfxL(h6@kk_QW za(5TXa$&7Dywy#v43zR#Xi<$2UjU8-pYMAeCjZUNeIBGDF|>DJ<|eo;S(7a-=r;ID z7f6qy`u8faQM?Dr3*A)Qi(fZVrA!Z@&V~5l;?1Sd3*(9Q4q>^Ik4l?WQ}f5zL*kW>!eX^IG?>98cmEHL#?Qo0=YV6=5|4_c|5fqQi3z59& TIlaWc%HUQKj3`VN)7$hnNFm%S literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/shrink.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/shrink.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c13fc44c14f3f916f922a8038990a73d3de8097b GIT binary patch literal 1191 zcmZWoy^qr{6u0AiHBEaRPN&|)F?QfOfRI2ZII)0)bOUTztTcApTvMmmF2|kHskboj zhwv|XLSnj|i3OgMv{b^8pWpjE`+eoTr@dZu`8A~@522svV1bM-VXF%u3^81w1jFeR z&XObqTZ|O$(n~yyxX0Wrev25K_lUWiY{?cUKEof;$bSF}=xT&b|4o`LxM1&6!3r(` z2}&Wp&~jz`k8_!eMP{$=76IlGwi*KAwfn^3gkk2~BQWnW0_I)mf;w}6*foG1z_b5D_Qn78qn-{K!?+^_Lq z6TnNa@__o4U%A)8*4a9n@DOF4W3<Q}w03somGTl473bTt>Ml$7O}mKX{F&I*3PV!W>B0>-L{=*+wqrUNTv07_o96dFjny2=4F7)$f#!I!9%DB_KC`_1@ zLg`d!gsQ{ zXLx#5 z-I~s4E>&I%`XT~j>I?{SLfpp#GQ>l2f_;39PjH{axc*3p?*`3`obR7rjXV=lD$*sV z)I^jnOSUd7A5;2ioffU8n-!^2ORnc7laIkuoxuUI?&~qKB~^BmLNW?W^e-nF18C0b zan;lFU1sNPX0!#QeVYvbyS7u?k**ybIJec5XFyDN(IoK7wx6Kc%ct~shSR*0Rw-A$au&fdXkyIe!V z|KKmVLZad?P%-0V?+zgf9L@OoYv#=x<;854EWQ-{J0;`?xidn*3o!E@oFIbMB&RTY zwb!tmQQTv--voK!un#!QLrP>If}YAy(si_sd-{fmPz2XR1d{cvr#;Olf}W8y`U#QA zX-e(AlcL;6CEgZF)KbGv)GGCfw_Ai=#jBkvZFII;HtkB3`0OwkfCZR&3QjtTxhI*R z!n-Dr$_LDZ?=TR9w4n~*YUzQ)fdSCoftmZ@_GC@=w4!_OD_tT_iWDC=#YXZ@D${CS z>9*mHp=yOpnPp{dtd9#DZY~SGG~b9$AlR>0S=Vf{YFBPDeDG|DP}S|FTl22U&WEZ^ z_F+&VGee#8?Poi=klL(T#h*`+pCj#EJs6dk-<=W04u9_bNoR0$XaYLhA`J=zC9geZ>8WUJgDI1NlyWDrAaLk+@ X@ynsG*YK|pg9XIil)}eC`jGwx=Wff_ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sign.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sign.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cfb6a1e240f2171e9326374da84ccef98d21b0b1 GIT binary patch literal 736 zcmZWnJ(JTg5S9ELUy`|@x}l)Z%q$%!wP93+Q3m~_5|hMu3m zUs6kTe}Rf!If2X|&#s?V((ZdJy_n6?<+qakpoIJ)CnE;D1T!DNal&a!3JQO(^`u|; z6k~oH$gl_<4gg0*1UTeT8_T3fC=nr#2Pz^#ZzltNM|i^H2f|~K2!99$I?y8J^oC@U zN2o%sGiv8=%W5MOe_txz3JsCCQ|g{|TZDbh>Yb_{fh`#~o2I%d`}I|G-zXd0G%HnM zs^jnhEWykLIN>A|p71&4-UEU10r#PNpiyq+fy04^&@REuIk-K!C3{-az4x82kS|55 zPi46gtQX33n$^0K%rR9R7nyJUsx>yiiH$aQrCynzL{A~v?^k&*w|Tv*HaQ-6K4z%f z?#|6wU+3#ly~#h0-N+3HTWr7B$!DQW(<%0HhU6S$@9P|OFa9oFXQ53PQ>7G)*_1Ka z@m-5}%Gjq}*&bHTsD zhyEq5o$?nt^-i)|1Ep}M$0K?7-jOe6vuydTDey73!#n1{?y8ix_YuVwLE$NGXw#NO~$`NpB}TeMdwpk_RFZnM&4&J?&|c33^TD zlSimRuIALAzAdY@G~#_}gpw8_No&kKZ#M|Ln%7%XJpx-YZgx#|S$3<-=DsnWT{ot} zOozb$EWzA4I5{XN0?7mw!2^Nnp~k{zw-F8EGwkS;~0 zPj$JLypzVYme;n`d?0FCA?M7qN;x0m#K-Hq(%!hA#7-gE?^k)JH+j9S);S({K4z#@ zdpFE^SLdryyvsk1&B$G27Mm}A@>yEfw1&T&A-92W@O1{N7k^i-=8;c1H>H-G`;2ql zimgIC<^0pORQr{aN|nxO*{xb(Pa)mF?#N+@p)r#~tu&mU`0O8FA9S^UHmL6E#ewu< zPnz!o7HJme|7|-gW2G^Dyt-h7~2PNbeIT;Dy6`1<~P7pyADJc8{6=+s4 ziZP}_9Tm}lL%?wn1CB(j5}g()B{C98Ph~9W&7`MqiAY6qPedY9$@;LTJuNapugGHZ z09DB4g8KQJvf4-^-jzluX(5ud#@z9Ci?FMCy))GVuqESW*Hjl}x4vlZ8so#O#;hw$ zbsP-93e25@lY@jJkW5e!+!H7t3I^pvi*l;~91c8$_8!bV0=FkOWKV0l55CiDxHO^yeijTvgy z-VSr#)%ki<@A8jhH*yEUmfJ6W@>yEfw1&T!A-REZ@O6&5mw%To7m-gnH>H-G`;2ql zik(6{<^0pGREL$bN|nxO*{xe)=a6sUcjBQQTuySVwu};}GIFk10`+jJ8z8imnD*`i96@MmI!8if!4JZfTxKdQQ^8Pq>%N zQ|czKM6p(ld@CARDGfV=wrM`|w!_etyzHC8h3Cs_Rbb6wFbHN~<`FpM(dB_+lFHzQ zK%Wp|CPNUK2vQ56>IbfP$!jn(0f(iQtmqOZq_epjNL7lyvMyUjTEwp!F<`%dOS&i)w#zT2#WATG@+M>M`7>Z=*wHj~w>(&zL}9 zLU2hq3eyue{HwOcGxyMQvE}rj`E;*2-*0GCE5G|s+Tj=l)Y!p=_)5O(5fTr~%aFX- TQF@7gl)kwT8_ zwLvup1qBM!MGpmf=^yC7=x@l8hhBQxztBtjyqsC>)=6hT&iggwOV0Z|oS*i3>C-O+2trvHdeFu_YU;qK{8{8s}=UKy;zNyOQwta=zQ8Lv|Hlry@W*K54L zVU_n8S^P3tcP1U@4a#)gophZXLe3@`XR<4z1DBcfm%Ri36%(ezH>R}S7jz5HjR{eu1Wn|;^BrhA6DR!sfHgeE2Jj5XGGSQRxA^-q{djOq|>J2%#5thsmKP5fJ4mzDE2GdtZxO@7yzG`ZbB&h>AFz0wgJioeQ_!E*i)f%EvoIV*5khFlG>TeI@iyOt+a8W^KzkU>zA^!VNusgTOWQK zICH3qYA&r;ZLPmvRQAETSjoJdd!{z)+?8Xs5eTYhHq=y!HkocJq*K-7%=*(3>9~k! z^|DZNt*DkPznrAAU0LRO@mlIu{zA?dl}g}O9dwh98!tz4Ds?X{{?639kpBI%i+a7i znC+&k3rgW9O-_K$OQ+}c?BaO?8h!Ca1ELEz*!lLA?YxjmFE&;F7zDxeIXdPgyzgbM zWjx{cyuSAye~%COySNAZ`+mT2BZA^ypE$^!AICXjF@AWcVQWAomPe`X+Oz z?L$5>&`kFo2AjV>aWNFxH()@#HE=Nl({nLB#N2^}tS(#O&napMJu<^K1JdpQRYP-v z_`64q-W-a)xr^QEyzxZ(CfJW)qgn47l7`~s+KW}kW`y@g$35+?LSWt^t{J`gE)ngn zd-s~-oaNRWrxoQpGBLhYvqz`E^C{t3{12K9vM{IfV8L%8c<{`Dz#;dF;Cn?}OXR=V z)p`ADE3X2w5{-{N8*K|!thJ376#x%la~leZg3uFkR_w|;e^Hb>c}0MCFu(c_F7;zl zsT<#ORz>v*m=gNckH|?!q8gGlm=<7y0FYmSUvRdx=aBUaA#7J(ZUHDT4if3ii~6}# zc_nNNURbPmYcPh?+NQ6i+7PL%qzzvp1|*|o!!{=x>(JnjO)fxRQr&mS$S-$AX@gBA zwK|0bsh&|%52*Vdb&fDH$6_t{+;D^)-nKWq){sToINW;r?bPiC+N{-GVw1Gt&Kygb zB*dRi8ZLC+Ix2|;FJ8z=)*5DuswgJ|M7Z#yKXt0}+6>Lc74P%DKkz*MzCYqaKLb6buw*>*hdkpEh-(;( zU`cr71>AG@2+}>C_ybTGSu+068{o~z8=$=&yhUn{j;uy?NX@YtRSasKQLP)CNjQ-> zeq7YgVITW%e>-C9?_AL1ui(+{ALH9oKYlijZIb6zv6gvm(>%uy(XJ#p%X2E2*3+Gq zh1P3XKi>%TkmjN^)Q8mFOzkAvQ1@fggP`dTCke72W*?7FY*_8q+gIu?Y&N|)N*c7B z+!)T+sCz{@s|$+l{(8OLsQQ;mZIpfJ&cb?jetqzqw+Bz&8We5et9uH6Lr=EUyl pS}lYWxjV94(%-cjn>=Z@%NhUx literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/softmax.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/softmax.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..15e5fecc8fa394e9e40e8308894f4ee40ac4003f GIT binary patch literal 1322 zcmcIj%Wl*#6tx{Y$vj#H1f}K8awOJfK^_*-IBGBl9FJp4bfmR1QU&a}IvuZRkj_(YV@Vi_#yl8$?d z?vr8k3nGxcA@%DolXRwydYu@RYYUpFH0D^AbA(kUvxP~0v|nabksPOJb~YgWHr*!x zbd&0s=|EA%J`o7T0SAgVSO69(Y;dR|NFlZY%u=@U7Qu@3zk%t#gQ%IJTcoB_sC$cS zk<$P$oicQ}WT(95ip_+5RC6<^f{IT?-Beifn*?_+>lEK4GiFsyreRGpTC=b80PdlR zTB}n5D6WNKHUA9JmbCo`FVVD9!=1L;jGcy{>DECVLJk39n7wHqW5YRyUWa1O_bP2% zX{DN^m8DRQ=gINJ{X#fg^WntI7nSoOsVeJyaG)z6O8?m=R^ZWUzD(0hXkLdK0CRx>ZGNj5&cfL=17--sK`XSx!39(3 zTzePv!@zF9VsE0@M1k42;tn9+`Jk2>-CU)Mg_ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/softplus.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/softplus.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..606846ce2762c2845be87416f890eb0ec91344dd GIT binary patch literal 702 zcmZXSv5wR*5QaT=lFjAz5JD6uD%uomglN%eMFSGjHAj`k3bB31u4C`nS&l>7$q~Z<0F=_LY6GB zR{N0PCS>co#$Ed##1*mG?~AJMHkI18>k1FN*mqFc-i>?StLkPi)mI<)(kp)ux7gf= zlh4xmPuB34a|9fz>DMQd{>9(&WtoPYbJKK^^H6Z!S+Ug^&pE%{Hu_LGZFS>)C;J;K z9QGVJkK8Hd@QU(jV4jpkDE^TL+Nv%}ly|_`Pj<8tj2CGBBRa(t)T{t}^O`rJ z5I{LmM@?MBLmXk86bUdLtGEZ9Xjn~FX%Fw2N>u#7RIEiWdg!4zQE<(&$uI28t}+Nu z-j&r_TlJx|s@4uOlh)cVvfWVF8ELk*3h8xgI)A&g6`dQGz+i#q&(Z0DvEW)LQ2c@6 ztVju*6}cG86-P&l4v}4=`KRc1Y{hn9V8-piabOx{(=h!<9(ZTM%Rzr<<|F?6fG-aTN36y9f1izIx^x$z3*6d} hj-rRrM>uqgj+jFFb}#7y|4-%#J>@gNMRz~T<-#A}FZs%ezrcxc((Xe*Do?(d*yH)WnLgjz>g;`C^o57ePju}G0q?=mDHx78 z&QRREaZJD`nV0*qk6p~mf;^1F8v9u*kK(At0pNDr#z;gwTw&1`WY$^XH;A`*c!78* z!j-qeD;#$@K0w3h7u;81Rt=+{Tc^6fO10RL`d*D zgL}IquVLvP7RQ{@BnTYe$e8Nx7pqD$ne|iN%ajnwCl?LPHK( zGR5+3S1JL6$oZ4&%8dSdB&oNm4lp9!y0z9-s=(p!owdKugcy%A1iDsJHZu zSNSXafh>b%X#80K`=I5^Ruxn&?(L!q%~};sF?c=?zLSc4BVX~6lP;XtZo{1NX=0QU z+IFvX|8PibP!qJb6PiwyHZ)mqMrDzm4I>*)i*jMK^)gY|wxgzxSt*pGV*NydMiCdH zbV%KD!3Q~;gNU`zi1_&Y-i`KLZl4T88&T@!ic;I5 zG?#plIozZ4(}HE|FWn?#TIa$XORlycyL#x%<)}5t)lv_&W2k*Fk>B%&J#`nL?OctY zB__4~S`(9wfM70*M$Si@;ASvK>%pY!fO7wl`2JtpHlN+C$_*9>d1I98!v0mUjdmN> UFWqEl*T9HGq!F*@g?I=50l<4q2mk;8 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/split.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/split.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6175ee5d58638be054b9e4a6e8b619202ae1e142 GIT binary patch literal 2078 zcmcIl&5z?W6t@%SqiH)kjAoZ9AgGoPsRugRLE-=_G%P|Oka}5!P%lv?c4yM0NwMA8 z*(#OLW-na0a^Z~NU-FgH@F#HMJ*V@bg*|RkzyAE5?PtID^UFv5esuhE693^7@)x=F zK%X2#Q&SL}a9WUQ`%kA1^qs<8uqmUca|>_bPkoCS;9we1B7E*OR0P7AhYkITaOgiL z+!L&E8`{umhttPo6kNjkWHO>==TVa8qU2vEB`<^oO;DBPMO-Zr>RCKnm8tO_FN;j4 zIO*zf0USe9-+>ThN;#Q2!sV1Z&j~nUfL+ck_5gd_x7Y_9@X+D_aEC`0hk(1hXK{!3 zVUs)3gQZgk1U}ed(7uJHCLn4$Cv%Dp8)xHcr*^nIK&{K20U3}vYslPdU^5$5yEWtN zfaFX)Lfj=ek>6+=t!J=xaOY19OD-}cDXeX}T9m4iG0#$ciJJBP=U^PduUhG0H5;B( ztCEib<0V>4W!zJtja!J)_*uDJX=OT~iPc%M6edViTx3d{==-Eti7%zB zHl2qG6Es_1I@y(DFkBSfeV~W3krg|VS&fLvt zhWud@6L2w0R)w}ZwlTAt9Z|Upqb+X5UFezt#=-_FUdk#J3S+xWWU@fBvN?9v@3h-_ z>DX&7bYK!j%5vdv0FZk+AR8BQ3#{1YpF;kfhHRL2=M404Gd5oB&3zyya>lQH?&O|) zRQqM5gPJw8_FpF(pWD&7FHdTZGgvn$e*inI+)(c2j{Irs$48!l^^=;_fbAH#cW;tS zs5>>FI?P@9yN-C!&}X#Oozkmu`!Kf-z(@Fy=x$Bsy_(MG?K7NGuy%d}ZvX210{0hU zA5CNcCvHP->EhXBUt$m?rguHGaU7;eIV>wZJP|{2F3RHRkZ0!^7kq5?%GDx<6sT-1 zVmn=p9Eo|B7~4_5#eGyDZ465*AXCVNSR%5cWQ67}ngh5Lmh^5`YI(=bu!MhOk>n!Y zUZ$C>z$=y)ky?>OKhK zgh1{dyazObcZcped(aE%J~W3iy6(43+s?e^6*3;171x8=KhvIz{AE3C2y+v43 z?6(8?X^U6LdO?r%?m}auNWKMn6Wx?iA`=7U73+M j62DNEuXY3fw=)wyY)||d)>wrs3!TtGy7pY3?$Lh%50cwJ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sqrt.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sqrt.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5d3784590515623595122bb267b84ab0d47db6eb GIT binary patch literal 877 zcmb7CyKdVs6eUHyEI;~~icTH6XsCsvK!zeHj4UlsBuh3etSVBmV^MNQxk&?W&eEm- z(O=@)DZkLE_fmF}qFqXXmxmACbM7JEjK|6BTfv7OAwS8376G0?H=iH~B4|x=3Zqwh zisg*r8moO3?ZhpMDS~S)_ zz0h5WsrHQlm_au$AxKw3?nx%7@NNju`+%A79S%eQQbLWTm*9tMm;n1n=;kqm4LK(p zTG5U7ot~j~in5=pVkvni8`ElD=~i*4x@m<>nPp{dtdA2LE-wpxW_}Pof@HtmW}RAP z)w*0}_`|C{LshqzZqB~rr-W}wLF>Z=`mk=iWUhQA)8IH%aVo}dTQyRH8$ zM8}XSWqJUEPB08Hpw>Ph)jjjU6PW&+`QRiCZOnO7D9O1^I9IJ$*N8`)U#yFIw=*p3 z!WbpHc`Nh;i5}gt{mJWY29+5fLhO(HbZC=%%dFQ`_JuRPtEPM3raRyGZb73_`Ln-{ x?YHr^H4@lF!OP+bpOy}B!AI+ziU*E3jn0<%urKi)K2L+C#NLRykA?Ip{S7-b()a)X literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/squeeze.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/squeeze.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..325b6b213ea718547bd64bf52e5d4325d521b558 GIT binary patch literal 1018 zcmb7DJ985;5SC8&vSSC5p#Ul+*kw^w*2 zOBuyIR`_L*1`hjx!!)Es1v1!B6)JieZRk59LmAu=87Q`48@i!sEa^EJML)qWnU1JE zd?T`js^oi7$wFz^iR!Al;q?+>lk7NVCpF*sr2p$ zgz^D1={pPrWFSL_Lm2^uSO;L1QBb(>jSk;}m;oqsBiWqJk*`0sp;nbBmG#AqGN|X~ zI{}U?D~#@efm6R;B~7_Z@>RA-Fpn3Fs!Xl(qP}+DyvdV`HdT{+YEw^4o7{N$#Xgy- zhKr`rhA(xUDFeoQDYPh&lYu@F;@v*)$}#@u?abYT%a{|&2N3fR)S6t9HO=YT`$lJ& z8^ty}EyY6dmMqV8U2@ljs+MZRbRX=jj~_N%Tnjzh%UB=aVehljW?onP1Y>M@9&LH< zPXCja9)h=yfIbAQAE4TmyA9soxj%Wd7ybBN^poi*vN7k_NX~7a^Rkw!0`Y+JtCc9a zlY^`f#+0hLsHMirYfMWY{T{|Nx-nH#9Hd6bbY}Cz+i@aBl9VHu|wYj~<$#xSRdjkp&3+XZa4S`JdQUCw| literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sub.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sub.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33d3f249727358a53af626fffadd5d1079c94eee GIT binary patch literal 1028 zcmb7DO>fgc5Z$#M+i{YXA|WA8Tzw!0A+ERJ{Gxba8WUDJYcOD|mb zAN-}ga_V2;#LOmXBM~In)sEkOXy(nE@$=CrntaRH+#%#A*%<-g2`u#y3@4mcB&G0m zDyMc+m*SaQd37)CS?mG!Qy*}T`&CefX-J9a@nA)TFX%;oMc)!0^5B~AK!n0wc`Lf2 zX~gLniTgJYg`CFJ9K6Z$xoG&itl^cAa1yjlbH&;PLS3+;Yw{ZkuVH`qT9$fN3ti?P z%B!+5?pZg@(baai04A{1Q!v7&kUGNUlsnf1!h3*S?pfRe4CF2Lc>uIRi8AD%jUDI= z*Lzs%0L+qHkR>hX()o^AP)y*cD(g}U&Ze@>c%CU8yT;8cWxS^4!ua#cOrEPBL=M5j zuNR4~7fI3O^91vJqD7-xSyb(%-7{Szv$Yf|nXaWtR5u+jzL@@JAywHn?AZtjS(eV% z5lAq;z4DPo9=zX`?EF@=M|CzAY@ItR zWLq;^bQJ90`J6oX8=sTYI4~h&O;!uWOvG5-@~%QWWb9LyRhyeZUS&!_L(N()vBL5Y z4JNuHgB1j|u=I*|5Sl^DEZ3IHK9VMUxz6?#{x!C5LuW|sbbWfC{syWD@cjS) literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sum.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/sum.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80b3cfec0c65891925c8a104abf99bd6ce6602ae GIT binary patch literal 1359 zcmcIkOK;Oa5Z+xs-&lmdrx&4Gl6R236u0u-|PN@XF zAaUY1@R#<=sehp-W;O{FL66;N$De1`^UZ7XbZIHrK8^T}MaWNbVR?YJVXJo_1Q9eR zA%!Q)Sz(11MV*z~g%dgk+koBB1?&hn_XO zr*ulgK+rwXZkz!N*=y)SCGCrel8s4uxmsve1 zk~)juWJg)4t-Wy(qpQV&v}S4a03;@bkR_I&f}Iecw*gziHrN3S!5i!X_JnV+CmIl9 zAh9Gdn|nsbF6<_3^#sI(33`{Dk_p)-6Pg0SX95zP`xClPUjkj9W^}^7v#)@_rL(J> zbyBKIa*@TgcC&Icu2qcL;X*D4_D$Go4MZQjzrFs6elZ+^OxZVfV1p-$rL+1;-Da9~ z9%&0awW;*sn;+!-S+_1m-EjKNG>^EhdOsSsEexX^ztf>af4IRV9CX2dv6;o*geC>2J$b(r(F0reIT0AS8rVG$5Vs8mQ736Fawi8#{}gcfEQry12{<}ZAeMsA2fkx zC8HQ)O{k+X8gK|WE@QxvjGIKKWlD*PWYSX=D|$2O=^G+bncNeZs8q2&>}gNSOwxBG zpFBVna+Onm`dUrRbKItGku)?7c7* zW;zT8U;*aN!Kpz(87L;H4DJb34<&=@p+&V-01gKpLc0KSXW(|^hU{ofcfoghjdUq8 zeXPY=@lF}nT3*{$^MR;orOKISRpWe!6CbZ{g}rt^iJd~S-!FqjKl=Dwp(d<`Fszx}cRkv)VJ%w}wyCa7shQ>?|wbC#@@!3DVKIm%yWKiAJ^8@Mm zo;2SFEYd8`|J!z0##Y-9oX<4eB-ePAHpT!0-2;UqTG&I2+SsFcCu90wFY_0SWCkP^B>;c6Mebb_P4cE@--JL&JaY zOKz$57pS<`nb}~R&yt-H^8@w;o zvcgn{<^xzjH;*9*S3=~Eo)yAXEdjO=Jl zciwk;irOj4ekjYeV4YB=)vVU7WKOkexyXF$SB*{A#tePO``*jHyxz#%#)%Z27i9JYnq9wruu0<%rYhY)M`WCBDSxX|R;Un^5=p5xq};16jb*T>t<8 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/tfidf_vectorizer.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/tfidf_vectorizer.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..617555acccaa0853c81ca14594772a48fd815df8 GIT binary patch literal 4052 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 literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/unpool_mixin.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/unpool_mixin.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..99c03aa5676a8170afed6b875df70f62e401dcd9 GIT binary patch literal 4573 zcmb7ITaO#J6&}t_ckSBU_>vn2F49!3vs*ifAB@6q;-W2DWSb^VT&N8Ovm&LHR+^DH zR4gw>PcjPh!D!Kc(O=TPQ1GP%`sDXM<*DBxXSI^-IF1(N9A3`hA^DvP_x)C@e)lg) z{Lf2{^IvD}=YzhBl7E1TJDiQ3F2mOyyA!YLG3xU``(2+ozjC!S8)(acM+sM_ZLCojl89^ z2r=7GOSY&K74BVe7FFdJl_mR=yQnSdkQML%t2Brjxjf|VfECp}2eO)FU&Tmn70xIu z!lF?$m)@dX)Ohv8TkI4&@?WYlsurHAQQy+#wWsdFGkyL>pRei#F6b(>#~SU+j%j0G z)V}OMrZZ|3Uf~yQtgu_`{Ef-T$k|npT+~Y0yG6kLlNv^EfumWV4Q*RRtL!~QZwtLG z&WxPh0fC}^dc7X4{XR+N_A-X)Aj$xUL=CfaHAUhcoM)zTK^^MmiIAxn$N6zG6}plu zIpiYO{xspJ4}bmO9>C=juyD`eFrCg+uD!8HwFkuM8o|!+N|L98L@Al;i?Knd=qIyr zIj&vR*EJ=RG@oX_>ftpMY`m^52L6)ZT_moKUO!mjwBh!vm|KK=D z`B=#O;3(;xh?E~#8S#XSXn*=x*C)xmJQ-R)zk|vN+Km48T;Hv-CPQ)S?jCES6{7g8 zZvVVpw(GXt5IwtY9W(2gb9%`_!`SKmx%eJ=2Kt3%F(&&d8UttH&wr^L7@WI=#s9+j z>K4qc^&s~^z> za_YBH@;WM~;j@eE5{uaB+v~`B-uPERp$RTRn?cy$K`3X$P~h&D^hGo>ZWg_TyK4Ku zVSp0Ozf`^o;K0KraAolLF+u=b|5XR*Lv2C*uc2eWN})7Iu=qy^I^QdzmJ2N;%r2!jG7V79y^8U znq|I2P$nZRM>b2=84Xv{5!C{&9wV@kk#s8ZB0k#hCArdp4HN-_)B88&k1=4(M()te zrZE>C+AET85nIzX%1Bj9#Uo30>vXX86uMPIliB?QJlz_avC333)`m2@(G}{YIpp%U zjSnfM^IMdh4AyB~f@}Ag@8SzHtQr?zWvB0cah{Crza*lrygr3EGJIo`UxI*rIY_gN z)y;1zrrg3Wt?k+(gsr$m2zx_qM<@mikYK@rf`_j^fcGEyHaZj@cc1!{q#3*V^R``m zn&2j3P!_6N*k9chq3cyF=v!=PLk`KJi#SKSXIPYa?u98&6Unk?4 zfEs5Vk?9~@_lM(gG@F`(fvSXd1c{#53@$G*WpJEtuasajkkwJ>>b>6`et!R>!~67{ zIMbn2suLKfuOZ(UhX+xes*M&0fQiNEheZ7hl_r3jb2I?gpro)1A2CuGGkEt7S7||w{ECTZVNTC@Ji>N~J zfg>qLjYq{EeSP{4+(iX539sRRAy!nWg+lx#C#cHO#iOLkgQv)ANE&zPZ{YI~@v4Ry zHOi2R+8&||T7E%~0(am-V#BmyEoHljcAXv^14zI)wb3eQ<**=auo~ogixz0VXcZL0 zS`Qpv`MvX*^9QGB!J4YchuhX7A~_Ltt>Rp?g(;FmKjhzQY>{1&dWYK>rrGN;6Kp2UqPNIdp7lMVnDxS|wQZA* zV@px<2r_w*asJOdV5r07PwnSDd=BB}4d&ZlCvun^jYXXI=ru)yx*-Lh^+Y_C8P^rW zCeqhh%XJ#3z;WvXBTv_|ROIn^cp`KNGwUTv*K^dknK9|b~Vb$ zx;uR&$8nj=A_47QFdggX)(y-BcN<5E>K)VbW*{^>((ciXu8)I{wI_wzw#3&Uy+FyY zp>mpdBjBYFve(@*>Nw-_U94&nN=boDl4Fph)0&?2n35*(q@XP6z0kS`g|7cHi%Kezhd PfrU9aB?wrNHNF1>wxEA~ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/unsqueeze.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/unsqueeze.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f7eac0b9b35c483edbe0dfc6d88e75d31270c17 GIT binary patch literal 1253 zcmcIjOK;Oa5Z?8!A9=J=OF>OR71ta{sJK?8LI{wMdO--u5?UGWx+L)<-F0ZF94_gF z1HJMa_)B}`)W5)q8RyYT^op&W{dQ(NGdth-*~Uim_O#f%;p&0%7v(+$ zph!q12_3~GmChxBWE?P)yv8nIS9&$}qz^>|+J( z6&pfWK)mD?pF@HX(_!UE)*;~IO5PzIGIOW0Jzac(S~*0ua1dKZp=p7+aa+)pO) zsE;9@EMg{UabBNAne;y|NH_gYiy`PwRy6nE626FwEGzO&h-S7y5T{L>v`x3^CM*xo z#nyT-dQ0y$pEw-2YCbUrbQ-uypvPC(Ukc-=_dwredIvUrAH@R{SpPzF0NKVDrOlwo z#R0mTdSIN3dpD`q_WzK)xek7?e=GaW9oY{~fTBQ%Jj#?1wkbqb$VrO0EyUR*N|%;a zoJPiEs{CBYx&`_n-uMxUo4eNt8&LlzI7kM04tTrW=G~@l!NE3fXw_S&cwEm*ne!rgz|R%YZ(a}>yVo%^n$Y;d@^-4Xr`1_=(F044-p=D~dY1$AL5Q2+n{ literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/upsample.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/upsample.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e15a6dbb678108f1c245cf3000cd8d38e6461e8 GIT binary patch literal 2705 zcma);O>Z1Y8OOW&{cUW=@h0)|HmnxdL9C57z_L=2ylYqNKp%^)!S8LPft(x zP~FCf)pKE%0|%BP7mi$z_$Zt>p}KPNSK!3|sh+U|i3HQ?r~lRUbiMxSdFJk55Z?b? zmi{m@jDH$0{e0;AxSK!2aD%hbNctyBOkK7T8&9)zW^Up#s`g7dlR2tv%>LGSJ#DH)fm3CNo6HgC!FKVHaD)4XB8RurZI8>=T2>Jowz;f$*2s zlJ!@z&Dj%UG`Pe_jl&UBfq0&ac{`~q6gD1Y`BYT=)2!m9ka*+ORrNfr=a8H8OtzD( zOq;X$yp}Eb&zqEsCYO_S3tl@;$7fZJN*}U0&E`V+Pv=cGo0sDFVzib+DSmY}k%AAu z_wjI2&Cgoc;jyTiT8_*5d@rXFu74K9eca7=VT6$|ZX~9#IOFE$#*!sAw8d?$9cYKU zTD#oCY<(Hvv)qKCpM%@R{Zrh{FJU^9vt6TO1-59{*fkbbXBBK|6z0-c*saysOUA9K zC4bP`g~M&`EKNrKZsBosu`~;RY4B+3$!FRl>^-=F&f`NBwR&19pX9A%=2t*f8MYC@U`;Wmhy{cY2=5lSZ-U%6s0o{ue`j6)pbj!~J$P-yfgl(|yA0 z-F|s!*L68<$NQ%}fzAGBJ(2roD}?suFH}ekr}?SKr*ELWh9+j1+bpKbyv1C0adW*U zd)K~K0EBQS2s8kHhxlIr6gD>7S+a%GIotvuZi}t&Y;FS^m+THGTzIRuj(!WP-};?X z_&p|zpbLrssQ6Q}`OQiPQ&WD?hDB7w#b6Os;Yx2T0<^c;d7VEtp|*JVdlUUf_lz#U zGse>>ZggzSP#W-!Kbf8RNAnAILMMFlP|`FtZpv-)tQ5^9?dK((B{?ATUqCSB@b(4H ztKCd4uz@oHD*5rql(*omqC73LrcLXrd@ibeGB>H#&TH(9&xM$i>OV27xpJ_t zwUoEX^A35M?N~XJS#}~+d?cu=pX-j4|KQ=z9v&WibfmV(9y~ct4-X!G^67&|N1#p0 z>;=B7+Pm+mH)q*Yq^nakmh}vSLYN}%MxorLuHGc`B{E+o^A$2Q4f%B#6;|RrJr$Fa z(>BriT2qBX*fSy-SBp$F7m2Pn{|`Ev@lbqWu+4+0UkxV1D_CHPQj zX?E@jTbkg~DT2;}W`FoA0vCwo#&7Y>!Y77TI)GQ$`Pv4ZTSQB9$3Q7Y3n3UDP*jDE zx~SLy!yXv^+e(9H`49MRQXX1FV7S-Y@W!`10ILz6;XR|D7iJZAF#@jjBck|b7i)?m z9=}ZSFN`DO8L}m1te1Gcq!=pSBJ&!K@72^g7TmQw*;~vvH*_@Jfm-A31Md*!*CPJG;mA{dnpW9Nq^Szi z6j|%6Bps(It>LOB$`M4GKD5Xo`jy`&^J6mC2k&aAI&)LbYFrrKjidPX=%(I3@8$JuRD4 zJs5T6-S@PIzdfg-#70Ps8lj*DNZkl@sSbOMp497RtNeTYvVBN|>rmsHSa@}Ldhi=Di*bWTrlJ9U$WI#|4x_YJMpsnwnG_LPtWU{@|1rNMweMo5& zvemYB*Zv1{Q*8G8X*qQ3(rlVlNe3S7JD9fL#=RU&x!mjY<@>$va!bnQ>o4K#lXm_? zZ{?F2(M9Cs>)oh){%NZ>rP70F0JuG|Ws9_{L zap#ny%gK+^^0YV$(|^n%8BBN>l@Dfq1fL(kDCIZtMQ56|E}`~i0;t(O1* literal 0 HcmV?d00001 diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/xor.cpython-36.pyc b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/__pycache__/xor.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcb27a9e6475b36471fba6d7d51ac6c47ae99994 GIT binary patch literal 898 zcmZvay^ho{5XbF&@7IaD3QJ%h9y%R>j`9d}$RimyNuE$5LLP6ahy=YHZ0Q@q6CPg^9*acy+h9w#G#_&M zk)(qgh(gX%YL8wQZ3D7V<;Au3PJW zQo6)*_QMA;12a#+3CEv%!snEG*92k*pnV=V9r6%3B8_>MPz*Ql0JL{t<_O$|T#^l~ z=*Ihr*c6G6W!==B;Otzhf|rHqQs4TeG&X1z7dBd46?$%d5j}v1a*<(T zPdm{Xr7Nkf+?;h)cG2fV3k%4bLB?z)Yk*}PY== 7 or node.attrs.get("is_test", 0): + inputs = [x, running_mean, running_variance, bias, scale] + return [cls.make_tensor_from_onnx_node(node, inputs=inputs)] + spatial = node.attrs.get("spatial", 1) == 1 + momentum = node.attrs.get("momentum", 0.9) + axis = [0] if spatial else [0] + list(range(2, total_num_dim)) + mean, variance = tf.nn.moments(x, axis) + running_mean = running_mean * momentum + mean * (1 - momentum) + running_variance = running_variance * momentum + variance * (1 - momentum) + # TODO: need to conform to the documentation here + inputs = [x, running_mean, running_variance, bias, scale] + return [cls.make_tensor_from_onnx_node(node, inputs=inputs)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_9(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/bitshift.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/bitshift.py new file mode 100644 index 0000000..252f74d --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/bitshift.py @@ -0,0 +1,20 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("BitShift") +class BitShift(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + tf_func = tf.bitwise.left_shift if node.attrs.get( + "direction") == "LEFT" else tf.bitwise.right_shift + return [ + cls.make_tensor_from_onnx_node(node, tf_func=tf_func, **kwargs) + ] + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/broadcast_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/broadcast_mixin.py new file mode 100644 index 0000000..4af769a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/broadcast_mixin.py @@ -0,0 +1,45 @@ +import numpy as np +import tensorflow as tf + + +class BroadcastMixin(object): + + @classmethod + def explicit_broadcast(cls, inputs, axis=None, tensor_dict=None): + x = inputs[0] if isinstance(inputs[0], + tf.Tensor) else tensor_dict[inputs[0]] + y = inputs[1] if isinstance(inputs[1], + tf.Tensor) else tensor_dict[inputs[1]] + + if np.prod(y.shape) == 1: + return y + + if not isinstance(x, tf.Tensor) or not isinstance(y, tf.Tensor): + raise ValueError("Targets for explicit broadcasting need to be Tensor.") + + if axis is None: + return y + + total_num_dim = len(x.get_shape()) + if axis < 0: + axis += total_num_dim + + if axis + len(y.get_shape()) == total_num_dim: + return y + + dims = [axis + i for i in range(len(y.get_shape()))] + new_y = y + for i in range(total_num_dim): + if i not in dims: + new_y = tf.expand_dims(new_y, i) + return new_y + + @classmethod + def limited_broadcast(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + y = tensor_dict[node.inputs[1]] + if node.attrs.get("broadcast") == 1: + y = cls.explicit_broadcast([x, y], node.attrs.get("axis", None)) + return [cls.make_tensor_from_onnx_node(node, inputs=[x, y], **kwargs)] + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cast.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cast.py new file mode 100644 index 0000000..b08a87b --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cast.py @@ -0,0 +1,44 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description + + +@onnx_op("Cast") +@tf_func(tf.cast) +@partial_support(True) +@ps_description("Cast string to float32/float64/int32/int64 " + + "are not supported in Tensorflow.") +class Cast(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"rename": {"to": "dtype"}} + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_9(cls, node, **kwargs): + inp = kwargs["tensor_dict"][node.inputs[0]] + to_type = node.attrs.get("to") + + if to_type == tf.string: + return [tf.as_string(inp)] + + if inp.dtype == tf.string: + if to_type not in [tf.float32, tf.float64, tf.int32, tf.int64]: + raise RuntimeError( + "Cast string to type {} is not supported in Tensorflow.".format( + to_type)) + return [tf.strings.to_number(inp, to_type)] + + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/ceil.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/ceil.py new file mode 100644 index 0000000..45ea7f5 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/ceil.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Ceil") +@tf_func(tf.ceil) +class Ceil(BasicMathMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/clip.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/clip.py new file mode 100644 index 0000000..a3956f5 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/clip.py @@ -0,0 +1,70 @@ +import tensorflow as tf + +from onnx_tf.common import exception +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description + + +@onnx_op("Clip") +@partial_support(True) +@ps_description("Clip input in uint64 is not supported in Tensorflow.") +class Clip(BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + # uint64 cannot upcast to any tensorflow supported datatype + # for tf.clip_by_value that didn't lose precision + if x.dtype == tf.uint64: + exception.OP_UNSUPPORTED_EXCEPT( + "Clip input, min and max in " + str(x.dtype) + " datatype", + "Tensorflow") + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + x_dtype = x.dtype + + if cls.SINCE_VERSION < 11: + # min/max were required and passed as attributes + clip_value_min = node.attrs.get("min", tf.reduce_min(x)) + clip_value_max = node.attrs.get("max", tf.reduce_max(x)) + else: + # min/max are optional and passed as inputs + clip_value_min = tensor_dict[node.inputs[1]] if len( + node.inputs) > 1 and node.inputs[1] != "" else x_dtype.min + clip_value_max = tensor_dict[node.inputs[2]] if len( + node.inputs) > 2 and node.inputs[2] != "" else x_dtype.max + + # tf.clip_by_value doesn't support uint8, uint16, uint32, int8 and int16 + # dtype for x, therefore need to upcast it to tf.int32 or tf.int64 + if x_dtype in [tf.uint8, tf.uint16, tf.uint32, tf.int8, tf.int16]: + cast_to = tf.int64 if x_dtype == tf.uint32 else tf.int32 + x = tf.cast(x, cast_to) + clip_value_min = tf.cast(clip_value_min, cast_to) + clip_value_max = tf.cast(clip_value_max, cast_to) + y = tf.clip_by_value(x, clip_value_min, clip_value_max) + y = tf.cast(y, x_dtype) + else: + y = tf.clip_by_value(x, clip_value_min, clip_value_max) + + return [y] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_12(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/compress.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/compress.py new file mode 100644 index 0000000..123f06c --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/compress.py @@ -0,0 +1,36 @@ +import copy +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Compress") +@tf_func(tf.gather) +class Compress(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + attrs = copy.deepcopy(node.attrs) + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + condition = tensor_dict[node.inputs[1]] + + x = tf.reshape(x, [-1]) if node.attrs.get("axis") is None else x + + indices = tf.constant(list(range(condition.shape[0])), dtype=tf.int64) + not_zero = tf.not_equal(condition, tf.zeros_like(condition)) + attrs['indices'] = tf.boolean_mask(indices, not_zero) + + return [ + cls.make_tensor_from_onnx_node(node, inputs=[x], attrs=attrs, **kwargs) + ] + + @classmethod + def version_9(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/concat.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/concat.py new file mode 100644 index 0000000..85a1ee7 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/concat.py @@ -0,0 +1,27 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Concat") +@tf_func(tf.concat) +class Concat(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + inputs = [kwargs["tensor_dict"][inp] for inp in node.inputs] + return [cls.make_tensor_from_onnx_node(node, inputs=[inputs])] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_4(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant.py new file mode 100644 index 0000000..d009882 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant.py @@ -0,0 +1,74 @@ +import numpy as np + +from onnx import numpy_helper +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from onnx_tf.common import data_type + + +@onnx_op("Constant") +@tf_func(tf.constant) +class Constant(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + attr_value = node.attrs["value"] + dtype = data_type.onnx2tf(attr_value.data_type) + value = numpy_helper.to_array(attr_value) + return [ + cls.make_tensor_from_onnx_node( + node, inputs=[value], attrs={ + "dtype": dtype + }) + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_9(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + # either value or sparse_value + if "value" in node.attrs: + return cls._common(node, **kwargs) + else: + sparse_value = node.attrs["sparse_value"] + indices = numpy_helper.to_array(sparse_value.indices) + values = numpy_helper.to_array(sparse_value.values) + shape = np.array(sparse_value.dims) + return [tf.SparseTensor(indices, values, shape)] + + @classmethod + def version_12(cls, node, **kwargs): + if "value" in node.attrs or "sparse_value" in node.attrs: + return cls.version_11(node, **kwargs) + elif "value_float" in node.attrs: + value = node.attrs["value_float"] + dtype = tf.float32 + elif "value_floats" in node.attrs: + value = node.attrs["value_floats"] + dtype = tf.float32 + elif "value_int" in node.attrs: + value = node.attrs["value_int"] + dtype = tf.int64 + elif "value_ints" in node.attrs: + value = node.attrs["value_ints"] + dtype = tf.int64 + elif "value_string" in node.attrs: + value = node.attrs["value_string"] + dtype = tf.string + elif "value_strings" in node.attrs: + value = node.attrs["value_strings"] + dtype = tf.string + return [ + cls.make_tensor_from_onnx_node(node, + inputs=[value], + attrs={"dtype": dtype}) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant_fill.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant_fill.py new file mode 100644 index 0000000..e718fdb --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant_fill.py @@ -0,0 +1,44 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("ConstantFill") +@tf_func(tf.fill) +class ConstantFill(BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + if node.inputs and "shape" in node.attrs: + raise ValueError( + "Cannot set the shape argument and pass in an input at the same time." + ) + if not node.inputs and "extra_shape" in node.attrs: + raise ValueError("Cannot set extra_shape when there is no input.") + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"value": 0.}} + + @classmethod + def version_1(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + + if "shape" in node.attrs: + shape = node.attrs["shape"] + else: + shape = tensor_dict[ + node.inputs[0]].get_shape().as_list() if node.attrs.get( + "input_as_shape", 0) == 0 else tensor_dict[node.inputs[0]] + + if "extra_shape" in node.attrs: + shape = tf.concat([shape, node.attrs["extra_shape"]], 0) + + value = node.attrs.get("value", 0.) + + if "dtype" in node.attrs: + return [tf.cast(tf.fill(shape, value), dtype=node.attrs["dtype"])] + + return [cls.make_tensor_from_onnx_node(node, inputs=[shape], **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant_of_shape.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant_of_shape.py new file mode 100644 index 0000000..27c228f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/constant_of_shape.py @@ -0,0 +1,37 @@ +import copy + +import tensorflow as tf + +from onnx import numpy_helper + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("ConstantOfShape") +@tf_func(tf.fill) +class ConstantOfShape(BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + attrs = copy.deepcopy(node.attrs) + + shape = kwargs["tensor_dict"][node.inputs[0]] + + # make sure the shape dtype is either int32 or int64 + if shape.dtype not in [tf.int64, tf.int32]: + shape = tf.cast(shape, tf.int64) + + # the default value is 0, float32 + if "value" in node.attrs: + attr_value = node.attrs["value"] + value = numpy_helper.to_array(attr_value) + attrs["value"] = value[0] + else: + attrs["value"] = 0. + + return [ + cls.make_tensor_from_onnx_node( + node, inputs=[shape], attrs=attrs, **kwargs) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/control_flow_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/control_flow_mixin.py new file mode 100644 index 0000000..e1f0301 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/control_flow_mixin.py @@ -0,0 +1,9 @@ +from .broadcast_mixin import BroadcastMixin + + +class LogicalMixin(BroadcastMixin): + pass + + +class ComparisonMixin(BroadcastMixin): + pass diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv.py new file mode 100644 index 0000000..656b3d1 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv.py @@ -0,0 +1,15 @@ +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .conv_mixin import ConvMixin + + +@onnx_op("Conv") +class Conv(ConvMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.conv(node, kwargs["tensor_dict"]) + + @classmethod + def version_11(cls, node, **kwargs): + return cls.conv(node, kwargs["tensor_dict"]) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_integer.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_integer.py new file mode 100644 index 0000000..8018335 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_integer.py @@ -0,0 +1,63 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .conv_mixin import ConvMixin + + +@onnx_op("ConvInteger") +class ConvInteger(ConvMixin, BackendHandler): + + @classmethod + def _apply_zero_point(cls, base, zero_point): + base = tf.cast(base, tf.float32) + zero_point = tf.cast(zero_point, tf.float32) + return base - zero_point + + @classmethod + def version_10(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + w = tensor_dict[node.inputs[1]] + + def process_conv(new_x, new_w): + # Remove zero-points from inputs + if len(node.inputs) == 4: + node.inputs.remove(node.inputs[3]) + if len(node.inputs) == 3: + node.inputs.remove(node.inputs[2]) + + new_dict = { node.inputs[0]:new_x, node.inputs[1]:new_w } + + # Use common conv handling + conv_node = cls.conv(node, new_dict) + + return conv_node + + # Apply x_zero_point first + x = cls._apply_zero_point( + x, tensor_dict[node.inputs[2]]) if len(node.inputs) > 2 else tf.cast( + x, tf.float32) + + # Apply w_zero_point next + if len(node.inputs) == 4: + w_zero_point = tensor_dict[node.inputs[3]] + if w_zero_point.shape.rank == 0: + # Simply apply w_zero_point for scalar + w = cls._apply_zero_point(w, w_zero_point) + elif w_zero_point.shape.rank == 1: + # Need additional processing for 1d w_zero_point + tensor_list = [] + process_shape = [1] + [w.shape[i] for i in range(1, len(w.shape))] + for i in range(w.shape.as_list()[0]): + # Apply w_zero_point for each element in 1d tensor + out_tensor = cls._apply_zero_point(w[i], w_zero_point[i]) + tensor_list.append(tf.reshape(out_tensor, process_shape)) + w = tf.concat(tensor_list, 0) + else: + raise ValueError("Unsupported w zero point: {}".format(w_zero_point)) + else: + # Just cast without processing w + w = tf.cast(w, tf.float32) + + return [tf.cast(process_conv(x, w)[0], tf.int32)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_mixin.py new file mode 100644 index 0000000..9720c8a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_mixin.py @@ -0,0 +1,274 @@ +import tensorflow as tf + +from onnx_tf.common import get_data_format +from onnx_tf.common import get_perm_from_formats +from onnx_tf.common import supports_device +from onnx_tf.common import exception +from .broadcast_mixin import BroadcastMixin +from .pad_mixin import PadMixin + +# Constant string used to indicate that requested padding +# is not natively supported in Tensorflow. +PAD_TF_INCOMPATIBLE = "PAD_TF_INCOMPATIBLE" + + +class ConvMixin(BroadcastMixin): + + @classmethod + def conv(cls, node, input_dict, transpose=False): + """ Convolution method for both conv and transposed conv + For transposed conv, + Attr pads is not used for input, but declares how much output is padded. + Here, output means output from transposed conv which already pad output_padding if set. + So the pseudo explanation for output should be: + output = conv_transpose_output + output_padding - pads + And conv_transpose_output shape should be: + conv_transpose_output_shape[i] = strides[i] * (input_shape[i] - 1) + kernel_shape[i] + """ + x = input_dict[node.inputs[0]] + x_rank = len(x.get_shape()) + x_shape = x.get_shape().as_list() + spatial_size = x_rank - 2 + + support_cuda = supports_device("CUDA") + storage_format, compute_format = get_data_format(x_rank) + compute_c_idx = compute_format.find("C") + spatial_format = "".join([d for d in compute_format if d not in ["N", "C"]]) + + in_weights = input_dict[node.inputs[1]] + weights_rank = len(in_weights.get_shape()) + if transpose: + # Translate weights from (C x M x KH x KW) to (KH x KW X M X C) + perm = list(range(2, weights_rank)) + [1, 0] + else: + # Translate weights from (M x C x KH x KW) to (KH x KW X C X M) + perm = list(range(2, weights_rank)) + [1, 0] + + if "kernel_shape" in node.attrs.keys(): + kernel_shape = node.attrs["kernel_shape"] + assert in_weights.get_shape().as_list()[2:] == kernel_shape, ( + "kernel_shape " + "attr of convolution does not match the actual weight " + "passed to this operation, attr {}, actual {}").format( + kernel_shape, + in_weights.get_shape().as_list()) + else: + kernel_shape = in_weights.get_shape().as_list()[2:] + + weights = tf.transpose(in_weights, perm) + dilations = node.attrs.get("dilations", [1] * spatial_size) + strides = node.attrs.get("strides", [1] * spatial_size) + + pads = node.attrs.get("pads", [0, 0] * spatial_size) + + # Check auto_pad nonexistent or NOTSET first + if "auto_pad" not in node.attrs or node.attrs["auto_pad"] == "NOTSET": + if not transpose: + if pads != [0, 0] * spatial_size: + x = PadMixin.get_padding_as_op(x, pads) + pad_mode = "VALID" + else: + pad_mode = "NOTSET" + # Then we use auto_pad to setup pad_mode + elif node.attrs["auto_pad"] == "SAME_UPPER": + pad_mode = "SAME" + elif node.attrs["auto_pad"] == "VALID": + pad_mode = "VALID" + elif node.attrs["auto_pad"] == "SAME_LOWER": + pad_mode = PAD_TF_INCOMPATIBLE + else: + raise ValueError("Invalid auto_pad attribute: {}".format( + node.attrs["auto_pad"])) + + # Currently auto_pad = SAME_LOWER is not supported + if pad_mode is PAD_TF_INCOMPATIBLE: + if transpose: + exception.OP_UNSUPPORTED_EXCEPT( + "ConvTranspose with auto_pad `SAME_LOWER`", "Tensorflow") + else: + exception.OP_UNSUPPORTED_EXCEPT("Conv with auto_pad `SAME_LOWER`", + "Tensorflow") + + group = node.attrs.get("group", 1) + + weight_groups = tf.split(weights, num_or_size_splits=group, axis=-1) + + if support_cuda: + xs = tf.split(x, num_or_size_splits=group, axis=1) + else: + x = tf.transpose( + x, perm=get_perm_from_formats(storage_format, compute_format)) + xs = tf.split(x, num_or_size_splits=group, axis=-1) + + if transpose: + if dilations != [1] * spatial_size: + raise RuntimeError("Cannot set non-1 dilation for conv transpose.") + convolved = [] + for (x, weight) in zip(xs, weight_groups): + x_spatial_shape = [ + x_shape[storage_format.find(d)] for d in spatial_format + ] + weights_shape = weights.get_shape().as_list() + output_shape = node.attrs.get("output_shape", None) + conv_output_shape = [x_shape[storage_format.find("N")]] + + # calculate output shape + if pad_mode == "NOTSET": + if output_shape is None: + conv_output_shape += [ + strides[i] * x_spatial_shape[i] - strides[i] + + (kernel_shape[i] - 1) * dilations[i] + 1 + for i in list(range(spatial_size)) + ] + else: + conv_output_shape += [ + s + pads[i] + pads[spatial_size + i] + for i, s in enumerate(output_shape[-2:]) + ] + conv_output_shape.insert(compute_c_idx, weights_shape[-2]) + + def handle_dynamic_batch_size(output_shape, batch_idx): + output_shape[batch_idx] = tf.shape(x)[batch_idx] + return tf.stack(output_shape) + + # process dynamic batch size + if conv_output_shape[storage_format.find("N")] is None: + batch_idx = storage_format.find("N") + conv_output_shape = handle_dynamic_batch_size(conv_output_shape, + batch_idx) + + # make strides to match input rank + strides_full = [1] + strides + strides_full.insert(compute_c_idx, 1) + + # get corresponding function in tf + if spatial_size == 1: + conv_func = tf.contrib.nn.conv1d_transpose + strides_full = strides[0] + elif spatial_size == 2: + conv_func = tf.nn.conv2d_transpose + elif spatial_size == 3: + conv_func = tf.nn.conv3d_transpose + else: + raise NotImplementedError( + "Transposed convolution for {}d is not implemented in Tensorflow". + format(spatial_size)) + + # use raw input x to do transposed conv + conv_rs = conv_func( + x, + weight, + conv_output_shape, + strides_full, + padding="VALID", + data_format=compute_format) + + # pad output first by output_padding attr + if "output_padding" in node.attrs and output_shape is None: + output_padding = [[0, 0] + ] + [[0, p] for p in node.attrs["output_padding"]] + output_padding.insert(compute_c_idx, [0, 0]) + conv_rs = tf.pad(conv_rs, output_padding) + + # remove pads set in pads attr + conv_rs_shape = conv_rs.get_shape().as_list() + begin = [0] + pads[:spatial_size] + begin.insert(compute_c_idx, 0) + size = [ + s if d in ["N", "C"] else s - pads[spatial_format.find(d)] - + pads[spatial_format.find(d) + spatial_size] + for d, s in zip(compute_format, conv_rs_shape) + ] + + # process dynamic batch size + if size[compute_format.find("N")] is None: + batch_idx = compute_format.find("N") + size = handle_dynamic_batch_size(size, batch_idx) + + conv_rs = tf.slice(conv_rs, begin=begin, size=size) + + convolved.append(conv_rs) + else: + # No need to check pads if auto_pad is specifically provided. + # The assumption is that once auto_pad is provided as either VALID + # or SAME_UPPER (SAME_LOWER is currently not supported in TF) the + # output_shape will always be inferred. That is, the output_shape + # and output_padding will not be used in this case. + if pad_mode == "VALID": + conv_output_shape += [ + strides[i] * (x_spatial_shape[i] - 1) + weights_shape[i] + for i in list(range(spatial_size)) + ] + else: + conv_output_shape += [ + strides[i] * x_spatial_shape[i] + for i in list(range(spatial_size)) + ] + conv_output_shape.insert(compute_c_idx, weights_shape[-2]) + + # process dynamic batch size + if conv_output_shape[storage_format.find("N")] is None: + batch_idx = storage_format.find("N") + conv_output_shape = handle_dynamic_batch_size(conv_output_shape, + batch_idx) + + # make strides to match input rank + strides_full = [1] + strides + strides_full.insert(compute_c_idx, 1) + + # get corresponding function in tf + if spatial_size == 1: + conv_func = tf.contrib.nn.conv1d_transpose + strides_full = strides[0] + elif spatial_size == 2: + conv_func = tf.nn.conv2d_transpose + elif spatial_size == 3: + conv_func = tf.nn.conv3d_transpose + else: + raise NotImplementedError( + "Transposed convolution for {}d is not implemented in Tensorflow". + format(spatial_size)) + + # use raw input x to do transposed conv + conv_rs = conv_func( + x, + weight, + conv_output_shape, + strides_full, + padding=pad_mode, + data_format=compute_format) + convolved.append(conv_rs) + + else: + convolved = [ + tf.nn.convolution( + x, + weight, + pad_mode, + strides=strides, + dilation_rate=dilations, + data_format=compute_format) + for (x, weight) in zip(xs, weight_groups) + ] + + if len(node.inputs) == 2: + if support_cuda: + output = tf.concat(convolved, axis=1) + else: + output = tf.concat(convolved, axis=-1) + output = tf.transpose( + output, perm=get_perm_from_formats(compute_format, storage_format)) + else: + bias = input_dict[node.inputs[2]] + bias = cls.explicit_broadcast([x, bias], compute_c_idx) + + if support_cuda: + output = tf.concat(convolved, axis=1) + output = tf.add(output, bias) + else: + output = tf.concat(convolved, axis=-1) + output = tf.add(output, bias) + output = tf.transpose( + output, perm=get_perm_from_formats(compute_format, storage_format)) + + return [output] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_transpose.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_transpose.py new file mode 100644 index 0000000..6449a67 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/conv_transpose.py @@ -0,0 +1,21 @@ +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from .conv_mixin import ConvMixin + + +@onnx_op("ConvTranspose") +@partial_support(True) +@ps_description("ConvTranspose with dilations != 1, or " + + "transposed convolution for 4D or higher " + + "are not supported in Tensorflow.") +class ConvTranspose(ConvMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.conv(node, kwargs["tensor_dict"], transpose=True) + + @classmethod + def version_11(cls, node, **kwargs): + return cls.conv(node, kwargs["tensor_dict"], transpose=True) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cos.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cos.py new file mode 100644 index 0000000..d996a73 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cos.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Cos") +@tf_func(tf.cos) +class Cos(BasicMathMixin, BackendHandler): + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cosh.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cosh.py new file mode 100644 index 0000000..10ca889 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cosh.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Cosh") +@tf_func(tf.cosh) +class Cosh(BasicMathMixin, BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cumsum.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cumsum.py new file mode 100644 index 0000000..1b2d391 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/cumsum.py @@ -0,0 +1,46 @@ +import tensorflow as tf + +from onnx_tf.common import exception +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("CumSum") +@tf_func(tf.math.cumsum) +@partial_support(True) +@ps_description( + "CumSum inputs in uint32/uint64 " + "are not supported in Tensorflow." +) +class CumSum(BackendHandler): + @classmethod + def args_check(cls, node, **kwargs): + supported_dtype = [ + tf.bfloat16, tf.half, tf.float32, tf.float64, tf.uint8, tf.uint16, + tf.int8, tf.int16, tf.int32, tf.int64, tf.complex64, tf.complex128 + ] + x = kwargs["tensor_dict"][node.inputs[0]] + if x.dtype not in supported_dtype: + exception.OP_UNSUPPORTED_EXCEPT( + "CumSum input in " + str(x.dtype) + " which", "Tensorflow") + + @classmethod + def version_11(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + inputs = [x] + + if len(node.inputs) > 1: + # optional 0-D tensor, range [-rank(x), rank(x)-1] + axis = tensor_dict[node.inputs[1]] + inputs.append(axis) + + attrs = { + "exclusive": bool(node.attrs.get("exclusive", 0)), + "reverse": bool(node.attrs.get("reverse", 0)) + } + + return [cls.make_tensor_from_onnx_node(node, inputs=inputs, attrs=attrs)] + diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/depth_to_space.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/depth_to_space.py new file mode 100644 index 0000000..9f743f7 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/depth_to_space.py @@ -0,0 +1,57 @@ +import copy + +import tensorflow as tf + +from onnx_tf.common import get_data_format +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("DepthToSpace") +@tf_func(tf.depth_to_space) +class DepthToSpace(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"rename": {"blocksize": "block_size"}} + + @classmethod + def version_1(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_rank = len(x.get_shape()) + storage_format, compute_format = get_data_format(x_rank) + attrs = copy.deepcopy(node.attrs) + attrs["data_format"] = storage_format + return [ + cls.make_tensor_from_onnx_node( + node, attrs=attrs, c_first_cuda_only=True, **kwargs) + ] + + @classmethod + def version_11(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_rank = len(x.get_shape()) + storage_format, compute_format = get_data_format(x_rank) + attrs = copy.deepcopy(node.attrs) + attrs["data_format"] = storage_format + mode = attrs.get("mode", "DCR") + + if mode == "CRD": + # need native computation + bsize = attrs.get("blocksize") + batch, channel, height, width = x.shape + csize = channel // (bsize**2) + + reshape_node = tf.reshape(x, [batch, csize, bsize, bsize, height, width]) + transpose_node = tf.transpose(reshape_node, perm=[0, 1, 4, 2, 5, 3]) + return [ + tf.reshape(transpose_node, + [batch, csize, height * bsize, width * bsize]) + ] + + else: + return [ + cls.make_tensor_from_onnx_node( + node, attrs=attrs, c_first_cuda_only=True, **kwargs) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dequantize_linear.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dequantize_linear.py new file mode 100644 index 0000000..4bf759f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dequantize_linear.py @@ -0,0 +1,40 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("DequantizeLinear") +class DequantizeLinear(BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + if len(node.inputs) == 3: + x = tensor_dict[node.inputs[0]] + x_scale = tensor_dict[node.inputs[1]] + x_zero_point = tensor_dict[node.inputs[2]] + if x_scale.shape != x_zero_point.shape: + raise ValueError("DequantizeLinear x_scale(shape=" + + str(x_scale.shape) + ") and x_zero_point(shape=" + + str(x_zero_point.shape) + + ") must be in the same shape") + if x_zero_point.dtype != x.dtype: + raise ValueError("DequantizeLinear x_zero_point(" + + str(x_zero_point.dtype) + ") and x(" + str(x.dtype) + + ") must be in the same dtype") + + @classmethod + def version_10(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + x = tf.cast(x, tf.float32) + x_scale = tensor_dict[node.inputs[1]] + if len(node.inputs) == 3 and x.dtype != tf.int32: + x_zero_point = tensor_dict[node.inputs[2]] + x_zero_point = tf.cast(x_zero_point, tf.float32) + x = tf.subtract(x, x_zero_point) + + y = tf.multiply(x, x_scale) + + return [y] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/det.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/det.py new file mode 100644 index 0000000..863d8fb --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/det.py @@ -0,0 +1,16 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Det") +@tf_func(tf.linalg.det) +class Det(BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + return [ + cls.make_tensor_from_onnx_node(node, **kwargs) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dilated_pooling.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dilated_pooling.py new file mode 100644 index 0000000..14b3deb --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dilated_pooling.py @@ -0,0 +1,702 @@ +from __future__ import division + +import tensorflow as tf +import numpy as np + +from onnx_tf.common import pooling_helper +from onnx_tf.common.tf_helper import tf_shape +from onnx_tf.common.tf_helper import tf_product + + +class DilatedPooling(object): + """ + This class implements two main methods: + dilated_pool: + calculates a max or average pool over the input + + dilated_maxpool_with_argmax: + calculates a maxpool over the input and returns the + indices/argmax of the selected values + + In addition to the standard features of pooling operations in + Tensorflow, these methods support dilations, ceil mode, SAME_LOWER and + explicit padding. + + Dilations are partly supported in Tensorflow in `tf.nn.pool` and + `tf.nn.dilation2d`. The code will try to use the Tensoflow build-in + functions as much as poosible. + + In cases, not supported by Tensorflow there is a custom algorith of + dilated pooling `_remove_dilations`. + + The idea behind `_remove_dilations` is to transform the input N-D data + into a supported input for the standard tf.nn.pool operation. + This is achieved by calculating N-D indicies for the values which will + be selected from the input when applying the dilations and + then extracting the values using tf.gather_nd. Next step is to execute + `tf.nn.pool` on this new input data with **strides=kernel_shape** and + no dilations. The resulting pool will be the result we are looking for. + + In case of `deilated_maxpool_with_argmax` an additional step is needed + to recalculated the resulting indices back into the original + data indices. It is done with `_calc_orig_argmax` + + Here is a simple example of how the algorithm works: + + kernel_shape = [3] + strides = [2] + dilations = [3] + + Input 1D data: + + x-----x-----x-----x-----x-----x-----x-----x-----x-----x-----x + | * | | ** | * | | ** | * | | ** | | + | 10 | 9 | 30 | 7 | 6 | 15 | 16 | 17 | 18 | 19 | + x-----x-----x-----x-----x-----x-----x-----x-----x-----x-----x + (0) (1) (2) (3) (4) (5) (6) (7) (8) (9) + + where * represents the values selected during the first sliding window + step and ** during the second sliding window step + + the resulting indices will be: + + [0, 3, 6, 2, 5, 8] + | | | | + First Second + step step + + after tf.gather_nd operation we get a new input data with + removed dilations: + + [10, 7, 16, 30, 15, 18] + + and apllying tf.nn.maxpool (or avgpool) with strides = kernel_shape = 3 + will result into: + + [16, 30] + + which is the result of the dilated maxpooling. + + Here is pseudo code of the algorithm with comments: + + FUNCTION _remove_dilations: + /* Calculate N-D index of the values to be selected by the + dilations and strides */ + + /* Do a loop over the input spatial dimensions starting from the + last (most internal) going up to the first dimension + + On every step of the loop calculate the input indices and + "combine" them with the already calculated indices from the + previous dimensions using cartesian product. + */ + LOOP with **dimension** from **dimensions_count** to **0**: + + // Initialize empty gather_nd index + gather_ind = [] + + // Calculate the output size for the current dimension + dim_filter_size = (dim_kernel_size - 1) * dim_dilations + dim_output_size = (((dim_input_size - dim_filter_size) // + dim_strides) + 1) * dim_kernel_size) + + /* For every output index, calculate the corresponding index + into the input data */ + dim_input_indices = range(0, dim_output_size) + dim_input_indices = calculate_input_indicies(dim_input_indices) + + /* combine the calculated indices with the previous dimensions + */ + gather_ind = cartesian_product(dim_input_indices, gather_ind) + END LOOP + + /* For example for 2D input the resulting gather_ind will + look like this: + + [[y1, x1], [y2, x2], ..., [yn, xm]] + + where: + n is the height + m is the width and + [xi, yi] are the 2D indices in the input data + */ + + new_data = tf.gather_nd(input, gather_ind) + + reshape new_data to the correct output shape + + RETURN new_data + + + Before executing _remove_dilations the code will apply paddings to the + input data if needed. Padding is done using tf.pad with -inf values. + Check `_remove_dilations` code for more details explanation of the + implementation + + In case of dilated_maxpool_with_argmax the returned indices from + tf.nn.max_pool_with_argmax will point into our "no dilations" data. + That is why they need to be mapped back to the original input data. + It is done with `_calc_orig_argmax` function which will apply the same + calculations, that are used in _remove_dilations when calculating the + input data indices from output indices (check `_calc_orig_argmax` for + detailed inline comments explaining the calculations) + + """ + + def __init__(self, + input, + kernel_shape, + strides, + dilations, + padding="VALID", + ceil_mode=False, + count_include_pad=False, + pooling_type="MAX", + p=2): + self.input = tf.convert_to_tensor(input) + + self.kernel_shape = kernel_shape + self.strides = strides + self.dilations = dilations + self.padding = padding + self.is_explicit_padding = type(padding) is list + self.ceil_mode = ceil_mode + self.count_include_pad = count_include_pad + self.pooling_type = pooling_type.upper() + self.p = p + + self.is_known_shape = self.input.shape.is_fully_defined() + self.spatial_size = len(kernel_shape) + self.input_rank = self.spatial_size + 2 + + # if the rank is not defined, set it to the calculated input_rank + # rank should be known for ops like tf.gather_nd + if not input.shape.rank: + input.set_shape([None] * self.input_rank) + self.orig_input_shape = tf_shape(input) + self.input_shape = self.orig_input_shape + + if pooling_type.startswith("MAX"): + self.padding_constant = input.dtype.min + else: + self.padding_constant = 0 + + def _calc_input_ind(self, output_ind, kernel, dilation, stride): + """ + This function maps index from the output of _remove_dilations + to index from the original input along single axis. It calculates + the index inside the input data from the index of the output. + It is used to generate the correct indexes of the values to be + extracted by gather_nd. + + Args: + output_ind: vector with indices from the output to be mapped + kernel: kernel size along the axis + dilation: dilations along the axis + stride: strides along the axis + Return: + input_ind: calculated indices + + The formula is: + input_ind = (output_ind // kernel) * stride + + (output_ind % kernel) * dilation + + Example: + If we have following 2D input to _remove_dilations: + [[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11], + [ 12, 13, 14, 15]] + and Kernel = [2, 2], Dilations: [2, 2], Strides: [1, 1] + + the output of _remove_dilations will have shape [4, 4] and + _calc_input_ind will be called twice for the two axis 0 (along + height) and axis 1 (along width) with + + output_ind = [0, 1, 2, 3] + + which will result in: + + input_ind = [0, 2, 1, 3] + """ + return (output_ind // kernel) * (stride - kernel * dilation) + \ + output_ind * dilation + + def _calc_orig_argmax(self, ind): + """ + Map result argxmax to the original input indices + + Maps indices generated by maxpool_with_argmax on top of the + dilation reduced input to the orignal input indices + """ + + in_width = self.orig_input_shape[2] + num_channels = self.orig_input_shape[3] + output_width = self.output_shape[2] + + # mod_floor op is not implemented on GPU + # implement it using: a % b = a - (a // b) * b + + # inRow = (ind // num_channels) // output_width + # inCol = (ind // num_channels) % output_width + # ind_channel = ind % num_channels + + ind_nhw = ind // num_channels + + inRow = ind_nhw // output_width + inCol = ind_nhw - (ind_nhw // output_width) * output_width + + ind_channel = ind - ind_nhw * num_channels + + row = self._calc_input_ind(inRow, self.kernel_shape[0], self.dilations[0], + self.strides[0]) - self.pads[0] + col = self._calc_input_ind(inCol, self.kernel_shape[1], self.dilations[1], + self.strides[1]) - self.pads[2] + + new_ind = num_channels * (row * in_width + col) + ind_channel + return new_ind + + def _remove_dilations(self): + """ + This method removes the dilations by extracting the values from + the input for every sliding window according to the dilations, + strides and kernel size and generates output that can be used by + pooling operations with strides = kernel_shape to accomplish + dilated pooling + + Example: + Input: [[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11], + [ 12, 13, 14, 15]] + + Kernel: [2, 2] + Dilations: [2, 2] + Strides: [1, 1] + + Will return: + [[ 0, 2, 1, 3], + [ 8, 10, 9, 11], + [ 4, 6, 5, 7], + [ 12, 14, 13, 15]] + + After max_pool2d with kernel_shape = strides = [2, 2] + the result is: + [[ 10, 11], + [ 14, 15]] + """ + + input_shape = tf_shape(self.input) + in_spatial_shape = input_shape[1:self.spatial_size + 1] + + channels_count = input_shape[self.spatial_size + 1] + # Initialize gather_ind with the range of channels + # e.g. [0 1] + gather_ind = tf.range(channels_count, dtype=tf.int64) + # convert the vector to column vector + # in the following logic we use column vectors + gather_ind = tf.expand_dims(gather_ind, 1) + + # initilize the output_shape with zeros + # self.output_shape will contain the shape of the + # output tensor after the loop below is executed + self.output_shape = [0] * (self.spatial_size + 2) + self.output_shape[0] = input_shape[0] + """ + Loop over the input spatial dimensions starting from the + last (most internal) going up to the first dimension + + On every step of the loop calculate the output indices and + map them to the input indices using `_calc_input_ind`, + then "combine" with the already calculated indices from the + previous dimensions using cartesian product. + + For the following example input: + + Input: [[ 0, 1, 2, 3], + [ 4, 5, 6, 7], + [ 8, 9, 10, 11], + [ 12, 13, 14, 15]] + + Kernel: [2, 2] + Dilations: [2, 2] + Strides: [1, 1] + + these are the steps that will be executed: + + 1. Initilize gather_ind = [[0]] # we have only 1 channel + + 2. Loop step 0 (axis 1): + filter_size = 3 + output_size = 4 + dim_ind = [[0] + [2] + [1] + [3]] + + gather_ind = [[0 0] + [2 0] + [1 0] + [3 0]] + + 3. Loop step 1 (axis 0): + filter_size = 3 + output_size = 4 + dim_ind = [[0] + [2] + [1] + [3]] + + gather_ind = [[0 0 0] + [0 2 0] + [0 1 0] + [0 3 0] + [2 0 0] + [2 2 0] + [2 1 0] + [2 3 0] + [1 0 0] + [1 2 0] + [1 1 0] + [1 3 0] + [3 0 0] + [3 2 0] + [3 1 0] + [3 3 0]] + + These are the indices used for gather_nd operation to collect + the values from the input data. + """ + + for dim in range(self.spatial_size - 1, -1, -1): + filter_size = (self.kernel_shape[dim] - 1) * \ + self.dilations[dim] + 1 + output_size = (( + (in_spatial_shape[dim] - filter_size) // self.strides[dim]) + 1 + ) * self.kernel_shape[dim] + self.output_shape[dim + 1] = output_size + + # initialize the output dimension index with the range of the + # dimension output size (e.g. 4): [0, 1, 2, 3] + dim_ind = tf.range(output_size) + + # calculate the matching indices in the input data + # [0, 1, 2, 3] will calculate to [0, 2, 1, 3] + # from the above example + dim_ind = self._calc_input_ind(dim_ind, self.kernel_shape[dim], + self.dilations[dim], self.strides[dim]) + # convert to column vector + dim_ind = tf.expand_dims(dim_ind, 1) + + # "combine" current dimension indices with the previous dimensions + # using cartesian product + gather_ind = tf_product(dim_ind, gather_ind) + + # The result from the above loop for 2D data will be: + # [[y1, x1, c], [y2, x2, c], ..., [yn, xm, c]] where n is the height, + # m is the width and c is the channel number. + + # set the channels count in the output_shape + self.output_shape[self.spatial_size + 1] = channels_count + + # expand the dimensions to match the input dimensions + 1 + for x in range(self.spatial_size): + gather_ind = tf.expand_dims(gather_ind, 0) + # dublicate the indices for every batch + gather_ind = tf.tile(gather_ind, + [input_shape[0]] + [1] * (self.spatial_size + 1)) + + # extract the selected values from the input + output = tf.gather_nd(self.input, gather_ind, batch_dims=1) + # reshape the output to the correct shape calculated earlier + output = tf.reshape(output, self.output_shape) + + return output + + def _calc_pads_same(self, in_spatial_shape): + """ + Calculate SAME_* paddings. + """ + + pad_ops = pooling_helper.pad_numpy_ops if self.is_known_shape else \ + pooling_helper.pad_tf_ops + + return pooling_helper.calc_pads_same(in_spatial_shape, self.kernel_shape, + self.strides, self.dilations, + self.padding, pad_ops, 2) + + def _calc_pads_explicit(self): + """ + Calculate explicit padding + """ + assert type(self.padding) is list + + pads = [] + for i in range(self.spatial_size): + pads += [self.padding[i], self.padding[i + self.spatial_size]] + return pads + + def _calc_pads_ceil_mode(self, in_spatial_shape): + """ + Calculate padding in ceil_mode + """ + + pads = [] + for i in range(self.spatial_size): + dim_size = in_spatial_shape[i] + filter_size = (self.kernel_shape[i] - 1) * self.dilations[i] + 1 + out_size = (dim_size - filter_size) / self.strides[i] + if self.is_known_shape: + pad_size = (np.ceil(out_size) - np.floor(out_size)).astype(np.int64) + else: + pad_size = tf.cast( + tf.math.ceil(out_size) - tf.math.floor(out_size), tf.int64) + + pads += [0, pad_size * self.strides[i]] + return pads + + def _calc_pads(self, in_spatial_shape): + if self.is_known_shape: + pads = np.zeros([self.spatial_size * 2], np.int64) + else: + pads = tf.zeros([self.spatial_size * 2], tf.int64) + + # check for explicit padding + if type(self.padding) is list: + pads += self._calc_pads_explicit() + elif self.padding.lower().startswith("same"): + pads += self._calc_pads_same(in_spatial_shape) + + # when padding is set to SAME, ceil_mode will not do anything + # because output sizes will be multiple of the strides + if self.ceil_mode and (type(self.padding) is list or + not self.padding.lower().startswith("same")): + new_spatial_shape = [ + in_spatial_shape[i] + pads[i * 2] + pads[i * 2 + 1] + for i in range(self.spatial_size) + ] + pads += self._calc_pads_ceil_mode(new_spatial_shape) + return pads + + def _pad_input(self): + """ + Pad the input according to the parameters + """ + # check if we need to do any padding at all + if not self.ceil_mode and ((type(self.padding) is list and + self.padding == [0] * self.spatial_size * 2) or + self.padding == "VALID"): + self.pads = np.array([0] * self.spatial_size * 2) + return (self.input, self.pads) + + in_spatial_shape = self.input_shape[1:self.spatial_size + 1] + pads = self._calc_pads(in_spatial_shape) + + if self.is_known_shape and np.count_nonzero(pads) == 0: + self.pads = pads + return (self.input, pads) + + tf_paddings = [[0, 0]] + for i in range(self.spatial_size): + tf_paddings += [[pads[i * 2], pads[i * 2 + 1]]] + tf_paddings += [[0, 0]] + + self.input = tf.pad( + self.input, + tf_paddings, + mode='CONSTANT', + constant_values=self.padding_constant) + # update input shape and pads values + self.input_shape = tf_shape(self.input) + self.pads = pads + + def _calc_argmax_without_padding(self, ind): + """ + Calculate the original indices as they would be without padding + """ + in_width = self.orig_input_shape[2] + padded_width = self.input_shape[2] + num_channels = self.input_shape[3] + + # mod_floor op is not implemented on GPU + # implement it using: a % b = a - (a // b) * b + + # ind_nhw = ind // num_channels + # ind_channel = ind % num_channels + + ind_nhw = ind // num_channels + ind_channel = ind - ind_nhw * num_channels + + new_ind = (ind_nhw // padded_width) * (self.pads[2] + self.pads[3]) + new_ind = ind_nhw - new_ind - self.pads[0] * in_width - self.pads[2] + new_ind = num_channels * new_ind + ind_channel + return new_ind + + def dilated_maxpool_with_argmax(self, force_custom_impl=False): + """ + Do a dilated maxpool and return indices/argmax + """ + # Tensorflow does not support maxpool_with_argmax on + # spatial_size != 2 + assert self.spatial_size == 2 + + if list(self.dilations) != [1] * self.spatial_size or \ + force_custom_impl: + # pad the input + self._pad_input() + + new_input = self._remove_dilations() + kernel_shape = [1] + list(self.kernel_shape) + [1] + pooled, new_ind = tf.nn.max_pool_with_argmax( + new_input, ksize=kernel_shape, strides=kernel_shape, padding="VALID") + new_ind = self._calc_orig_argmax(new_ind) + else: + self.pads = np.array([0] * self.spatial_size * 2) + if type(self.padding) is list or \ + self.padding.lower() == "same_lower": + # pad the input + self._pad_input() + + padding_ = "VALID" + elif self.padding.lower() == "same_upper": + padding_ = "SAME" + else: + padding_ = self.padding + + strides = [1] + list(self.strides) + [1] + kernel_shape = [1] + list(self.kernel_shape) + [1] + pooled, new_ind = tf.nn.max_pool_with_argmax( + self.input, ksize=kernel_shape, strides=strides, padding=padding_) + # if there was padding, recalculate the returned index + # to exclude the padding + if np.count_nonzero(self.pads) != 0: + new_ind = self._calc_argmax_without_padding(new_ind) + + return (pooled, new_ind) + + def _lp_pool(self, input, ksize, strides, padding): + window_size = np.prod(ksize) + + input = tf.math.pow(tf.math.abs(input), self.p) * window_size + pooled = tf.nn.avg_pool_v2(input, ksize=ksize, strides=strides, + padding=padding) + pooled = tf.math.pow(pooled, 1.0 / self.p) + + return pooled + + def dilated_pool(self, force_custom_impl=False): + """ + Does N-D dilated max/avg pooling. Pads the input if explicit or + SAME_* padding is provided or ceil_mode is True + """ + + assert self.is_supported() + + if self.is_explicit_padding or self.padding.lower() == "same_lower" \ + or (self.padding.lower() == "same_upper" and + self.count_include_pad) or self.pooling_type.upper() == "LP": + # pad the input + self._pad_input() + + padding_ = "VALID" + elif self.padding.lower() == "same_upper": + padding_ = "SAME" + else: + padding_ = self.padding + + # if maxpool op with dialtions != 1 and spatial_size == 2 + # we can use tf.nn.dilation2d directly + if self.spatial_size == 2 and self.pooling_type.startswith("MAX") \ + and self.dilations != [1] * self.spatial_size and \ + not force_custom_impl: + strides = [1] + list(self.strides) + [1] + dilations = [1] + list(self.dilations) + [1] + + filter = tf.zeros( + [self.kernel_shape[0], self.kernel_shape[1], self.input_shape[3]], + self.input.dtype) + pooled = tf.nn.dilation2d( + input=self.input, + filters=filter, + strides=strides, + dilations=dilations, + padding=padding_) + # if spatial_size < 4 and strides == 1 or dilation == 1 use tf.nn.pool + elif self.spatial_size < 4 and (self.strides == [1] * self.spatial_size or + self.dilations == [1] * self.spatial_size) and \ + not force_custom_impl: + # if strides == 1 and not LpPool use tf.nn.pool directly + if self.strides == [1] * self.spatial_size and self.pooling_type != "LP": + pooled = tf.nn.pool( + self.input, + window_shape=self.kernel_shape, + dilations=self.dilations, + strides=self.strides, + padding=padding_, + pooling_type=self.pooling_type) + else: + # othwerwise check the pooling_type and use the correct op + if self.pooling_type.startswith("MAX"): + op = tf.nn.max_pool_v2 + elif self.pooling_type == "AVG": + op = tf.nn.avg_pool_v2 + elif self.pooling_type == "LP": + op = self._lp_pool + else: + raise ValueError("%d-D %s pooling is not supported." % + (self.spatial_size, self.pooling_type)) + pooled = op(self.input, ksize=self.kernel_shape, strides=self.strides, + padding=padding_) + # in any other case we use custom implementation _remove_dilations + # to reduce atrous/dilated pooling into regular pooling and selecting + # only the values of the input that should have been selected by + # applying the strides and dilations. Then use tf.nn.pool with + # strides = kernel_shape and no dilations + else: + if padding_ == "SAME": + # pad the input + self._pad_input() + input_ = self._remove_dilations() + if self.pooling_type=="LP": + pooled = self._lp_pool( + input_, + ksize=self.kernel_shape, + strides=self.kernel_shape, + padding="VALID") + + else: + pooled = tf.nn.pool( + input_, + window_shape=self.kernel_shape, + strides=self.kernel_shape, + padding="VALID", + pooling_type=self.pooling_type) + return pooled + + def is_supported(self): + """ + Function to check if the current set of arguments are + supported for average pool + """ + # check for maxpool + if self.pooling_type.startswith("MAX") or \ + self.pooling_type=="LP": + return True + else: + # if count_include_pad is true it is fully supported + if self.count_include_pad: + return True + # ceil mode is not supported + elif self.ceil_mode: + return False + # explicit padding with padding values set to 0 is supported + elif (self.is_explicit_padding and + self.padding == [0] * self.spatial_size * 2): + return True + # "valid" and "same_upper" auto padding is supported + elif (not self.is_explicit_padding and + self.padding.lower() in ["valid", "same_upper"]): + return True + # any other case is not supported + else: + return False diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/div.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/div.py new file mode 100644 index 0000000..f4228a7 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/div.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ArithmeticMixin + + +@onnx_op("Div") +@tf_func(tf.div) +class Div(ArithmeticMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dropout.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dropout.py new file mode 100644 index 0000000..80184bb --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dropout.py @@ -0,0 +1,37 @@ +import copy + +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Dropout") +@tf_func(tf.nn.dropout) +class Dropout(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + attrs = copy.deepcopy(node.attrs) + if cls.SINCE_VERSION >= 7 or attrs.pop("is_test", 0) == 1: + return [x] + attrs["keep_prob"] = 1 - attrs.pop("ratio", 0.5) + return [cls.make_tensor_from_onnx_node(node, attrs=attrs, **kwargs)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_10(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dynamic_quantize_linear.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dynamic_quantize_linear.py new file mode 100644 index 0000000..d0b799a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/dynamic_quantize_linear.py @@ -0,0 +1,39 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("DynamicQuantizeLinear") +class DynamicQuantizeLinear(BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + # A Function to fuse calculation for Scale, Zero Point and FP32->8Bit convertion of FP32 Input data. + + # Scale is calculated as: + # y_scale = (max(x) - min(x))/(qmax - qmin) + # Zero point is calculated as: + # intermediate_zero_point = qmin - min(x)/y_scale + # y_zero_point = cast(round(saturate(intermediate_zero_point))) + # Data quantization formula is: + # y = saturate(round(x / y_scale) + y_zero_point) + # Only uint8 is supported, so saturation range is [0, 255] + + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + dtype = tf.uint8 + qmin = dtype.min + qmax = dtype.max + min_x = tf.math.minimum(0., tf.math.reduce_min(x)) + max_x = tf.math.maximum(0., tf.math.reduce_max(x)) + y_scale = (max_x - min_x) / (qmax - qmin) + intermediate_zero_point = qmin - (min_x / y_scale) + y_zero_point = tf.clip_by_value(tf.round(intermediate_zero_point), qmin, + qmax) + y = tf.cast( + tf.clip_by_value((tf.round(x / y_scale) + y_zero_point), qmin, qmax), + dtype) + + return [y, y_scale, tf.cast(y_zero_point, dtype)] + diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/elu.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/elu.py new file mode 100644 index 0000000..b375e12 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/elu.py @@ -0,0 +1,30 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Elu") +@tf_func(tf.nn.elu) +class Elu(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + alpha = node.attrs.get("alpha", 1.0) + if alpha != 1.0: + return [ + tf.cast(x < 0.0, tf.float32) * alpha * (tf.exp(x) - 1.0) + + tf.cast(x >= 0.0, tf.float32) * x + ] + else: + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/equal.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/equal.py new file mode 100644 index 0000000..f30a978 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/equal.py @@ -0,0 +1,41 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from .control_flow_mixin import ComparisonMixin + + +@onnx_op("Equal") +@tf_func(tf.equal) +@partial_support(True) +@ps_description("Equal inputs in uint16/uint32/uint64 " + + "are not supported in Tensorflow.") +class Equal(ComparisonMixin, BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + supported_dtype = [ + tf.bfloat16, tf.half, tf.float32, tf.float64, tf.uint8, + tf.int8, tf.int16, tf.int32, tf.int64, tf.complex64, + tf.quint8, tf.qint8, tf.qint32, tf.string, tf.bool, + tf.complex128 + ] + x = kwargs["tensor_dict"][node.inputs[0]] + if x.dtype not in supported_dtype: + exception.OP_UNSUPPORTED_EXCEPT( + "Equal inputs in " + str(x.dtype) + " which", "Tensorflow") + + @classmethod + def version_1(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_11(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/erf.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/erf.py new file mode 100644 index 0000000..150ed35 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/erf.py @@ -0,0 +1,14 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Erf") +@tf_func(tf.erf) +class Erf(BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/exp.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/exp.py new file mode 100644 index 0000000..50ca20d --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/exp.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Exp") +@tf_func(tf.exp) +class Exp(BasicMathMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/expand.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/expand.py new file mode 100644 index 0000000..ddfcd5a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/expand.py @@ -0,0 +1,22 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("Expand") +class Expand(BackendHandler): + + @classmethod + def version_8(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x, shape = tensor_dict[node.inputs[0]], tensor_dict[node.inputs[1]] + + # tf.math.multiply does not support bool therefore use int8 + if x.dtype is tf.bool: + ones = tf.ones(shape, dtype=tf.int8) + r = tf.cast(x, tf.int8) * ones + return [tf.cast(r, tf.bool)] + else: + ones = tf.ones(shape, dtype=x.dtype) + return [x * ones] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/eye_like.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/eye_like.py new file mode 100644 index 0000000..d49274b --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/eye_like.py @@ -0,0 +1,41 @@ +import copy +import numpy as np +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("EyeLike") +class EyeLike(BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + + attrs = copy.deepcopy(node.attrs) + inp = kwargs["tensor_dict"][node.inputs[0]] + dtype = attrs.pop("dtype", inp.dtype) + offset = attrs.pop("k", 0) + shape = inp.shape.as_list() + + # calculate upper and lower bound of max eye shape + max_eye_shape_ub = shape[1] if offset > 0 else shape[0] + max_eye_shape_lb = shape[0] if offset > 0 else shape[1] + offset = max_eye_shape_ub * np.sign(offset) if abs( + offset) > max_eye_shape_ub else offset + abs_offset = abs(offset) + eye_shape = min(max_eye_shape_ub - abs_offset, max_eye_shape_lb) + tensor = tf.eye(eye_shape, num_columns=eye_shape, dtype=dtype) + if offset > 0: + tb_paddings = [0, shape[0] - eye_shape] + lr_paddings = [offset, shape[1] - offset - eye_shape] + else: + tb_paddings = [abs_offset, shape[0] - abs_offset - eye_shape] + lr_paddings = [0, shape[1] - eye_shape] + paddings = tf.constant([tb_paddings, lr_paddings], dtype=tf.int32) + attrs["paddings"] = paddings + return [ + cls.make_tensor_from_onnx_node( + node, tf_func=tf.pad, inputs=[tensor], attrs=attrs, **kwargs) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/flatten.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/flatten.py new file mode 100644 index 0000000..70f1669 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/flatten.py @@ -0,0 +1,39 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Flatten") +@tf_func(tf.layers.flatten) +class Flatten(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + shape = tf.shape(x) + x_rank = len(x.shape) + axis = node.attrs.get("axis", 1) + + if axis == 1 and x_rank > 1: + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + if axis == 0: + cal_shape = (1, -1) + else: + cal_shape = (tf.reduce_prod(shape[0:axis]), + tf.reduce_prod(shape[axis:tf.size(shape)])) + return [tf.reshape(x, cal_shape)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_9(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/floor.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/floor.py new file mode 100644 index 0000000..8aa7dff --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/floor.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Floor") +@tf_func(tf.floor) +class Floor(BasicMathMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather.py new file mode 100644 index 0000000..c049d8e --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather.py @@ -0,0 +1,29 @@ +import copy +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .gather_and_scatter_mixin import GatherAndScatterMixin + + +@onnx_op("Gather") +@tf_func(tf.gather) +class Gather(GatherAndScatterMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_11(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + indices = kwargs["tensor_dict"][node.inputs[1]] + attrs = copy.deepcopy(node.attrs) + axis = attrs.get("axis", 0) + result = cls.chk_idx_out_of_bounds_along_axis(x, axis, indices) + msg = 'Gather indices are out of bounds, please double check the indices and retry.' + with tf.control_dependencies([tf.compat.v1.assert_equal(result, True, message=msg)]): + indices = cls.process_neg_idx_along_axis(x, axis, indices) + attrs['axis'] = axis + return [cls.make_tensor_from_onnx_node(node, attrs=attrs, inputs=[x, indices], **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_and_scatter_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_and_scatter_mixin.py new file mode 100644 index 0000000..92bbaf1 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_and_scatter_mixin.py @@ -0,0 +1,79 @@ +import tensorflow as tf +try: + from tensorflow.math import floormod as tf_floormod +except ImportError: + from tensorflow import floormod as tf_floormod + +from onnx_tf.common.tf_helper import tf_shape + +class GatherAndScatterMixin(object): + + @classmethod + def chk_idx_out_of_bounds(cls, data, indices): + """ Check indices out of bounds for ScatterND and GatherND + In Tensorflow GPU version, if an out of bound index is found, + a 0 is stored in the corresponding output value for GatherND; + and the index is ignored for ScatterND/TensorScatterNDUpdate. + But ONNX spec state that it is an error if any index values + are out of bounds. Therefore the converter need to run this + function to verify all the indices are in bounds before send + it to Tensoflow. If out of bound is detected then the caller + of this function need to throw InvalidArgumentError exception. + """ + data_shape = tf_shape(data) + indices_shape = tf_shape(indices) + + def _chk_idx_out_of_bounds(i, result): + indices_i = tf.transpose(indices)[i] + limit_i = tf.cast(data_shape, indices.dtype)[i] + cond1 = tf.greater_equal(indices_i, tf.negative(limit_i)) + cond2 = tf.less(indices_i, limit_i) + result = tf.reduce_all(tf.logical_and(cond1, cond2)) + return i + 1, result + + _, result = tf.while_loop( + lambda i, result: tf.logical_and(tf.less(i, indices_shape[-1]), result), + _chk_idx_out_of_bounds, [0, True]) + return result + + @classmethod + def chk_idx_out_of_bounds_along_axis(cls, data, axis, indices): + """ Check indices out of bounds for ScatterElement + In Tensorflow GPU version, if an out of bound index is found, + the index is ignored for ScatterND/TensorScatterNDUpdate. + But ONNX spec state that it is an error if any index values + are out of bounds. Therefore the converter need to run this + function to verify all the indices are in bounds along the + axis before send it to Tensoflow. If out of bound is detected + then the caller of this function need to throw + InvalidArgumentError exception. + """ + data_shape = tf.cast(tf_shape(data), indices.dtype) + limit = data_shape[axis] + cond1 = tf.greater_equal(indices, tf.negative(limit)) + cond2 = tf.less(indices, limit) + return tf.logical_and(cond1, cond2) + + @classmethod + def process_neg_idx(cls, data, indices): + """ Convert all the negative indices to positive + GatherND and ScatterND/TensorScatterNDUpdate in Tensorflow + doesn't support negative indices. Therefore need to run this + function to convert all the negative indices to positive before + send it to Tensorflow. + """ + data_shape = tf_shape(data) + indices_shape = tf_shape(indices) + max_i = tf.cast(data_shape[:indices_shape[-1]], indices.dtype) + return tf_floormod(tf.add(indices, max_i), max_i) + + @classmethod + def process_neg_idx_along_axis(cls, data, axis, indices): + """ Convert all the negative indices to positive + ScatterND/TensorScatterNDUpdate in Tensorflow doesn't support + negative indices. Therefore need to run this function to convert + all the negative indices to positive before send it to Tensorflow. + """ + data_shape = tf_shape(data) + max_i = tf.cast(data_shape[axis], indices.dtype) + return tf_floormod(tf.add(indices, max_i), max_i) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_elements.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_elements.py new file mode 100644 index 0000000..d030858 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_elements.py @@ -0,0 +1,58 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .gather_and_scatter_mixin import GatherAndScatterMixin + + +@onnx_op("GatherElements") +class GatherElements(GatherAndScatterMixin, BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + # GatherElements takes two inputs data and indices of the same rank r >= 1 and an optional attribute axis that identifies + # an axis of data (by default, the outer-most axis, that is axis 0). It is an indexing operation that produces its output by + # indexing into the input data tensor at index positions determined by elements of the indices tensor. Its output shape is the + # same as the shape of indices and consists of one value (gathered from the data) for each element in indices. + + axis = node.attrs.get("axis", 0) + data = kwargs["tensor_dict"][node.inputs[0]] + indices = kwargs["tensor_dict"][node.inputs[1]] + + # poocess negative axis + axis = axis if axis >= 0 else tf.add(tf.rank(data), axis) + + # check are there any indices are out of bounds + result = cls.chk_idx_out_of_bounds_along_axis(data, axis, indices) + msg = 'GatherElements indices are out of bounds,'\ + ' please double check the indices and retry.' + with tf.control_dependencies( + [tf.compat.v1.assert_equal(result, True, message=msg)]): + # process negative indices + indices = cls.process_neg_idx_along_axis(data, axis, indices) + + # adapted from reference implementation in onnx/onnx/backend/test/case/node/gatherelements.py + if axis == 0: + axis_perm = tf.range(tf.rank(data)) + data_swaped = data + index_swaped = indices + else: + axis_perm = tf.tensor_scatter_nd_update(tf.range(tf.rank(data)), + tf.constant([[0], [axis]]), + tf.constant([axis, 0])) + data_swaped = tf.transpose(data, perm=axis_perm) + index_swaped = tf.transpose(indices, perm=axis_perm) + + idx_tensors_per_axis = tf.meshgrid(*list( + map(lambda x: tf.range(x, dtype=index_swaped.dtype), + index_swaped.shape.as_list())), + indexing='ij') + idx_tensors_per_axis[0] = index_swaped + dim_expanded_idx_tensors_per_axis = list( + map(lambda x: tf.expand_dims(x, axis=-1), idx_tensors_per_axis)) + index_expanded = tf.concat(dim_expanded_idx_tensors_per_axis, axis=-1) + + gathered = tf.gather_nd(data_swaped, index_expanded) + y = tf.transpose(gathered, perm=axis_perm) + + return [y] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_nd.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_nd.py new file mode 100644 index 0000000..3a9d86e --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gather_nd.py @@ -0,0 +1,20 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .gather_and_scatter_mixin import GatherAndScatterMixin + + +@onnx_op("GatherND") +class GatherND(GatherAndScatterMixin, BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + data = kwargs["tensor_dict"][node.inputs[0]] + indices = kwargs["tensor_dict"][node.inputs[1]] + + result = cls.chk_idx_out_of_bounds(data, indices) + msg = 'GatherND indices are out of bounds, please double check the indices and retry.' + with tf.control_dependencies([tf.compat.v1.assert_equal(result, True, message=msg)]): + indices = cls.process_neg_idx(data, indices) + return [tf.gather_nd(data, indices)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gemm.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gemm.py new file mode 100644 index 0000000..72983c4 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gemm.py @@ -0,0 +1,48 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("Gemm") +class Gemm(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + x = tf.layers.flatten(x) + y = tensor_dict[node.inputs[1]] + + if len(node.inputs) > 2: + z = tensor_dict[node.inputs[2]] + else: + z = 0 + + if node.attrs.get("transA", 0): + x = tf.transpose(x) + if node.attrs.get("transB", 0): + y = tf.transpose(y) + alpha = node.attrs.get("alpha", 1.0) + beta = node.attrs.get("beta", 1.0) + return [alpha * tf.matmul(x, y) + beta * z] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_9(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_average_pool.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_average_pool.py new file mode 100644 index 0000000..5812bb2 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_average_pool.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("GlobalAveragePool") +class GlobalAveragePool(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + dims = tf.range(tf.rank(x)) + _, dim_window = tf.split(dims, [2, tf.size(dims) - 2]) + return [tf.reduce_mean(x, axis=dim_window, keep_dims=True)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_lp_pool.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_lp_pool.py new file mode 100644 index 0000000..2b2b374 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_lp_pool.py @@ -0,0 +1,26 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("GlobalLpPool") +class GlobalLpPool(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + p = node.attrs.get("p", 2.) + dims = list(range(len(x.shape))) + dim_window = dims[2:] + if len(dim_window) > 1 and p == 2: + p = "euclidean" + return [tf.norm(x, ord=p, axis=dim_window, keepdims=True)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_2(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_max_pool.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_max_pool.py new file mode 100644 index 0000000..3a3dfb3 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/global_max_pool.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("GlobalMaxPool") +class GlobalMaxPool(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + dims = tf.range(tf.rank(x)) + _, dim_window = tf.split(dims, [2, tf.size(dims) - 2]) + return [tf.reduce_max(x, axis=dim_window, keep_dims=True)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/greater.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/greater.py new file mode 100644 index 0000000..32527f8 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/greater.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .control_flow_mixin import ComparisonMixin + + +@onnx_op("Greater") +@tf_func(tf.greater) +class Greater(ComparisonMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_9(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gru.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gru.py new file mode 100644 index 0000000..c0e6cf5 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/gru.py @@ -0,0 +1,202 @@ +from functools import partial + +import tensorflow as tf + +from onnx_tf.common import get_unique_suffix +from onnx_tf.common import exception +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from .rnn_mixin import RNNMixin + + +@onnx_op("GRU") +@partial_support(True) +@ps_description("GRU with clip or GRU with linear_before_reset, or " + + "GRU not using sigmoid for z and r, or " + + "GRU using Elu as the activation function " + + "with alpha != 1, or " + + "GRU using HardSigmoid as the activation function " + + "with alpha != 0.2 or beta != 0.5 " + + "are not supported in TensorFlow.") +class GRU(RNNMixin, BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + direction = node.attrs.get("direction", "forward") + num_directions = 2 if direction == "bidirectional" else 1 + if "clip" in node.attrs: + exception.OP_UNSUPPORTED_EXCEPT("GRU with clip", "Tensorflow") + if node.attrs.get("linear_before_reset", 0): + exception.OP_UNSUPPORTED_EXCEPT("GRU with linear_before_reset", + "Tensorflow") + if "activations" in node.attrs: + activations = list(map(lambda x: x.lower(), node.attrs["activations"])) + if activations[0] != "sigmoid": + exception.OP_UNSUPPORTED_EXCEPT("GRU without sigmoid for `z` and `r`", + "Tensorflow") + if num_directions == 2: + if activations[2] != "sigmoid": + exception.OP_UNSUPPORTED_EXCEPT("GRU without sigmoid for `z` and `r`", + "Tensorflow") + + @classmethod + def _custom_getter(cls, + getter, + name, + node=None, + tensor_dict=None, + is_bidirectional=None, + *args, + **kwargs): + names = name.split("/") + if is_bidirectional: + if "fw" in names: + index = 0 + elif "bw" in names: + index = 1 + else: + raise RuntimeError("Can not get {} for bidirectional. " + "Either fw and bw is not in name scope.".format( + names[-1])) + if names[-1] == "kernel": + # onnx W[zrh], R[zrh] + if is_bidirectional: + w = tf.split(tensor_dict[node.inputs[1]], 2)[index] + r = tf.split(tensor_dict[node.inputs[2]], 2)[index] + else: + w = tensor_dict[node.inputs[1]] + r = tensor_dict[node.inputs[2]] + w_z, w_r, w_h = tf.split(tf.squeeze(w), 3) + r_z, r_r, r_h = tf.split(tf.squeeze(r), 3) + if names[-2] == "gates": + new_w = tf.transpose(tf.concat([w_r, w_z], 0)) + new_r = tf.transpose(tf.concat([r_r, r_z], 0)) + elif names[-2] == "candidate": + new_w = tf.transpose(w_h) + new_r = tf.transpose(r_h) + kernel = tf.concat([new_w, new_r], 0) + return kernel + if names[-1] == "bias": + if len(node.inputs) >= 4: + # onnx Wb[zrh], Rb[zrh] + if is_bidirectional: + b = tf.split(tensor_dict[node.inputs[3]], 2)[index] + else: + b = tensor_dict[node.inputs[3]] + w_b, r_b = tf.split(tf.squeeze(b), 2) + w_b_z, w_b_r, w_b_h = tf.split(w_b, 3) + r_b_z, r_b_r, r_b_h = tf.split(r_b, 3) + if names[-2] == "gates": + w_b = tf.transpose(tf.concat([w_b_r, w_b_z], 0)) + r_b = tf.transpose(tf.concat([r_b_r, r_b_z], 0)) + elif names[-2] == "candidate": + w_b = tf.transpose(w_b_h) + r_b = tf.transpose(r_b_h) + return tf.add(w_b, r_b) + return getter(name, *args, **kwargs) + return getter(name, *args, **kwargs) + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + input_shape = x.get_shape().as_list() + input_size = len(node.inputs) + hidden_size = node.attrs["hidden_size"] + direction = node.attrs.get("direction", "forward") + num_directions = 2 if direction == "bidirectional" else 1 + + # removed from version 7, default is 0 + output_sequence = node.attrs.get("output_sequence", 0) + + # TODO(fumihwh): check if prev node is one of RNN + # process input if it comes from other previous cell + # which has shape [seq_length, num_directions, batch_size, hidden_size] + if len(input_shape) == 4 and input_shape[1] == 1: + x = tf.squeeze(x) + + sequence_length = None + if input_size >= 5 and node.inputs[4] in tensor_dict: + sequence_length = tensor_dict[node.inputs[4]] + + cell_kwargs = {} + + tf_activations = [tf.nn.tanh] + if "activations" in node.attrs: + activations = list(map(lambda x: x.lower(), node.attrs["activations"])) + activation_alpha = node.attrs.get("activation_alpha", [None] * 4) + activation_beta = node.attrs.get("activation_beta", [None] * 4) + tf_activations = [ + cls.rnn_get_activation(activations[1], activation_alpha[1], + activation_beta[1]) + ] + if num_directions == 2: + tf_activations.append( + cls.rnn_get_activation(activations[3], activation_alpha[3], + activation_beta[3])) + + # TODO(fumihwh): check if reverse and bidirectional works + with tf.variable_scope( + "GRU_" + get_unique_suffix(), + custom_getter=partial( + cls._custom_getter, + node=node, + tensor_dict=tensor_dict, + is_bidirectional=num_directions == 2)): + + cell_kwargs["num_units"] = hidden_size + if input_size < 4 or node.inputs[3] not in tensor_dict: + cell_kwargs["bias_initializer"] = tf.zeros_initializer + initial_state = None + initial_state_bw = None + if input_size == 6: + initial_h = tensor_dict.get(node.inputs[5], None) + if initial_h is not None: + initial_state = (initial_h[0],) + if num_directions == 2: + initial_state_bw = (initial_h[1],) + + rnn_kwargs = {} + if num_directions == 1: + rnn_kwargs["initial_state"] = initial_state + elif num_directions == 2: + rnn_kwargs["initial_state_fw"] = initial_state + rnn_kwargs["initial_state_bw"] = initial_state_bw + rnn_kwargs["sequence_length"] = sequence_length + rnn_kwargs["time_major"] = True + rnn_kwargs["dtype"] = tf.float32 + + outputs, states = cls.rnn(x, tf.nn.rnn_cell.GRUCell, cell_kwargs, + rnn_kwargs, tf_activations, direction) + + if num_directions == 1: + state = states[0] + h = tf.expand_dims(state, 0) + output = tf.expand_dims(outputs, 1) + else: + state_fw = states[0][0] + state_bw = states[1][0] + output_fw = outputs[0] + output_bw = outputs[1] + h_fw = tf.expand_dims(state_fw, 0) + h_bw = tf.expand_dims(state_bw, 0) + h = tf.concat((h_fw, h_bw), axis=0) + output_fw = tf.expand_dims(output_fw, 1) + output_bw = tf.expand_dims(output_bw, 1) + output = tf.concat((output_fw, output_bw), axis=1) + + return [output, h] if output_sequence == 0 else [h] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_3(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/hard_sigmoid.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/hard_sigmoid.py new file mode 100644 index 0000000..5f1e8d5 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/hard_sigmoid.py @@ -0,0 +1,26 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("HardSigmoid") +class HardSigmoid(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + if "alpha" not in node.attrs and "beta" not in node.attrs: + return [tf.keras.backend.hard_sigmoid(x)] + + alpha = node.attrs.get("alpha", 0.2) + beta = node.attrs.get("beta", 0.5) + return [tf.clip_by_value(x * alpha + beta, 0, 1)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/hardmax.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/hardmax.py new file mode 100644 index 0000000..42f0ba9 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/hardmax.py @@ -0,0 +1,35 @@ +import numpy as np +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Hardmax") +@tf_func(tf.contrib.seq2seq.hardmax) +class Hardmax(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + axis = node.attrs.get("axis", 1) + axis = axis if axis >= 0 else len(np.shape(x)) + axis + + if axis == len(np.shape(x)) - 1: + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + shape = tf.shape(x) + cal_shape = (tf.reduce_prod(shape[0:axis]), + tf.reduce_prod(shape[axis:tf.size(shape)])) + x = tf.reshape(x, cal_shape) + + return [tf.reshape(tf.contrib.seq2seq.hardmax(x), shape)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/identity.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/identity.py new file mode 100644 index 0000000..b974b2f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/identity.py @@ -0,0 +1,14 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Identity") +@tf_func(tf.identity) +class Identity(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/if.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/if.py new file mode 100644 index 0000000..1eac5ee --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/if.py @@ -0,0 +1,51 @@ +import tensorflow as tf + +import onnx_tf +from onnx.helper import make_opsetid +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("If") +@tf_func(tf.cond) +class If(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + cond = kwargs["tensor_dict"][node.inputs[0]] + then_branch = node.attrs["then_branch"] + else_branch = node.attrs["else_branch"] + current_opset = [make_opsetid(cls.DOMAIN, cls.VERSION)] + + def true_fn(): + subgraph_tensor_dict = onnx_tf.backend.onnx_graph_to_tensorflow_ops( + subgraph=then_branch, + input_values={}, # all inputs of then_branch are in tensor_dict + tensor_dict=kwargs["tensor_dict"], + opset=current_opset) + return [subgraph_tensor_dict[o.name] for o in then_branch.output] + + def false_fn(): + subgraph_tensor_dict = onnx_tf.backend.onnx_graph_to_tensorflow_ops( + subgraph=else_branch, + input_values={}, # all inputs of else_branch are in tensor_dict + tensor_dict=kwargs["tensor_dict"], + opset=current_opset) + return [subgraph_tensor_dict[o.name] for o in else_branch.output] + + # Set strict=True to make sure singleton lists and tuples return from + # true_fn and false_fn will not be implicitly unpacked to single values + strict = True + return [ + cls.make_tensor_from_onnx_node(node, + inputs=[cond, true_fn, false_fn, strict]) + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/image_scaler.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/image_scaler.py new file mode 100644 index 0000000..4ae2599 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/image_scaler.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("ImageScaler") +class ImageScaler(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + input_dict = kwargs["tensor_dict"] + x = input_dict[node.inputs[0]] + scale = node.attrs.get("scale", 1.0) + output = tf.multiply(x, scale) + if "bias" in node.attrs: + bias = node.attrs["bias"] + output = tf.nn.bias_add(output, bias, data_format="NCHW") + return [output] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/instance_normalization.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/instance_normalization.py new file mode 100644 index 0000000..525626e --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/instance_normalization.py @@ -0,0 +1,60 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("InstanceNormalization") +@tf_func(tf.nn.batch_normalization) +class InstanceNormalization(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return { + "default": { + "epsilon": 1e-5 + }, + "rename": { + "epsilon": "variance_epsilon" + } + } + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + # this file is adapted from : + # https://github.com/tensorflow/tensorflow/blob/r1.8/tensorflow/contrib/layers/python/layers/normalization.py. + # We do not use the tf layer instance_norm because there is no way + # to pass in tensor as beta or gamma. + gamma = tensor_dict[node.inputs[1]] + beta = tensor_dict[node.inputs[2]] + + inputs = tensor_dict[node.inputs[0]] + inputs_shape = inputs.shape + inputs_rank = inputs.shape.ndims + + moments_axes = list(range(inputs_rank))[2:] + params_shape_broadcast = list([1, inputs_shape[1].value] + + [1 for _ in range(2, inputs_rank)]) + + beta = tf.reshape(beta, params_shape_broadcast) + gamma = tf.reshape(gamma, params_shape_broadcast) + + # Calculate the moments (instance activations). + mean, variance = tf.nn.moments(inputs, moments_axes, keep_dims=True) + + # Compute instance normalization. + inputs = [inputs, mean, variance, beta, gamma] + return [ + cls.make_tensor_from_onnx_node( + node, inputs=inputs, name="instancenorm", **kwargs) + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/is_inf.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/is_inf.py new file mode 100644 index 0000000..09fb75b --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/is_inf.py @@ -0,0 +1,27 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + +@onnx_op("IsInf") +@tf_func(tf.math.is_inf) +class IsInf(BackendHandler): + + @classmethod + def version_10(cls, node, **kwargs): + inp = kwargs["tensor_dict"][node.inputs[0]] + dtype = inp.dtype + shape = inp.shape + zero = tf.zeros(shape, dtype) + dn = node.attrs.get("detect_negative", 1) + dp = node.attrs.get("detect_positive", 1) + # detecting only positive infinity, zero out elements < 0 + if dn == 0: + inp = tf.maximum(zero, inp) + # detecting only negative infinity, zero out elements > 0 + if dp == 0: + inp = tf.minimum(zero, inp) + return [ + cls.make_tensor_from_onnx_node(node, inputs=[inp], **kwargs) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/is_nan.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/is_nan.py new file mode 100644 index 0000000..b7874e8 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/is_nan.py @@ -0,0 +1,14 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("IsNaN") +@tf_func(tf.is_nan) +class IsNaN(BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/leaky_relu.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/leaky_relu.py new file mode 100644 index 0000000..e0efe19 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/leaky_relu.py @@ -0,0 +1,22 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("LeakyRelu") +@tf_func(tf.nn.leaky_relu) +class Identity(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"alpha": 0.01}} + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/less.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/less.py new file mode 100644 index 0000000..c2f6701 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/less.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .control_flow_mixin import ComparisonMixin + + +@onnx_op("Less") +@tf_func(tf.less) +class Less(ComparisonMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_9(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/log.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/log.py new file mode 100644 index 0000000..19370f7 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/log.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Log") +@tf_func(tf.log) +class Log(BasicMathMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/log_softmax.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/log_softmax.py new file mode 100644 index 0000000..506c643 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/log_softmax.py @@ -0,0 +1,35 @@ +import numpy as np +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("LogSoftmax") +@tf_func(tf.nn.log_softmax) +class LogSoftmax(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + axis = node.attrs.get("axis", 1) + axis = axis if axis >= 0 else len(np.shape(x)) + axis + + if axis == len(np.shape(x)) - 1: + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + shape = tf.shape(x) + cal_shape = (tf.reduce_prod(shape[0:axis]), + tf.reduce_prod(shape[axis:tf.size(shape)])) + x = tf.reshape(x, cal_shape) + + return [tf.reshape(tf.nn.log_softmax(x - tf.reduce_max(x)), shape)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/loop.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/loop.py new file mode 100644 index 0000000..b29ce8a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/loop.py @@ -0,0 +1,110 @@ +import tensorflow as tf + +import onnx_tf +from onnx.helper import make_opsetid +from onnx_tf.common import data_type +from onnx_tf.common import exception +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("Loop") +class Loop(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + body = node.attrs["body"] + tensor_dict = kwargs["tensor_dict"] + M = tensor_dict[node.inputs[0]] if node.inputs[0] != "" else None + cond = tf.cast(tensor_dict[node.inputs[1]], + tf.bool) if node.inputs[1] != "" else None + v_initial = [tensor_dict[graph_input] for graph_input in node.inputs[2:]] + v_shapes = [v.get_shape() for v in v_initial] + current_opset = [make_opsetid(cls.DOMAIN, cls.VERSION)] + # outputs of the body will be in this format: + # (condition, loop carried dependencies..., scan_outputs...) + scan_outputs_start_index = 1 + len(v_initial) + scan_outputs = [ + tf.TensorArray(dtype=data_type.onnx2tf( + body.output[i].type.tensor_type.elem_type), + size=0, + dynamic_size=True) + for i in range(scan_outputs_start_index, len(body.output)) + ] + scan_outputs_shapes = [tf.TensorShape(None) for o in scan_outputs] + + def run_subgraph(cond, v, scan_outputs): + input_values = {} + input_values[body.input[0].name] = M + input_values[body.input[1].name] = cond + for i in range(2, len(body.input)): + input_values[body.input[i].name] = v[i - 2] + subgraph_tensor_dict = onnx_tf.backend.onnx_graph_to_tensorflow_ops( + subgraph=body, + input_values=input_values, + tensor_dict=tensor_dict, + opset=current_opset) + outputs = [subgraph_tensor_dict[output.name] for output in body.output] + for i in range(scan_outputs_start_index, len(outputs)): + s_index = i - scan_outputs_start_index + insert_index = scan_outputs[s_index].size() + scan_outputs[s_index] = scan_outputs[s_index].write( + insert_index, outputs[i]) + return [outputs[0], outputs[1:scan_outputs_start_index], scan_outputs] + + # for loop + if M is not None and cond is None: + M = tf.cast(M, tf.int32) + condition = lambda cond, v, scan_outputs: True + _, v_final, scan_outputs = tf.while_loop( + cond=condition, + body=run_subgraph, + loop_vars=["", v_initial, scan_outputs], + shape_invariants=[ + tf.TensorShape(None), v_shapes, scan_outputs_shapes + ], + maximum_iterations=M) + # while and do-while loop + elif M is None and cond is not None: + condition = lambda cond, v, scan_outputs: tf.reduce_all( + tf.equal(cond, True)) + cond, v_final, scan_outputs = tf.while_loop( + cond=condition, + body=run_subgraph, + loop_vars=[cond, v_initial, scan_outputs], + shape_invariants=[ + tf.TensorShape(None), v_shapes, scan_outputs_shapes + ]) + # combine for loop and while loop together + elif M is not None and cond is not None: + M = tf.cast(M, tf.int32) + condition = lambda cond, v, scan_outputs: tf.reduce_all( + tf.equal(cond, True)) + cond, v_final, scan_outputs = tf.while_loop( + cond=condition, + body=run_subgraph, + loop_vars=[cond, v_initial, scan_outputs], + shape_invariants=[ + tf.TensorShape(None), v_shapes, scan_outputs_shapes + ], + maximum_iterations=M) + else: # M is None and cond is None + exception.OP_UNSUPPORTED_EXCEPT( + "Both M and cond in Loop are not set at the same time", + "Tensorflow.(PS. if you want to create a do-while loop " + + "then please set cond to True or 1)") + + scan_outputs_tensors = [o.stack() for o in scan_outputs] + if scan_outputs_start_index == len(body.output): + # there is no scan_output in the body graph + return [v_final] + else: + return [v_final, scan_outputs_tensors] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lp_normalization.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lp_normalization.py new file mode 100644 index 0000000..a22d844 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lp_normalization.py @@ -0,0 +1,33 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("LpNormalization") +@tf_func(tf.norm) +class LpNormalization(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return { + "default": { + "axis": -1, + "p": 2, + "keepdims": True + }, + "rename": { + "p": "ord" + } + } + + @classmethod + def version_1(cls, node, **kwargs): + input_tensor = kwargs["tensor_dict"][node.inputs[0]] + tf_norm = cls.make_tensor_from_onnx_node(node, **kwargs) + + return [ + cls.make_tensor_from_onnx_node( + node, tf_func=tf.div, inputs=[input_tensor, tf_norm], **kwargs) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lp_pool.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lp_pool.py new file mode 100644 index 0000000..25732e0 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lp_pool.py @@ -0,0 +1,24 @@ +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .pool_mixin import PoolMixin + + +@onnx_op("LpPool") +class LpPool(PoolMixin, BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + return cls.pool(node, kwargs["tensor_dict"], "LP", + kwargs.get("strict", True)) + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_2(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lrn.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lrn.py new file mode 100644 index 0000000..cff8796 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lrn.py @@ -0,0 +1,29 @@ +import copy + +import tensorflow as tf +import numpy as np + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("LRN") +@tf_func(tf.nn.lrn) +class LRN(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + attrs = copy.deepcopy(node.attrs) + alpha = attrs.get("alpha", 1e-4) + attrs.setdefault("beta", 0.75) + size = attrs["size"] + attrs["alpha"] = alpha / size + attrs["depth_radius"] = np.floor([(size - 1) / 2.])[0] + # TODO: LRN in tf accepts radius + # but in ONNX/Caffe accepts diameter. + # This could be a problem. + return [ + cls.make_tensor_from_onnx_node( + node, attrs=attrs, c_last_only=True, **kwargs) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lstm.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lstm.py new file mode 100644 index 0000000..74369e0 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/lstm.py @@ -0,0 +1,218 @@ +from functools import partial + +import tensorflow as tf + +from onnx_tf.common import get_unique_suffix +from onnx_tf.common import exception +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from .rnn_mixin import RNNMixin + + +@onnx_op("LSTM") +@partial_support(True) +@ps_description("LSTM not using sigmoid for `f`, or " + + "LSTM not using the same activation for `g` and `h` " + + "are not supported in Tensorflow.") +class LSTM(RNNMixin, BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + direction = node.attrs.get("direction", "forward") + num_directions = 2 if direction == "bidirectional" else 1 + if node.attrs.get("input_forget", 0): + # TODO(fumihwh): warning + pass + if "activations" in node.attrs: + activations = list(map(lambda x: x.lower(), node.attrs["activations"])) + if activations[0] != "sigmoid": + exception.OP_UNSUPPORTED_EXCEPT("LSTM without sigmoid for `f`", + "Tensorflow") + if activations[1] != activations[2]: + exception.OP_UNSUPPORTED_EXCEPT( + "LSTM without same activation for `g` and `h`", "Tensorflow") + if num_directions == 2: + if activations[3] != "sigmoid": + exception.OP_UNSUPPORTED_EXCEPT("LSTM without sigmoid for `f`", + "Tensorflow") + if activations[4] != activations[5]: + exception.OP_UNSUPPORTED_EXCEPT( + "LSTM without same activation for `g` and `h`", "Tensorflow") + + @classmethod + def _custom_getter(cls, + getter, + name, + node=None, + tensor_dict=None, + is_bidirectional=None, + *args, + **kwargs): + names = name.split("/") + if is_bidirectional: + if "fw" in names: + index = 0 + elif "bw" in names: + index = 1 + else: + raise RuntimeError("Can not get {} for bidirectional. " + "Either fw and bw is not in name scope.".format( + names[-1])) + + if names[-1] == "kernel": + # onnx W[iofc], R[iofc] + if is_bidirectional: + w = tf.split(tensor_dict[node.inputs[1]], 2)[index] + r = tf.split(tensor_dict[node.inputs[2]], 2)[index] + else: + w = tensor_dict[node.inputs[1]] + r = tensor_dict[node.inputs[2]] + w_i, w_o, w_f, w_c = tf.split(tf.squeeze(w), 4) + r_i, r_o, r_f, r_c = tf.split(tf.squeeze(r), 4) + new_w = tf.transpose(tf.concat([w_i, w_c, w_f, w_o], 0)) + new_r = tf.transpose(tf.concat([r_i, r_c, r_f, r_o], 0)) + kernel = tf.concat([new_w, new_r], 0) + return kernel + if names[-1] == "bias": + if len(node.inputs) >= 4: + # onnx Wb[iofc], Rb[iofc] + if is_bidirectional: + b = tf.split(tensor_dict[node.inputs[3]], 2)[index] + else: + b = tensor_dict[node.inputs[3]] + w_b, r_b = tf.split(tf.squeeze(b), 2) + w_b_i, w_b_o, w_b_f, w_b_c = tf.split(w_b, 4) + r_b_i, r_b_o, r_b_f, r_b_c = tf.split(r_b, 4) + w_b = tf.transpose(tf.concat([w_b_i, w_b_c, w_b_f, w_b_o], 0)) + r_b = tf.transpose(tf.concat([r_b_i, r_b_c, r_b_f, r_b_o], 0)) + return tf.add(w_b, r_b) + return getter(name, *args, **kwargs) + # Only use_peepholes is True, + # will try to get w_f_diag, w_i_diag, w_o_diag + # onnx P[iof] + if names[-1] in ["w_f_diag", "w_i_diag", "w_o_diag"]: + if is_bidirectional: + p = tf.split(tensor_dict[node.inputs[7]], 2)[index] + else: + p = tensor_dict[node.inputs[7]] + if names[-1] == "w_f_diag": + return tf.split(p, 3, axis=1)[2] + if names[-1] == "w_i_diag": + return tf.split(p, 3, axis=1)[0] + if names[-1] == "w_o_diag": + return tf.split(p, 3, axis=1)[1] + return getter(name, *args, **kwargs) + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + input_shape = x.get_shape().as_list() + input_size = len(node.inputs) + hidden_size = node.attrs["hidden_size"] + direction = node.attrs.get("direction", "forward") + num_directions = 2 if direction == "bidirectional" else 1 + + # removed from version 7, default is 0 + output_sequence = node.attrs.get("output_sequence", 0) + + # TODO(fumihwh): check if prev node is one of RNN + # process input if it comes from other previous cell + # which has shape [seq_length, num_directions, batch_size, hidden_size] + if len(input_shape) == 4 and input_shape[1] == 1: + x = tf.squeeze(x) + + sequence_length = None + if input_size >= 5 and node.inputs[4] in tensor_dict: + sequence_length = tensor_dict[node.inputs[4]] + + cell_kwargs = {} + + if "clip" in node.attrs: + cell_kwargs["cell_clip"] = node.attrs["clip"] + + tf_activations = [tf.nn.tanh] * num_directions + if "activations" in node.attrs: + activations = list(map(lambda x: x.lower(), node.attrs["activations"])) + activation_alpha = node.attrs.get("activation_alpha", [None] * 6) + activation_beta = node.attrs.get("activation_beta", [None] * 6) + + # tf only supports cutomizing hidden states activation function, + # which correspond to activation functions specified at position 1 + # and 4 in onnx's activations attribute. + activation_idxs = [1, 4] if num_directions == 2 else [1] + tf_activations = [ + cls.rnn_get_activation(activations[i], activation_alpha[i], + activation_beta[i]) for i in activation_idxs + ] + + # TODO(fumihwh): check if reverse and bidirectional works + with tf.variable_scope("LSTM_" + get_unique_suffix(), + custom_getter=partial( + cls._custom_getter, + node=node, + tensor_dict=tensor_dict, + is_bidirectional=num_directions == 2)): + + cell_kwargs[ + "use_peepholes"] = input_size == 8 and node.inputs[7] in tensor_dict + cell_kwargs["forget_bias"] = 0. + cell_kwargs["num_units"] = hidden_size + initial_state = None + initial_state_bw = None + if input_size >= 6: + initial_h = tensor_dict.get(node.inputs[5], None) + initial_c = tensor_dict.get( + node.inputs[6], + None) if input_size >= 7 else tf.zeros_like(initial_h) + if initial_h is not None and initial_c is not None: + initial_state = (tf.nn.rnn_cell.LSTMStateTuple( + initial_c[0], initial_h[0]),) + if num_directions == 2: + initial_state_bw = (tf.nn.rnn_cell.LSTMStateTuple( + initial_c[1], initial_h[1]),) + + rnn_kwargs = {} + if num_directions == 1: + rnn_kwargs["initial_state"] = initial_state + elif num_directions == 2: + rnn_kwargs["initial_state_fw"] = initial_state + rnn_kwargs["initial_state_bw"] = initial_state_bw + rnn_kwargs["sequence_length"] = sequence_length + rnn_kwargs["time_major"] = True + rnn_kwargs["dtype"] = tf.float32 + + outputs, states = cls.rnn(x, tf.nn.rnn_cell.LSTMCell, cell_kwargs, + rnn_kwargs, tf_activations, direction) + + if num_directions == 1: + state = states[0] + c = tf.expand_dims(state[0], 0) + h = tf.expand_dims(state[1], 0) + output = tf.expand_dims(outputs, 1) + else: + state_fw = states[0][0] + state_bw = states[1][0] + output_fw = outputs[0] + output_bw = outputs[1] + c_fw = tf.expand_dims(state_fw[0], 0) + c_bw = tf.expand_dims(state_bw[0], 0) + c = tf.concat((c_fw, c_bw), axis=0) + h_fw = tf.expand_dims(state_fw[1], 0) + h_bw = tf.expand_dims(state_bw[1], 0) + h = tf.concat((h_fw, h_bw), axis=0) + output_fw = tf.expand_dims(output_fw, 1) + output_bw = tf.expand_dims(output_bw, 1) + output = tf.concat((output_fw, output_bw), axis=1) + + return [output, h, c] if output_sequence == 0 else [h, c] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mat_mul.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mat_mul.py new file mode 100644 index 0000000..c45c049 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mat_mul.py @@ -0,0 +1,18 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("MatMul") +@tf_func(tf.matmul) +class MatMul(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_9(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mat_mul_integer.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mat_mul_integer.py new file mode 100644 index 0000000..fcc26be --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mat_mul_integer.py @@ -0,0 +1,38 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("MatMulInteger") +@tf_func(tf.matmul) +class MatMulInteger(BackendHandler): + + @classmethod + def version_10(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + A = tensor_dict[node.inputs[0]] + B = tensor_dict[node.inputs[1]] + # tf.matmul doesn't support int8 and uint8 for A and B, + # therefore need to cast them to int32 + A = tf.cast(A, tf.int32) + B = tf.cast(B, tf.int32) + + # apply a_zero_point to A + if len(node.inputs) > 2: + a_zero_point = tensor_dict[node.inputs[2]] + shape = a_zero_point.get_shape().as_list() + if len(shape) > 0 and shape[0] > 1: + # reshape a_zero_point before subtract it from A + a_zero_point = tf.reshape(a_zero_point, [shape[0], 1]) + a_zero_point = tf.cast(a_zero_point, tf.int32) + A = tf.subtract(A, a_zero_point) + + # apply b_zero_point to B + if len(node.inputs) == 4: + b_zero_point = tensor_dict[node.inputs[3]] + b_zero_point = tf.cast(b_zero_point, tf.int32) + B = tf.subtract(B, b_zero_point) + + return [cls.make_tensor_from_onnx_node(node, inputs=[A, B], **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/math_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/math_mixin.py new file mode 100644 index 0000000..dfe5919 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/math_mixin.py @@ -0,0 +1,25 @@ +import copy + +from .broadcast_mixin import BroadcastMixin + + +class BasicMathMixin(BroadcastMixin): + pass + + +class ArithmeticMixin(BroadcastMixin): + pass + + +class ReductionMixin(BroadcastMixin): + + @classmethod + def _common(cls, node, **kwargs): + attrs = copy.deepcopy(node.attrs) + axis = attrs.pop("axes", None) + if isinstance(axis, (list, tuple)) and len(axis) == 1: + axis = axis[0] + attrs["axis"] = axis + # https://github.com/onnx/onnx/issues/585 + attrs["keepdims"] = attrs.pop("keepdims", 1) == 1 + return [cls.make_tensor_from_onnx_node(node, attrs=attrs, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max.py new file mode 100644 index 0000000..8bffa69 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max.py @@ -0,0 +1,34 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Max") +@tf_func(tf.reduce_max) +class Max(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"axis": 0}} + + @classmethod + def _common(cls, node, **kwargs): + values = [kwargs["tensor_dict"][inp] for inp in node.inputs] + return [ + cls.make_tensor_from_onnx_node( + node, inputs=[tf.stack(values)], **kwargs) + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_8(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max_pool.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max_pool.py new file mode 100644 index 0000000..acc14c4 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max_pool.py @@ -0,0 +1,40 @@ +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from .pool_mixin import PoolMixin + + +@onnx_op("MaxPool") +@partial_support(True) +@ps_description( + "MaxPoolWithArgmax with pad is None or incompatible mode, or " + + "MaxPoolWithArgmax with 4D or higher input, or" + + "MaxPoolWithArgmax with column major " + "are not supported in Tensorflow.") +class MaxPool(PoolMixin, BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + pool_type = "MAX" if len(node.outputs) == 1 else "MAX_WITH_ARGMAX" + return cls.pool(node, kwargs["tensor_dict"], pool_type, + kwargs.get("strict", True)) + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_8(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_10(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_12(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max_unpool.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max_unpool.py new file mode 100644 index 0000000..8fdfa6f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/max_unpool.py @@ -0,0 +1,15 @@ +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .unpool_mixin import UnpoolMixin + + +@onnx_op("MaxUnpool") +class MaxUnpool(UnpoolMixin, BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + return cls.max_unpool(node, kwargs["tensor_dict"]) + + @classmethod + def version_11(cls, node, **kwargs): + return cls.max_unpool(node, kwargs["tensor_dict"]) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mean.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mean.py new file mode 100644 index 0000000..6afdea5 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mean.py @@ -0,0 +1,34 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Mean") +@tf_func(tf.reduce_mean) +class Mean(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"axis": 0}} + + @classmethod + def _common(cls, node, **kwargs): + values = [kwargs["tensor_dict"][inp] for inp in node.inputs] + return [ + cls.make_tensor_from_onnx_node( + node, inputs=[tf.stack(values)], **kwargs) + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_8(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mean_variance_normalization.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mean_variance_normalization.py new file mode 100644 index 0000000..be8b783 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mean_variance_normalization.py @@ -0,0 +1,47 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("MeanVarianceNormalization") +class MeanVarianceNormalization(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + inputs = tensor_dict[node.inputs[0]] + inputs_rank = inputs.shape.ndims + + across_channels = node.attrs.get("across_channels", 0) + normalize_variance = node.attrs.get("normalize_variance", 1) + + moments_axes = [0] if not across_channels else [0, 1] + moments_axes += list(range(inputs_rank))[2:] + + mean, variance = tf.nn.moments(inputs, moments_axes, keep_dims=True) + + if not normalize_variance: + return [inputs - mean] + return [(inputs - mean) / tf.sqrt(variance)] + + @classmethod + def version_9(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + inputs = tensor_dict[node.inputs[0]] + inputs_rank = inputs.shape.ndims + # To satisfy default axes=[0,2,3], also assume the + # following default when rank is not 4 + # rank1 -> axes=[0] + # rank2 -> axes=[0] + # rank3 -> axes=[0,2] + # rank4 -> axes=[0,2,3] + # rankN -> axes=[0,2,3,..,N-1] + # TODO(tedhtchang): Since input tensor is no longer limited + # to shape [N,C,H,W], consider using "[0]" or "[]" as default axes. + # See issue https://github.com/onnx/onnx/issues/2047 + default_axes = [0] if inputs_rank < 3 else [0, 2] + default_axes += list(range(inputs_rank))[3:] + moments_axes = node.attrs.get("axes", default_axes) + mean, variance = tf.nn.moments(inputs, moments_axes, keep_dims=True) + return [(inputs - mean) / tf.sqrt(variance)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/min.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/min.py new file mode 100644 index 0000000..f478b0d --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/min.py @@ -0,0 +1,34 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Min") +@tf_func(tf.reduce_min) +class Min(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"axis": 0}} + + @classmethod + def _common(cls, node, **kwargs): + values = [kwargs["tensor_dict"][inp] for inp in node.inputs] + return [ + cls.make_tensor_from_onnx_node( + node, inputs=[tf.stack(values)], **kwargs) + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_8(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mod.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mod.py new file mode 100644 index 0000000..ad5567f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mod.py @@ -0,0 +1,38 @@ +import tensorflow as tf + +from onnx_tf.common import exception +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from .math_mixin import ArithmeticMixin + + +@onnx_op("Mod") +@partial_support(True) +@ps_description("Mod Dividend or Divisor in " + + "int8/int16/uint8/uint16/uint32/uint64 " + + "are not supported in Tensorflow.") +class Mod(ArithmeticMixin, BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + unsupported_dtype = [ + tf.int8, tf.int16, tf.uint8, tf.uint16, tf.uint32, tf.uint64 + ] + x = kwargs["tensor_dict"][node.inputs[0]] + y = kwargs["tensor_dict"][node.inputs[1]] + if x.dtype in unsupported_dtype: + exception.OP_UNSUPPORTED_EXCEPT( + "Mod Dividend in " + str(x.dtype), "Tensorflow") + if y.dtype in unsupported_dtype: + exception.OP_UNSUPPORTED_EXCEPT( + "Mod Divisor in " + str(y.dtype), "Tensorflow") + + @classmethod + def version_10(cls, node, **kwargs): + fmod = node.attrs.get("fmod", 0) + tf_func = tf.floormod + if fmod == 1: + tf_func = tf.truncatemod + return [cls.make_tensor_from_onnx_node(node, tf_func=tf_func, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mul.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mul.py new file mode 100644 index 0000000..55056b0 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/mul.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ArithmeticMixin + + +@onnx_op("Mul") +@tf_func(tf.multiply) +class Mul(ArithmeticMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/neg.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/neg.py new file mode 100644 index 0000000..09b33c1 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/neg.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Neg") +@tf_func(tf.negative) +class Neg(BasicMathMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/non_max_suppression.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/non_max_suppression.py new file mode 100644 index 0000000..d9745a6 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/non_max_suppression.py @@ -0,0 +1,84 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("NonMaxSuppression") +class NonMaxSuppression(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + boxes = tensor_dict[node.inputs[0]] + scores = tensor_dict[node.inputs[1]] + # in ONNX spec max_output_boxes_per_class need to be in int64 but + # max_output_boxes for tf.image.non_max_suppression must be in tf.int32 + # therefore need to cast this input to tf.int32 + max_output_boxes_per_class = tf.cast( + tensor_dict[node.inputs[2]], + tf.int32) if (len(node.inputs) > 2 and + node.inputs[2] != "") else tf.constant(0, tf.int32) + # make sure max_output_boxes_per_class is a scalar not a 1-D 1 element tensor + max_output_boxes_per_class = tf.squeeze(max_output_boxes_per_class) if len( + max_output_boxes_per_class.shape) == 1 else max_output_boxes_per_class + iou_threshold = tensor_dict[node.inputs[3]] if ( + len(node.inputs) > 3 and node.inputs[3] != "") else tf.constant( + 0, tf.float32) + # make sure iou_threshold is a scalar not a 1-D 1 element tensor + iou_threshold = tf.squeeze(iou_threshold) if len( + iou_threshold.shape) == 1 else iou_threshold + score_threshold = tensor_dict[node.inputs[4]] if ( + len(node.inputs) > 4 and node.inputs[4] != "") else tf.constant( + float('-inf')) + # make sure score_threshold is a scalar not a 1-D 1 element tensor + score_threshold = tf.squeeze(score_threshold) if len( + score_threshold.shape) == 1 else score_threshold + center_point_box = node.attrs.get("center_point_box", 0) + + if center_point_box == 1: + boxes_t = tf.transpose(boxes, perm=[0, 2, 1]) + x_centers = tf.slice(boxes_t, [0, 0, 0], [-1, 1, -1]) + y_centers = tf.slice(boxes_t, [0, 1, 0], [-1, 1, -1]) + widths = tf.slice(boxes_t, [0, 2, 0], [-1, 1, -1]) + heights = tf.slice(boxes_t, [0, 3, 0], [-1, 1, -1]) + y1 = tf.subtract(y_centers, tf.divide(heights, 2)) + x1 = tf.subtract(x_centers, tf.divide(widths, 2)) + y2 = tf.add(y_centers, tf.divide(heights, 2)) + x2 = tf.add(x_centers, tf.divide(widths, 2)) + boxes_t = tf.concat([y1, x1, y2, x2], 1) + boxes = tf.transpose(boxes_t, perm=[0, 2, 1]) + + # get number of batches in boxes + num_batches = boxes.shape[0] + for batch_i in range(num_batches): + # get boxes in batch_i only + tf_boxes = tf.squeeze(tf.gather(boxes, [batch_i]), axis=0) + # get scores of all classes in batch_i only + batch_i_scores = tf.squeeze(tf.gather(scores, [batch_i]), axis=0) + # get number of classess in batch_i only + num_classes = batch_i_scores.shape[0] + for class_j in range(num_classes): + # get scores in class_j for batch_i only + tf_scores = tf.squeeze(tf.gather(batch_i_scores, [class_j]), axis=0) + # get the selected boxes indices + selected_indices = tf.image.non_max_suppression( + tf_boxes, tf_scores, max_output_boxes_per_class, iou_threshold, + score_threshold) + # add batch and class information into the indices + output = tf.transpose([tf.cast(selected_indices, dtype=tf.int64)]) + paddings = tf.constant([[0, 0], [1, 0]]) + output = tf.pad(output, paddings, constant_values=class_j) + output = tf.pad(output, paddings, constant_values=batch_i) + result = tf.concat([result, output], + 0) if 'result' in locals() else output + + return [result] + + @classmethod + def version_10(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/non_zero.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/non_zero.py new file mode 100644 index 0000000..b3bdd43 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/non_zero.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("NonZero") +class NonZero(BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + input_tensor = kwargs["tensor_dict"][node.inputs[0]] + condition = tf.not_equal(input_tensor, tf.zeros_like(input_tensor)) + nonzero_indices = tf.where(condition) + return [tf.transpose(nonzero_indices)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/not.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/not.py new file mode 100644 index 0000000..f65815c --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/not.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .control_flow_mixin import LogicalMixin + + +@onnx_op("Not") +@tf_func(tf.logical_not) +class Not(LogicalMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/onehot.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/onehot.py new file mode 100644 index 0000000..2d32cbc --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/onehot.py @@ -0,0 +1,60 @@ +import copy +import tensorflow as tf + +from onnx_tf.common import exception +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("OneHot") +@tf_func(tf.one_hot) +@partial_support(True) +@ps_description("OneHot indices in uint16/uint32/uint64/int8/int16/"+ + "float16/float/double, or " + + "OneHot depth in uint8/uint16/uint32/uint64/int8/" + + "int16/int64/float16/float/double " + + "are not supported in Tensorflow.") +class OneHot(BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + indices = tensor_dict[node.inputs[0]] + depth = tensor_dict[node.inputs[1]] + if indices.dtype not in [tf.uint8, tf.int32, tf.int64]: + exception.OP_UNSUPPORTED_EXCEPT( + "OneHot indices must be in uint8 or int32 or int64 " + + "but it is currently in " + str(indices.dtype) + " which", + "Tensorflow") + if depth.dtype not in [tf.int32]: + exception.OP_UNSUPPORTED_EXCEPT( + "OneHot depth must be in int32 but it is currently in " + str( + depth.dtype) + " which", "Tensorflow") + + @classmethod + def _common(cls, node, **kwargs): + attrs = copy.deepcopy(node.attrs) + tensor_dict = kwargs["tensor_dict"] + indices = tensor_dict[node.inputs[0]] + depth = tensor_dict[node.inputs[1]] + off_value = tensor_dict[node.inputs[2]][0] + on_value = tensor_dict[node.inputs[2]][1] + attrs["dtype"] = on_value.dtype + return [ + cls.make_tensor_from_onnx_node( + node, + inputs=[indices, depth, on_value, off_value], + attrs=attrs, + **kwargs) + ] + + @classmethod + def version_9(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/or.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/or.py new file mode 100644 index 0000000..7db3686 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/or.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .control_flow_mixin import LogicalMixin + + +@onnx_op("Or") +@tf_func(tf.logical_or) +class Or(LogicalMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/p_relu.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/p_relu.py new file mode 100644 index 0000000..5a24ffb --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/p_relu.py @@ -0,0 +1,38 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .broadcast_mixin import BroadcastMixin + + +@onnx_op("PRelu") +class PRelu(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + """ + Reference implementation at + https://github.com/tflearn/tflearn/blob/4ba8c8d78bf1bbdfc595bf547bad30580cb4c20b/tflearn/activations.py#L191 + """ + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + slope = BroadcastMixin.explicit_broadcast([x, tensor_dict[node.inputs[1]]]) + pos = tf.nn.relu(x) + neg = slope * (x - abs(x)) * 0.5 + return [pos + neg] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_9(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pad.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pad.py new file mode 100644 index 0000000..85ed2f4 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pad.py @@ -0,0 +1,65 @@ +import numpy as np +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Pad") +@tf_func(tf.pad) +class Pad(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + num_dim = len(tensor_dict[node.inputs[0]].get_shape()) + mode = node.attrs.pop("mode", "constant") + + if cls.SINCE_VERSION < 11: # for opset 1 and opset 2 + paddings = node.attrs.pop("pads", None) + # tf requires int32 paddings + paddings = tf.constant( + np.transpose( + np.array(paddings).reshape([2, num_dim]).astype(np.int32))) + constant_values = node.attrs.pop("value", 0.) + + else: # for opset 11 + paddings = tensor_dict[node.inputs[1]] + # tf requires int32 paddings + paddings = tf.cast(tf.transpose(tf.reshape(paddings, [2, num_dim])), + dtype=tf.int32) + constant_values = tensor_dict[node.inputs[2]] if len( + node.inputs) == 3 else 0 + + def _symmetric_pad(i, x): + paddings_i = tf.map_fn(lambda e: tf.where(i < e, 1, 0), paddings) + paddings_i = tf.reshape(paddings_i, [num_dim, 2]) + x = tf.pad(x, paddings_i, 'SYMMETRIC') + return i + 1, x + + if mode.lower() == "edge": + paddings = tf.reshape(paddings, [-1]) + max_i = tf.reduce_max(paddings) + _, x = tf.while_loop( + lambda i, x: tf.less(i, max_i), _symmetric_pad, [0, x], + [tf.TensorShape([]), tf.TensorShape(None)]) + return [x] + + return [ + cls.make_tensor_from_onnx_node( + node, inputs=[x, paddings, mode, None, constant_values], **kwargs) + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_2(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pad_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pad_mixin.py new file mode 100644 index 0000000..271f4f9 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pad_mixin.py @@ -0,0 +1,17 @@ +import numpy as np +import tensorflow as tf + + +class PadMixin(object): + + @classmethod + def get_padding_as_op(cls, x, pads): + num_dim = int(len(pads) / 2) + + tf_pads = np.transpose(np.array(pads).reshape([2, num_dim])) + tf_pads = [0, 0, 0, 0] + tf_pads.flatten().tolist() + + padding = tf.constant( + np.array(tf_pads).reshape([num_dim + 2, 2]) + .astype(np.int32)) # tf requires int32 paddings + return tf.pad(x, padding) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pool_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pool_mixin.py new file mode 100644 index 0000000..aa26f0d --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pool_mixin.py @@ -0,0 +1,125 @@ +import tensorflow as tf + +from onnx_tf.common import exception +from onnx_tf.common import get_data_format +from onnx_tf.common import get_perm_from_formats + +from onnx_tf.common import logger +from .dilated_pooling import DilatedPooling +from onnx_tf.common.pooling_helper import py_pool +from onnx_tf.common.pooling_helper import calc_pads_same +from onnx_tf.common.pooling_helper import calc_output_shape + +class PoolMixin(object): + + @classmethod + def pool(cls, node, input_dict, pooling_type, strict=True): + x = input_dict[node.inputs[0]] + orig_x = x + + kernel_shape = node.attrs["kernel_shape"] + + spatial_size = len(kernel_shape) + x_rank = spatial_size + 2 + + kernel_shape = node.attrs["kernel_shape"] + strides = node.attrs.get("strides", [1] * spatial_size) + dilations = node.attrs.get("dilations", [1] * spatial_size) + ceil_mode = bool(node.attrs.get("ceil_mode", 0)) + pads = node.attrs.get("auto_pad", "NOTSET") + p = node.attrs.get("p", 2) + + if pads == "NOTSET": + pads = node.attrs.get("pads", [0] * spatial_size * 2) + # In case shape is fully defined, check if pads match + # SAME padding in Tensorflow + if x.shape.is_fully_defined() and pads != [0] * spatial_size * 2: + in_shape = x.get_shape().as_list() + same_paddings = calc_pads_same(in_shape[1:x_rank-1], kernel_shape, + strides, dilations, "SAME_UPPER") + if pads == same_paddings: + pads = "SAME_UPPER" + + count_include_pad = bool(node.attrs.get("count_include_pad", 0)) + if pooling_type == "AVG": + pooling_name = "AveragePool" + elif pooling_type == "MAX": + pooling_name = "MaxPool" + elif pooling_type == "MAX_WITH_ARGMAX": + pooling_name = "MaxPoolWithArgmax" + elif pooling_type == "LP": + pooling_name = "LpPool" + + if spatial_size > 3: + exception.OP_UNSUPPORTED_EXCEPT( + pooling_name + " with {}D input".format(x_rank), "Tensorflow") + if pooling_type == "MAX_WITH_ARGMAX" and x_rank != 4: + exception.OP_UNSUPPORTED_EXCEPT( + pooling_name + " with {}D input".format(x_rank), "Tensorflow") + if node.attrs.get("storage_order", 0) != 0: + exception.OP_UNSUPPORTED_EXCEPT(pooling_name + " with column major", + "Tensorflow") + + storage_format, _ = get_data_format(x_rank) + + need_trans = storage_format.startswith("NC") + if need_trans: + compute_format = "N" + storage_format[2:] + "C" + x = tf.transpose( + x, perm=get_perm_from_formats(storage_format, compute_format)) + + dp = DilatedPooling( + input=x, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + padding=pads, + ceil_mode=ceil_mode, + pooling_type=pooling_type, + count_include_pad=count_include_pad, + p=p) + if not dp.is_supported(): + if strict: + logger.warning( + "Using the pooling op in compatibility mode. " + "This means your graph cannot be serialized.", UserWarning) + + result = tf.py_func(py_pool, [ + orig_x, kernel_shape, strides, dilations, pads, ceil_mode, + pooling_type, False + ], orig_x.dtype) + + if orig_x.shape.is_fully_defined(): + shape = orig_x.get_shape().as_list() + output_shape = shape[0:2] + calc_output_shape(shape[2:x_rank], + kernel_shape, strides, dilations, pads, ceil_mode) + else: + output_shape = [None] * x_rank + result.set_shape(output_shape) + return [result] + else: + exception.OP_UNSUPPORTED_EXCEPT("strict == 0 and " + pooling_name + + " arguments not compatible", + "Tensorflow") + + def dilated_pool(): + return (dp.dilated_pool(), None) + + # select correct op depending on the pooling type + pooling_op = dilated_pool if pooling_type in ["MAX", "AVG", "LP"] else \ + dp.dilated_maxpool_with_argmax + + # select the correct transpose ops depending on the input storage format + perm = get_perm_from_formats(compute_format, storage_format) + + def postprocess(pooled, argmax): + return (tf.transpose(pooled, perm=perm) if need_trans else pooled, + tf.transpose(argmax, perm=perm) + if need_trans and argmax is not None else argmax) + + pooled, argmax = pooling_op() + pooled, argmax = postprocess(pooled, argmax) + + result = [pooled] if argmax is None else [pooled, argmax] + + return result diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pow.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pow.py new file mode 100644 index 0000000..1fddc2a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/pow.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Pow") +@tf_func(tf.pow) +class Pow(BasicMathMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/q_linear_conv.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/q_linear_conv.py new file mode 100644 index 0000000..e3e2dda --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/q_linear_conv.py @@ -0,0 +1,86 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .conv_mixin import ConvMixin + + +@onnx_op("QLinearConv") +class QLinearConv(ConvMixin, BackendHandler): + + @classmethod + def _dequantize_tensor(cls, base, zero_point, scale): + # Do computation in float32 + base = tf.cast(base, tf.float32) + zero_point = tf.cast(zero_point, tf.float32) + return (base - zero_point) * scale + + @classmethod + def _dequantize_w(cls, base, zero_point, scale): + tensor_list = [ + cls._dequantize_tensor(base[i][j], zero_point[j], scale[j]) + for i in range(base.shape.as_list()[0]) + for j in range(zero_point.shape.as_list()[0]) + ] + + out_tensor = tf.concat(tensor_list, 0) + return tf.reshape(out_tensor, base.shape) + + @classmethod + def version_10(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + x_scale = tensor_dict[node.inputs[1]] + x_zero_point = tensor_dict[node.inputs[2]] + w = tensor_dict[node.inputs[3]] + w_scale = tensor_dict[node.inputs[4]] + w_zero_point = tensor_dict[node.inputs[5]] + y_scale = tensor_dict[node.inputs[6]] + y_zero_point = tensor_dict[node.inputs[7]] + + output_dtype = x.dtype + + # Convert w_zero_point and w_scale to 1-D if scalar + if len(w_zero_point.shape) == 0: + w_zero_point = tf.fill([x.shape[1]], w_zero_point) + elif len(w_zero_point.shape) > 1: + raise ValueError("Unsupported zero point: {}".format(w_zero_point)) + + if len(w_scale.shape) == 0: + w_scale = tf.fill([x.shape[1]], w_scale) + elif len(w_scale.shape) > 1: + raise ValueError("Unsupported scale: {}".format(w_scale)) + + # Dequantize variables to float32 + x = cls._dequantize_tensor(x, x_zero_point, x_scale) + w = cls._dequantize_w(w, w_zero_point, w_scale) + y_zero_point = tf.cast(y_zero_point, tf.float32) + + new_dict = tensor_dict.copy() + new_dict[node.inputs[0]] = x + new_dict[node.inputs[3]] = w + + # if bias is defined save it here + B = tensor_dict[node.inputs[8]] if len(node.inputs) == 9 else tf.constant( + [0], tf.float32) + if len(node.inputs) == 9: + B = tf.cast(B, tf.float32) + B_scale = x_scale * w_scale + B = tf.round(B / B_scale) + # Remove bias from inputs + node.inputs.remove(node.inputs[8]) + + # Remove scales and zero-points from inputs + for i in [7, 6, 5, 4, 2, 1]: + node.inputs.remove(node.inputs[i]) + + # Use common conv handling + conv_node = cls.conv(node, new_dict)[0] + + # Process output + y = tf.round(conv_node / y_scale) + y_zero_point + + # Add bias to the convolution + y = y + B + + return [tf.cast(y, output_dtype)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/q_linear_mat_mul.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/q_linear_mat_mul.py new file mode 100644 index 0000000..9462881 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/q_linear_mat_mul.py @@ -0,0 +1,57 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("QLinearMatMul") +class QLinearMatMul(BackendHandler): + + @classmethod + def version_10(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + a = tensor_dict[node.inputs[0]] + a_scale = tensor_dict[node.inputs[1]] + a_zero_point = tensor_dict[node.inputs[2]] + b = tensor_dict[node.inputs[3]] + b_scale = tensor_dict[node.inputs[4]] + b_zero_point = tensor_dict[node.inputs[5]] + y_scale = tensor_dict[node.inputs[6]] + y_zero_point = tensor_dict[node.inputs[7]] + y_dtype = y_zero_point.dtype + + # reshape 1-D a_scale, a_zero_point, y_scale and + # y_zero_point so it can broadcast in arithmetic + # operations later + a_scale_shape = a_scale.get_shape().as_list() + if a_scale_shape and a_scale_shape[0] > 1: + a_scale = tf.reshape(a_scale, [a_scale_shape[0], 1]) + a_zero_point = tf.reshape(a_zero_point, [a_scale_shape[0], 1]) + y_scale_shape = y_scale.get_shape().as_list() + if y_scale_shape and y_scale_shape[0] > 1: + y_scale = tf.reshape(y_scale, [y_scale_shape[0], 1]) + y_zero_point = tf.reshape(y_zero_point, [y_scale_shape[0], 1]) + + # cast all inputs to float32 + a = tf.cast(a, tf.float32) + a_zero_point = tf.cast(a_zero_point, tf.float32) + b = tf.cast(b, tf.float32) + b_zero_point = tf.cast(b_zero_point, tf.float32) + y_zero_point = tf.cast(y_zero_point, tf.float32) + + # dequantize a and b + dequantized_a = tf.subtract(a, a_zero_point) + dequantized_a = tf.multiply(dequantized_a, a_scale) + dequantized_b = tf.subtract(b, b_zero_point) + dequantized_b = tf.multiply(dequantized_b, b_scale) + + # matmul + x = tf.matmul(dequantized_a, dequantized_b) + + # quantize x + y = tf.divide(x, y_scale) + y = tf.round(y) + y = tf.add(y, y_zero_point) + y = tf.saturate_cast(y, y_dtype) + + return [y] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/quantize_linear.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/quantize_linear.py new file mode 100644 index 0000000..f9241f2 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/quantize_linear.py @@ -0,0 +1,29 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("QuantizeLinear") +class QuantizeLinear(BackendHandler): + + @classmethod + def version_10(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + y_scale = tensor_dict[node.inputs[1]] + + x = tf.cast(x, tf.float32) + y = tf.divide(x, y_scale) + y = tf.round(y) + if len(node.inputs) == 3: + y_zero_point = tensor_dict[node.inputs[2]] + y_dtype = y_zero_point.dtype + y_zero_point = tf.cast(y_zero_point, tf.float32) + y = tf.add(y, y_zero_point) + else: # y_zero_point default dtype = uint8 + y_dtype = tf.uint8 + + y = tf.saturate_cast(y, y_dtype) + + return [y] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_normal.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_normal.py new file mode 100644 index 0000000..8ae0768 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_normal.py @@ -0,0 +1,18 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("RandomNormal") +@tf_func(tf.random_normal) +class RandomNormal(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"mean": 0., "scale": 1.}, "rename": {"scale": "stddev"}} + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_normal_like.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_normal_like.py new file mode 100644 index 0000000..464d6c8 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_normal_like.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("RandomNormalLike") +@tf_func(tf.random_normal) +class RandomNormalLike(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"mean": 0., "scale": 1.}, "rename": {"scale": "stddev"}} + + @classmethod + def version_1(cls, node, **kwargs): + inputs = [kwargs["tensor_dict"][node.inputs[0]].get_shape()] + return [cls.make_tensor_from_onnx_node(node, inputs=inputs, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_uniform.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_uniform.py new file mode 100644 index 0000000..9aa8ca9 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_uniform.py @@ -0,0 +1,27 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("RandomUniform") +@tf_func(tf.random_uniform) +class RandomUniform(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return { + "default": { + "low": 0., + "high": 1. + }, + "rename": { + "low": "minval", + "high": "maxval" + } + } + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_uniform_like.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_uniform_like.py new file mode 100644 index 0000000..f17c247 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/random_uniform_like.py @@ -0,0 +1,28 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("RandomUniformLike") +@tf_func(tf.random_uniform) +class RandomUniformLike(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return { + "default": { + "low": 0., + "high": 1. + }, + "rename": { + "low": "minval", + "high": "maxval" + } + } + + @classmethod + def version_1(cls, node, **kwargs): + inputs = [kwargs["tensor_dict"][node.inputs[0]].get_shape()] + return [cls.make_tensor_from_onnx_node(node, inputs=inputs, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/range.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/range.py new file mode 100644 index 0000000..3ede22e --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/range.py @@ -0,0 +1,14 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Range") +@tf_func(tf.range) +class Round(BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reciprocal.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reciprocal.py new file mode 100644 index 0000000..ec6ca73 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reciprocal.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Reciprocal") +@tf_func(tf.reciprocal) +class Reciprocal(BasicMathMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_l1.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_l1.py new file mode 100644 index 0000000..a429848 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_l1.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceL1") +@tf_func(tf.norm) +class ReduceL1(ReductionMixin, BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"ord": 1}} + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_l2.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_l2.py new file mode 100644 index 0000000..6913b9f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_l2.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceL2") +@tf_func(tf.norm) +class ReduceL2(ReductionMixin, BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"ord": 2}} + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_log_sum.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_log_sum.py new file mode 100644 index 0000000..3fad6dd --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_log_sum.py @@ -0,0 +1,24 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceLogSum") +class ReduceLogSum(ReductionMixin, BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + axis = node.attrs.get("axes", list(range(len(x.get_shape().as_list())))) + keepdims = node.attrs.get("keepdims", 1) == 1 + return [tf.log(tf.reduce_sum(x, axis=axis, keepdims=keepdims))] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_log_sum_exp.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_log_sum_exp.py new file mode 100644 index 0000000..d9fdc9b --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_log_sum_exp.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceLogSumExp") +@tf_func(tf.reduce_logsumexp) +class ReduceLogSumExp(ReductionMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_max.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_max.py new file mode 100644 index 0000000..768de25 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_max.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceMax") +@tf_func(tf.reduce_max) +class ReduceMax(ReductionMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_12(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_mean.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_mean.py new file mode 100644 index 0000000..cf3bf2a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_mean.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceMean") +@tf_func(tf.reduce_mean) +class ReduceMean(ReductionMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_min.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_min.py new file mode 100644 index 0000000..839cc3d --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_min.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceMin") +@tf_func(tf.reduce_min) +class ReduceMin(ReductionMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_12(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_prod.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_prod.py new file mode 100644 index 0000000..5d3ea7e --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_prod.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceProd") +@tf_func(tf.reduce_prod) +class ReduceProd(ReductionMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_sum.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_sum.py new file mode 100644 index 0000000..fabc91e --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_sum.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceSum") +@tf_func(tf.reduce_sum) +class ReduceSum(ReductionMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_sum_square.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_sum_square.py new file mode 100644 index 0000000..cef9a7b --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reduce_sum_square.py @@ -0,0 +1,24 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .math_mixin import ReductionMixin + + +@onnx_op("ReduceSumSquare") +class ReduceSumSquare(ReductionMixin, BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + axis = node.attrs.get("axes", list(range(len(x.get_shape().as_list())))) + keepdims = node.attrs.get("keepdims", 1) == 1 + return [tf.reduce_sum(tf.square(x), axis=axis, keepdims=keepdims)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/relu.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/relu.py new file mode 100644 index 0000000..c160f18 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/relu.py @@ -0,0 +1,18 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Relu") +@tf_func(tf.nn.relu) +class Relu(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reshape.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reshape.py new file mode 100644 index 0000000..f493564 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reshape.py @@ -0,0 +1,48 @@ +import copy + +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Reshape") +@tf_func(tf.reshape) +class Reshape(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + tensor = kwargs["tensor_dict"][node.inputs[0]] + if cls.SINCE_VERSION == 1: + shape = tf.constant(node.attrs["shape"], dtype=tf.int64) + else: # since_version >= 5 + shape = tf.cast(kwargs["tensor_dict"][node.inputs[1]], tf.int64) + input_shape = tf.shape(tensor, out_type=tf.int64) + + # Extract indicies of the shape parameter where + # a copy from the original dimension size is needed. + copy_indices = tf.squeeze( + tf.where(tf.equal(shape, tf.constant(0, dtype=tf.int64))), -1) + + indices_gathered = tf.gather(input_shape, copy_indices) + indices_scattered = tf.sparse_to_dense(copy_indices, + tf.cast(tf.shape(shape), tf.int64), + indices_gathered) + + # Perform the copy wherever requested (wherever dim_size == 0) + copied_shape = shape + indices_scattered + attrs = copy.deepcopy(node.attrs) + attrs.pop("shape", None) + return [ + cls.make_tensor_from_onnx_node( + node, inputs=[tensor, copied_shape], attrs=attrs, **kwargs) + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_5(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/resize.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/resize.py new file mode 100644 index 0000000..5e5c6b7 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/resize.py @@ -0,0 +1,274 @@ +import tensorflow as tf + +from onnx_tf.common import exception +from onnx_tf.common.tf_helper import tf_shape +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description + + +@onnx_op("Resize") +@partial_support(True) +@ps_description( + "Resize required 4D input in Tensorflow. " + + "For opset 11, only the following attributes and inputs " + + "conbination are supported in Tensorflow:\n\t1. mode=nearest, " + + "coordinate_transformation_mode=align_corners, nearest_mode=" + + "round_prefer_ceil, can use scales(*) or sizes.\n" + + "\t2. mode=nearest, coordinate_transformation_mode=asymmetric, " + + "nearest_mode=floor, can use scales(*) or sizes.\n" + + "\t3. mode=nearest, coordinate_transformation_mode=" + + "tf_half_pixel_for_nn, nearest_mode=floor, can use scales(*) " + + "or sizes.\n\t4. mode=linear, coordinate_transformation_mode=" + + "align_corners, can use scales(*) or sizes.\n\t5. mode=linear, " + + "coordinate_transformation_mode=asymmetric, can use scales(*) " + + "or sizes.\n\t6. mode=linear, coordinate_transformation_mode=" + + "half_pixel, can use scales(*) or sizes.\n\t7. mode=cubic, " + + "coordinate_transformation_mode=align_corners, " + + "cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) " + + "or sizes.\n\t8. mode=cubic, coordinate_transformation_mode=" + + "asymmetric, cubic_coeff_a=-0.5, exclude_outside=1, can use " + + "scales(*) or sizes.\n\t9. mode=cubic, coordinate_transformation_mode=" + + "half_pixel, cubic_coeff_a=-0.5, exclude_outside=1, can use " + + "scales(*) or sizes.\n\t10. mode=nearest, " + + "coordinate_transformation_mode=tf_crop_and_resize, " + + "extrapolation_value=any_float_value, nearest_mode=round_prefer_ceil, " + + "can use scales or sizes.\n\t11. mode=linear, " + + "coordinate_transformation_mode=tf_crop_and_resize, " + + "extrapolation_value=any_float_value, can use scales or sizes." + + "\n\t- Note (*): The accuracy of your model will go down, if the height and " + + "the width of the new sizes(scales * origial sizes) are not in whole numbers." +) +class Resize(BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_shape = x.get_shape().as_list() + if len(x_shape) != 4: + exception.OP_UNSUPPORTED_EXCEPT("Resize required 4D input", "Tensorflow") + if cls.SINCE_VERSION >= 11: + # supported attributes combination + # ____________________________________________________________________________________________________________________________________________________ + # | mode | coordinate_transformation_mode | cubic_coeff_a | exclude_outside | extrapolation_value | nearest_mode | scales | sizes | + # |_________|________________________________|_______________|_________________|_____________________|___________________|_______________|___________| + # | nearest | align_corners | not apply | 0 | not apply | round_prefer_ceil | supported (1) | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | nearest | asymmetric | not apply | 0 | not apply | floor | supported (1) | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | nearest | tf_half_pixel_for_nn | not apply | 0 | not apply | floor | supported (1) | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | linear | align_corners | not apply | 0 | not apply | not apply | supported (1) | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | linear | asymmetric | not apply | 0 | not apply | not apply | supported (1) | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | linear | half_pixel | not apply | 0 | not apply | not apply | supported (1) | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | cubic | align_corners | -0.5 | 1 | not apply | not apply | supported (1) | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | cubic | asymmetric | -0.5 | 1 | not apply | not apply | supported (1) | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | cubic | half_pixel | -0.5 | 1 | not apply | not apply | supported (1) | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | nearest | tf_crop_and_resize | not apply | 0 | any float value | round_prefer_ceil | supported | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # | linear | tf_crop_and_resize | not apply | 0 | any float value | not apply | supported | supported | + # |---------|--------------------------------|---------------|-----------------|---------------------|-------------------|---------------|-----------| + # Note: + # 1. The accuracy of your model will go down, if the height and the width of the new sizes(scales * origial sizes) are not in whole numbers. + coordinate_transformation_mode = node.attrs.get( + "coordinate_transformation_mode", "half_pixel") + cubic_coeff_a = node.attrs.get("cubic_coeff_a", -0.75) + exclude_outside = node.attrs.get("exclude_outside", 0) + mode = node.attrs.get("mode", "nearest") + nearest_mode = node.attrs.get("nearest_mode", "round_prefer_floor") + if coordinate_transformation_mode == "pytorch_half_pixel": + exception.OP_UNSUPPORTED_EXCEPT( + "Resize coordinate_transformation_mode=pytorch_half_pixel", + "Tensorflow") + if (coordinate_transformation_mode == "half_pixel" and mode == "nearest" + ) or (coordinate_transformation_mode == "tf_half_pixel_for_nn" and + mode in ["linear", "cubic"]) or ( + coordinate_transformation_mode == "tf_crop_and_resize" and + mode == "cubic"): + exception.OP_UNSUPPORTED_EXCEPT( + "Resize coordinate_transformation_mode=" + + coordinate_transformation_mode + " and mode=" + mode, "Tensorflow") + if (exclude_outside == 1 and + mode in ["nearest", "linear"]) or (exclude_outside == 0 and + mode == "cubic"): + exception.OP_UNSUPPORTED_EXCEPT( + "Resize mode=" + mode + " and exclude_outside=" + + str(exclude_outside), "Tensorflow") + if cubic_coeff_a != -0.5 and mode == "cubic": + exception.OP_UNSUPPORTED_EXCEPT( + "Resize mode=cubic and cubic_coeff_a=" + cubic_coeff_a, + "Tensorflow") + if mode == "nearest": + if (nearest_mode in [ + "round_prefer_floor", "ceil" + ]) or (coordinate_transformation_mode in [ + "align_corners", "tf_crop_and_resize" + ] and nearest_mode == "floor") or (coordinate_transformation_mode in [ + "asymmetric", "tf_half_pixel_for_nn" + ] and nearest_mode == "round_prefer_ceil"): + exception.OP_UNSUPPORTED_EXCEPT( + "Resize coordinate_transformation_mode=" + + coordinate_transformation_mode + + ", mode=nearest and nearest_mode=" + nearest_mode, "Tensorflow") + + @classmethod + def version_10(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_shape = x.get_shape().as_list() + scales = kwargs["tensor_dict"][node.inputs[1]] + + n_in_scales_is_one = tf.equal(scales[0], 1) + c_in_scales_is_one = tf.logical_or(tf.equal(scales[1], 1), + tf.equal(scales[3], 1)) + assert_n_c_in_scales_are_ones = tf.Assert( + tf.logical_and(n_in_scales_is_one, c_in_scales_is_one), [scales]) + + with tf.control_dependencies([assert_n_c_in_scales_are_ones]): + x_in_NCHW_format = tf.equal(scales[1], 1) + h_w_scale = tf.where(x_in_NCHW_format, scales[2:], scales[1:3]) + h_w_shape = tf.where(x_in_NCHW_format, x_shape[2:], x_shape[1:3]) + new_h_w_shape = tf.cast(h_w_scale * tf.cast(h_w_shape, scales.dtype), + tf.int32) + + mode = node.attrs.get("mode", "nearest") + if mode.lower() == "linear": + mode = tf.image.ResizeMethod.BILINEAR + else: + mode = tf.image.ResizeMethod.NEAREST_NEIGHBOR + + def process_NCHW_format(x): + x_t = tf.transpose(x, perm=[0, 2, 3, 1]) + y = tf.image.resize_images(x_t, size=new_h_w_shape, method=mode) + y_t = tf.transpose(y, perm=[0, 3, 1, 2]) + return y_t + + def process_NHWC_format(x): + y = tf.image.resize_images(x, size=new_h_w_shape, method=mode) + return y + + output = tf.cond(x_in_NCHW_format, lambda: process_NCHW_format(x), + lambda: process_NHWC_format(x)) + + return [output] + + @classmethod + def version_11(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + x_shape = tf_shape(x) + roi = tensor_dict[node.inputs[1]] + scales = tensor_dict[node.inputs[2]] + sizes = tensor_dict[node.inputs[3]] if len( + node.inputs) == 4 else tf.constant([], dtype=tf.int64) + coordinate_transformation_mode = node.attrs.get( + "coordinate_transformation_mode", "half_pixel") + extrapolation_value = node.attrs.get("extrapolation_value", 0.0) + mode = node.attrs.get("mode", "nearest") + + param = scales if len(node.inputs) == 3 else sizes + n_in_param_is_one = tf.equal(param[0], 1) + c_in_param_is_one = tf.logical_or(tf.equal(param[1], 1), + tf.equal(param[3], 1)) + assert_n_c_in_param_are_ones = tf.Assert( + tf.logical_and(n_in_param_is_one, c_in_param_is_one), [param]) + + with tf.control_dependencies([assert_n_c_in_param_are_ones]): + if mode.lower() == "linear": + tf_resize = tf.image.resize_bilinear + mode = "bilinear" + elif mode.lower() == "cubic": + tf_resize = tf.image.resize_bicubic + else: + tf_resize = tf.image.resize_nearest_neighbor + + x_in_NCHW_format = tf.equal(param[1], 1) + + if len(node.inputs) == 3: # only scales is defined + h_w_scale = tf.where(x_in_NCHW_format, scales[2:], scales[1:3]) + h_w_shape = tf.where(x_in_NCHW_format, x_shape[2:], x_shape[1:3]) + new_size = tf.cast(h_w_scale * tf.cast(h_w_shape, scales.dtype), + tf.int32) + else: # sizes is defined + # The number of elements of 'sizes' should be the same as the rank of input 'X' + sizes.set_shape(x_shape.shape) + new_size = tf.cast(tf.where(x_in_NCHW_format, sizes[2:], sizes[1:3]), + tf.int32) + # Tensorflow require the shape of "size" in the "tf.image.resize" must be known at + # graph creation time. However in the dynamic shape situation, the shape of "new_size" + # will be "None", the actual shape can only be determine at runtime. But we know + # "new_size" should always contain [h, w], therefore the shape must be 2. + new_size.set_shape([2]) + + def get_NCHW_boxes(): + indices = [] + x_rank = len(x.get_shape()) + for i in range(2, x_rank): + indices.insert(i - 2, i) + indices.insert(i, i + x_rank) + return tf.expand_dims(tf.gather(roi, indices, axis=0), 0) + + def get_NHWC_boxes(): + indices = [] + x_rank = len(x.get_shape()) + for i in range(1, x_rank - 1): + indices.insert(i - 1, i) + indices.insert(i + 1, i + x_rank) + return tf.expand_dims(tf.gather(roi, indices, axis=0), 0) + + box_indices = tf.cast(tf.range(0, x_shape[0]), dtype=tf.int32) + + def process_NCHW_format(): + x_t = tf.transpose(x, perm=[0, 2, 3, 1]) + if coordinate_transformation_mode == "tf_crop_and_resize": + boxes = get_NCHW_boxes() + y = tf.image.crop_and_resize(x_t, boxes, box_indices, new_size, mode, + extrapolation_value) + elif coordinate_transformation_mode == "align_corners": + y = tf_resize(x_t, + size=new_size, + align_corners=True, + half_pixel_centers=False) + elif coordinate_transformation_mode == "asymmetric": + y = tf_resize(x_t, + size=new_size, + align_corners=False, + half_pixel_centers=False) + else: # half_pixel or tf_half_pixel_for_nn + y = tf_resize(x_t, + size=new_size, + align_corners=False, + half_pixel_centers=True) + return tf.transpose(y, perm=[0, 3, 1, 2]) + + def process_NHWC_format(): + if coordinate_transformation_mode == "tf_crop_and_resize": + boxes = get_NHWC_boxes() + return tf.image.crop_and_resize(x, boxes, box_indices, new_size, mode, + extrapolation_value) + elif coordinate_transformation_mode == "align_corners": + return tf_resize(x, + size=new_size, + align_corners=True, + half_pixel_centers=False) + elif coordinate_transformation_mode == "asymmetric": + return tf_resize(x, + size=new_size, + align_corners=False, + half_pixel_centers=False) + else: # half_pixel or tf_half_pixel_for_nn + return tf_resize(x, + size=new_size, + align_corners=False, + half_pixel_centers=True) + + output = tf.cond(x_in_NCHW_format, process_NCHW_format, + process_NHWC_format) + + return [output] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reverse_sequence.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reverse_sequence.py new file mode 100644 index 0000000..07e069e --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/reverse_sequence.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("ReverseSequence") +@tf_func(tf.reverse_sequence) +class ReverseSequence(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"time_axis": 0, "batch_axis": 1}, + "rename": {"time_axis": "seq_axis"}} + + @classmethod + def version_10(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/rnn.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/rnn.py new file mode 100644 index 0000000..02b4ca8 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/rnn.py @@ -0,0 +1,161 @@ +from functools import partial + +import tensorflow as tf + +from onnx_tf.common import get_unique_suffix +from onnx_tf.common import exception +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from .rnn_mixin import RNNMixin + + +@onnx_op("RNN") +@partial_support(True) +@ps_description("RNN with clip is not supported in Tensorflow.") +class RNN(RNNMixin, BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + if "clip" in node.attrs: + exception.OP_UNSUPPORTED_EXCEPT("RNN with clip", "Tensorflow") + + @classmethod + def _custom_getter(cls, + getter, + name, + node=None, + tensor_dict=None, + is_bidirectional=None, + *args, + **kwargs): + names = name.split("/") + if is_bidirectional: + if "fw" in names: + index = 0 + elif "bw" in names: + index = 1 + else: + raise RuntimeError("Can not get {} for bidirectional. " + "Either fw and bw is not in name scope.".format( + names[-1])) + if names[-1] == "kernel": + if is_bidirectional: + w = tf.split(tensor_dict[node.inputs[1]], 2)[index] + r = tf.split(tensor_dict[node.inputs[2]], 2)[index] + else: + w = tensor_dict[node.inputs[1]] + r = tensor_dict[node.inputs[2]] + new_w = tf.transpose(tf.squeeze(w)) + new_r = tf.transpose(tf.squeeze(r)) + kernel = tf.concat([new_w, new_r], 0) + return kernel + if names[-1] == "bias": + if len(node.inputs) >= 4: + if is_bidirectional: + b = tf.split(tensor_dict[node.inputs[3]], 2)[index] + else: + b = tensor_dict[node.inputs[3]] + w_b, r_b = tf.split(tf.squeeze(b), 2) + w_b = tf.transpose(w_b) + r_b = tf.transpose(r_b) + return tf.add(w_b, r_b) + return getter(name, *args, **kwargs) + return getter(name, *args, **kwargs) + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + input_shape = x.get_shape().as_list() + input_size = len(node.inputs) + hidden_size = node.attrs["hidden_size"] + direction = node.attrs.get("direction", "forward") + num_directions = 2 if direction == "bidirectional" else 1 + + output_sequence = node.attrs.get("output_sequence", 0) + + # TODO(fumihwh): check if prev node is one of RNN + # process input if it comes from other previous cell + # which has shape [seq_length, num_directions, batch_size, hidden_size] + if len(input_shape) == 4 and input_shape[1] == 1: + x = tf.squeeze(x) + + sequence_length = None + if input_size >= 5 and node.inputs[4] in tensor_dict: + sequence_length = tensor_dict[node.inputs[4]] + + cell_kwargs = {} + + tf_activations = [tf.nn.tanh] + if "activations" in node.attrs: + activations = list(map(lambda x: x.lower(), node.attrs["activations"])) + activation_alpha = node.attrs.get("activation_alpha", [None] * 2) + activation_beta = node.attrs.get("activation_beta", [None] * 2) + tf_activations = [ + cls.rnn_get_activation(activations[0], activation_alpha[0], + activation_beta[0]) + ] + if num_directions == 2: + tf_activations.append( + cls.rnn_get_activation(activations[1], activation_alpha[1], + activation_beta[1])) + + # TODO(fumihwh): check if reverse and bidirectional works + with tf.variable_scope( + "RNN_" + get_unique_suffix(), + custom_getter=partial( + cls._custom_getter, + node=node, + tensor_dict=tensor_dict, + is_bidirectional=num_directions == 2)): + + cell_kwargs["num_units"] = hidden_size + initial_state = None + initial_state_bw = None + if input_size == 6: + initial_h = tensor_dict.get(node.inputs[5], None) + if initial_h is not None: + initial_state = (initial_h[0],) + if num_directions == 2: + initial_state_bw = (initial_h[1],) + + rnn_kwargs = {} + if num_directions == 1: + rnn_kwargs["initial_state"] = initial_state + elif num_directions == 2: + rnn_kwargs["initial_state_fw"] = initial_state + rnn_kwargs["initial_state_bw"] = initial_state_bw + rnn_kwargs["sequence_length"] = sequence_length + rnn_kwargs["time_major"] = True + rnn_kwargs["dtype"] = tf.float32 + + outputs, states = cls.rnn(x, tf.nn.rnn_cell.BasicRNNCell, cell_kwargs, + rnn_kwargs, tf_activations, direction) + + if num_directions == 1: + state = states[0] + h = tf.expand_dims(state, 0) + output = tf.expand_dims(outputs, 1) + else: + state_fw = states[0][0] + state_bw = states[1][0] + output_fw = outputs[0] + output_bw = outputs[1] + h_fw = tf.expand_dims(state_fw, 0) + h_bw = tf.expand_dims(state_bw, 0) + h = tf.concat((h_fw, h_bw), axis=0) + output_fw = tf.expand_dims(output_fw, 1) + output_bw = tf.expand_dims(output_bw, 1) + output = tf.concat((output_fw, output_bw), axis=1) + + return [output, h] if output_sequence == 0 else [h] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/rnn_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/rnn_mixin.py new file mode 100644 index 0000000..3cd5852 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/rnn_mixin.py @@ -0,0 +1,86 @@ +from functools import partial + +import tensorflow as tf +# import tensorflow_probability as tfp +from tensorflow.python.ops import array_ops + +from onnx_tf.common import exception + + +class RNNMixin(object): + + ONNX_ACTIVATION_MAPPING = { + # Added from tf 1.8 + # "affine": tf.contrib.distributions.bijectors.AffineScalar, + # tf.contrib was removed since tf 2.0, + # Class Affine had been move to the following module + # "affine": tfp.bijectors.Affine, + "elu": tf.nn.elu, + "hard_sigmoid": tf.keras.backend.hard_sigmoid, + "leaky_relu": tf.nn.leaky_relu, + "relu": tf.nn.relu, + "sigmoid": tf.sigmoid, + "softsign": tf.nn.softsign, + "softplus": tf.nn.softplus, + "tanh": tf.tanh, + "thresholded_relu": tf.keras.layers.ThresholdedReLU, + } + + @classmethod + def rnn(cls, x, cell_class, cell_kwargs, rnn_kwargs, activations, direction): + cell_kwargs["activation"] = activations[0] + + rnn_cell = [cell_class(**cell_kwargs)] + cell_fw = tf.nn.rnn_cell.MultiRNNCell(rnn_cell) + + if direction == "bidirectional": + cell_kwargs["activation"] = activations[1] + rnn_cell_bw = [cell_class(**cell_kwargs)] + cell_bw = tf.nn.rnn_cell.MultiRNNCell(rnn_cell_bw) + + if direction == "forward": + outputs, states = tf.nn.dynamic_rnn(cell_fw, x, **rnn_kwargs) + elif direction == "bidirectional": + outputs, states = tf.nn.bidirectional_dynamic_rnn(cell_fw, cell_bw, x, + **rnn_kwargs) + elif direction == "reverse": + + def _reverse(input_, seq_dim): + return array_ops.reverse(input_, axis=[seq_dim]) + + time_dim = 0 + inputs_reverse = _reverse(x, time_dim) + outputs, states = tf.nn.dynamic_rnn(cell_fw, inputs_reverse, **rnn_kwargs) + outputs = _reverse(outputs, time_dim) + + return outputs, states + + @classmethod + def rnn_get_activation(cls, name, alpha, beta): + if name not in cls.ONNX_ACTIVATION_MAPPING: + exception.OP_UNSUPPORTED_EXCEPT( + "Activation function {} for {}".format(name, cls.__name__), + "Tensorflow") + activation = cls.ONNX_ACTIVATION_MAPPING[name] + kwargs = {} + if name == "affine": + kwargs["scale"] = alpha + kwargs["shift"] = beta + activation = activation(**kwargs) + elif name == "elu": + if alpha != 1: + exception.OP_UNSUPPORTED_EXCEPT( + "Activation function {} with alpha={} for {}".format( + name, alpha, cls.__name__), "Tensorflow") + elif name == "hard_sigmoid": + if alpha != 0.2 or beta != 0.5: + exception.OP_UNSUPPORTED_EXCEPT( + "Activation function {} with alpha={}, beta={} for {}".format( + name, alpha, beta, cls.__name__), "Tensorflow") + elif name == "leaky_relu": + kwargs["alpha"] = alpha or 0.01 + activation = partial(activation, **kwargs) + elif name == "thresholded_relu": + kwargs["theta"] = alpha + activation = activation(**kwargs) + return activation diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/round.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/round.py new file mode 100644 index 0000000..28dba15 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/round.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Round") +@tf_func(tf.round) +class Round(BasicMathMixin, BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scan.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scan.py new file mode 100644 index 0000000..4bc7644 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scan.py @@ -0,0 +1,24 @@ +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .scan_mixin import ScanMixin + + +@onnx_op("Scan") +class Scan(ScanMixin, BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + return cls.scan(node, kwargs["tensor_dict"], + kwargs.get("strict", True)) + + @classmethod + def version_8(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_9(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scan_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scan_mixin.py new file mode 100644 index 0000000..3fd8dab --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scan_mixin.py @@ -0,0 +1,188 @@ +import tensorflow as tf +from onnx.helper import make_opsetid +import onnx_tf +from onnx_tf.common import data_type + + +class ScanMixin(object): + + @classmethod + def scan(cls, node, input_dict, strict): + current_opset = [make_opsetid(cls.DOMAIN, cls.VERSION)] + + body = node.attrs["body"] + + # in version 8, node.inputs[0] is the sequence_lens + node_inputs = node.inputs if cls.SINCE_VERSION != 8 else \ + node.inputs[1:] + # M + num_scan_inputs = int(node.attrs["num_scan_inputs"]) + # N = num_inputs - M + num_state_vars = len(node_inputs) - num_scan_inputs + # K = num_outputs - N + num_scan_outputs = len(node.outputs) - num_state_vars + + """ + Function to run subgraph used with tf.scan + """ + + def run_subgraph(a, b): + input_values = {} + # set the input values for the subgraph + # set the values for the state variables + for i in range(num_state_vars): + input_values[body.input[i].name] = a[i] + # set the values for the scan inputs + for i in range(num_scan_inputs): + input_values[body.input[i + num_state_vars].name] = b[i] + + # get the tensor operations for the onnx graph + subgraph_tensor_dict = onnx_tf.backend.onnx_graph_to_tensorflow_ops( + subgraph=body, + input_values=input_values, + tensor_dict=input_dict, + opset=current_opset, + strict=strict) + # return sequence of tensors for every subgraph output + outputs = [subgraph_tensor_dict[output.name] for output in body.output] + return outputs + + scan_input_axes = node.attrs.get("scan_input_axes", [0] * num_scan_inputs) + scan_input_directions = node.attrs.get( + "directions" if cls.SINCE_VERSION == 8 else "scan_input_directions", + [0] * num_scan_inputs) + scan_output_axes = node.attrs.get("scan_output_axes", + [0] * num_scan_outputs) + scan_output_directions = node.attrs.get("scan_output_directions", + [0] * num_scan_outputs) + + # if version 8 read the sequnce_lens from the first input + if cls.SINCE_VERSION == 8: + sequence_lens = input_dict[node.inputs[0]] \ + if node.inputs[0] != '' else None + + inputs = [input_dict[node_input] for node_input in node_inputs] + + scan_inputs = inputs[num_state_vars:] + # loop over all the scan inputs and apply transpose depending + # on input axes provided and also reverse the scan inputs if + # reverse direction for scan is provided + for i in range(num_scan_inputs): + # if input axes are different than 0, use transpose to scan over + # the provided axes + if scan_input_axes[i] != 0: + transpose_perm = cls._calc_transpose_perm_input(tf.rank(scan_inputs[i]), + scan_input_axes[i]) + scan_inputs[i] = tf.transpose(scan_inputs[i], transpose_perm) + + # check for reverse direction scans + if scan_input_directions[i] == 1: + # version 8 has a batch dimension + axis = 0 if cls.SINCE_VERSION != 8 else 1 + scan_inputs[i] = tf.reverse(scan_inputs[i], [axis]) + + state_vars_init = inputs[:num_state_vars] + + scan_outputs_init = [] + # generate sequence of zero tensors for all scan outputs + # with the correct shape and dtype + for scan_output in body.output[num_state_vars:]: + tensor_type = scan_output.type.tensor_type + shape = [ + d.dim_value if (d.dim_value > 0 and d.dim_param == "") else None + for d in tensor_type.shape.dim + ] + dtype = data_type.onnx2tf(tensor_type.elem_type) + scan_outputs_init.append(tf.zeros(shape, dtype=dtype)) + + # tf.scan initilizer is state_variables_init + scan_outputs_init + initializer = state_vars_init + scan_outputs_init + + if cls.SINCE_VERSION == 8: + # version == 8 + # function to process the batches. it is used with tf.map_fn + def run_batches(x): + # state vars initial values per batch + initial = x[0] + # scan inputs per batch + scan_inputs = x[1] + # sequence length for the batch + seq_len = x[2] + + # slice the input to the current sequence len + scan_inputs = [scan_input[:seq_len, ...] for scan_input in scan_inputs] + + # run scan on the current batch + out = tf.scan(run_subgraph, + scan_inputs, + initializer=initial + scan_outputs_init) + + # pad to the original shape with zeros + paddings = [[0, tf.shape(x[1][0], out_type=seq_len.dtype)[0] - seq_len]] + for i in range(len(out)): + pads = tf.concat( + [paddings, + tf.zeros([(tf.rank(out[i]) - 1), 2], dtype=tf.int32)], + axis=0) + out[i] = tf.pad(out[i], pads) + return out + + if sequence_lens is None: + # if sequence_lens is None, fill it with the shape of + # the input axis 1 + sequence_lens = tf.fill([tf.shape(scan_inputs[0])[0]], + tf.shape(scan_inputs[0], out_type=tf.int32)[1]) + + output_types = [ + data_type.onnx2tf(output.type.tensor_type.elem_type) + for output in body.output + ] + # run scan for every batch + out = tf.map_fn(run_batches, + (state_vars_init, scan_inputs, sequence_lens), + dtype=output_types) + + state_vars_outputs = [] + # extract the final values of the state variables + for state_var in out[:num_state_vars]: + state_vars_outputs.append( + tf.map_fn(lambda x: x[0][x[1] - 1], (state_var, sequence_lens), + state_var.dtype)) + else: + # version > 8 + # run the scan + out = tf.scan(run_subgraph, scan_inputs, initializer=initializer) + + # extract the final values of the state variables + state_vars_outputs = [ + state_var[tf.shape(state_var)[0] - 1] + for state_var in out[:num_state_vars] + ] + + scan_outputs = out[num_state_vars:] + + # post process the scan outputs depending on the directions and + # axes provided. + for i in range(num_scan_outputs): + # check for reverse direction scan outputs + if scan_output_directions[i] == 1: + scan_outputs[i] = tf.reverse(scan_outputs[i], [0]) + + if scan_output_axes[i] != 0: + transpose_perm = cls._calc_transpose_perm_output( + tf.rank(scan_outputs[i]), scan_output_axes[i]) + scan_outputs[i] = tf.transpose(scan_outputs[i], transpose_perm) + + return state_vars_outputs + scan_outputs + + @classmethod + def _calc_transpose_perm_input(cls, rank, axis): + if axis < 0: + axis = rank + axis + return tf.concat([[axis], tf.range(axis), tf.range(axis + 1, rank)], 0) + + @classmethod + def _calc_transpose_perm_output(cls, rank, axis): + if axis < 0: + axis = rank + axis + return tf.concat([tf.range(1, axis + 1), [0], tf.range(axis + 1, rank)], 0) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter.py new file mode 100644 index 0000000..67c8596 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter.py @@ -0,0 +1,12 @@ +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + +from onnx_tf.handlers.backend.scatter_elements import ScatterElements + + +@onnx_op("Scatter") +class Scatter(BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + return ScatterElements.version_11(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter_elements.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter_elements.py new file mode 100644 index 0000000..03ea802 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter_elements.py @@ -0,0 +1,64 @@ +import tensorflow as tf + +from onnx_tf.common.tf_helper import tf_shape +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .gather_and_scatter_mixin import GatherAndScatterMixin + + +@onnx_op("ScatterElements") +class ScatterElements(GatherAndScatterMixin, BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + axis = node.attrs.get("axis", 0) + data = kwargs["tensor_dict"][node.inputs[0]] + indices = kwargs["tensor_dict"][node.inputs[1]] + updates = kwargs["tensor_dict"][node.inputs[2]] + + # poocess negative axis + axis = axis if axis >= 0 else tf.add(tf.rank(data), axis) + + # check are there any indices are out of bounds + result = cls.chk_idx_out_of_bounds_along_axis(data, axis, indices) + msg = 'ScatterElements indices are out of bounds, please double check the indices and retry.' + with tf.control_dependencies([tf.compat.v1.assert_equal(result, True, message=msg)]): + # process negative indices + indices = cls.process_neg_idx_along_axis(data, axis, indices) + + # Calculate shape of the tensorflow version of indices tensor. + sparsified_dense_idx_shape = tf_shape(updates) + + # Move on to convert ONNX indices to tensorflow indices in 2 steps: + # + # Step 1: + # What would the index tensors look like if updates are all + # dense? In other words, produce a coordinate tensor for updates: + # + # coordinate[i, j, k ...] = [i, j, k ...] + # where the shape of "coordinate" tensor is same as that of updates. + # + # Step 2: + # But the coordinate tensor needs some correction because coord + # vector at position axis is wrong (since we assumed update is dense, + # but it is not at the axis specified). + # So we update coordinate vector tensor elements at psotion=axis with + # the sparse coordinate indices. + + idx_tensors_per_axis = tf.meshgrid(*list( + map(lambda x: tf.range(x, dtype=tf.dtypes.int64), + sparsified_dense_idx_shape)), + indexing='ij') + idx_tensors_per_axis[axis] = indices + dim_expanded_idx_tensors_per_axis = list( + map(lambda x: tf.expand_dims(x, axis=-1), idx_tensors_per_axis)) + coordinate = tf.concat(dim_expanded_idx_tensors_per_axis, axis=-1) + + # Now the coordinate tensor is in the shape + # [updates.shape, updates.rank] + # we need it to flattened into the shape: + # [product(updates.shape), updates.rank] + indices = tf.reshape(coordinate, [-1, tf.rank(data)]) + updates = tf.reshape(updates, [-1]) + + return [tf.tensor_scatter_nd_update(data, indices, updates)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter_nd.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter_nd.py new file mode 100644 index 0000000..51cc40d --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/scatter_nd.py @@ -0,0 +1,20 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from .gather_and_scatter_mixin import GatherAndScatterMixin + + +@onnx_op("ScatterND") +class ScatterND(GatherAndScatterMixin, BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + data = kwargs["tensor_dict"][node.inputs[0]] + indices = kwargs["tensor_dict"][node.inputs[1]] + updates = kwargs["tensor_dict"][node.inputs[2]] + + result = cls.chk_idx_out_of_bounds(data, indices) + msg = 'ScatterND indices are out of bounds, please double check the indices and retry.' + with tf.control_dependencies([tf.compat.v1.assert_equal(result, True, message=msg)]): + return [tf.tensor_scatter_nd_update(data, cls.process_neg_idx(data, indices), updates)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/selu.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/selu.py new file mode 100644 index 0000000..1bf31d2 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/selu.py @@ -0,0 +1,33 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Selu") +@tf_func(tf.nn.selu) +class Selu(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + if "alpha" not in node.attrs and "gamma" not in node.attrs: + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + x = tensor_dict[node.inputs[0]] + alpha = node.attrs.get("alpha", 1.67326319217681884765625) + gamma = node.attrs.get("gamma", 1.05070102214813232421875) + + return [ + tf.clip_by_value(x, 0, tf.reduce_max(x)) * gamma + + (tf.exp(tf.clip_by_value(x, tf.reduce_min(x), 0)) - 1) * alpha * gamma + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_at.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_at.py new file mode 100644 index 0000000..79a25f6 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_at.py @@ -0,0 +1,45 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("SequenceAt") +class SequenceAt(BackendHandler): + + @classmethod + def chk_pos_in_bounds(cls, input_seq, pos): + """ + Check the position is in-bounds with respect to the sequence. + Accepted range for 'position' is in [-n, n - 1], where n is the + number of tensors in 'input_sequence'. + + :param input_seq: input sequence + :param pos: position of the output tensor + + :return: True if position is in-bounds or input length is dynamic. + """ + seq_length = input_seq.shape[0].value + if seq_length is None: + return True + + seq_length = tf.cast(seq_length, pos.dtype) + + cond1 = tf.greater_equal(pos, tf.negative(seq_length)) + cond2 = tf.less_equal(pos, seq_length - 1) + + # pos >= -n and pos < n + return tf.reduce_all(tf.logical_and(cond1, cond2)) + + @classmethod + def version_11(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + input_sequence = tensor_dict[node.inputs[0]] + position = tensor_dict[node.inputs[1]] + + # check whether position is in-bounds and assert if not + result = cls.chk_pos_in_bounds(input_sequence, position) + assert_pos = tf.Assert(tf.equal(result, True), [result]) + + with tf.control_dependencies([assert_pos]): + return [input_sequence[position]] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_construct.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_construct.py new file mode 100644 index 0000000..32aa33b --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_construct.py @@ -0,0 +1,26 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("SequenceConstruct") +class SequenceConstruct(BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + # create an empty sequence first + tensor_dict = kwargs["tensor_dict"] + dtype = tensor_dict[node.inputs[0]].dtype + input_sequence = tf.ragged.constant([], dtype=dtype) + + # insert tensors at the end of sequence + for i in range(len(node.inputs)): + input_tensor = tf.expand_dims(tensor_dict[node.inputs[i]], 0) + if input_sequence.shape[0] == 0: + output_seq = tf.RaggedTensor.from_tensor(input_tensor) + else: + output_seq = tf.concat([input_sequence, input_tensor], axis=0) + input_sequence = output_seq + + return [output_seq] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_empty.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_empty.py new file mode 100644 index 0000000..5609830 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_empty.py @@ -0,0 +1,20 @@ +import numpy as np +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.common import data_type +from onnx import mapping + + +@onnx_op("SequenceEmpty") +class SequenceEmpty(BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + default_dtype = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype('float32')] + dtype = data_type.onnx2tf(node.attrs.get("dtype", default_dtype)) + + ragged = tf.RaggedTensor.from_row_lengths(values=[], row_lengths=[]) + sparse = tf.cast(ragged.to_sparse(), dtype) + return [tf.RaggedTensor.from_sparse(sparse)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_erase.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_erase.py new file mode 100644 index 0000000..f773547 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_erase.py @@ -0,0 +1,45 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("SequenceErase") +class SequenceErase(BackendHandler): + + @classmethod + def chk_pos_in_bounds(cls, input_seq, pos): + """ + Check the position is in-bounds with respect to the sequence. + Accepted range for 'position' is in [-n, n - 1], where n is the + number of tensors in 'input_sequence'. + + :param input_seq: input sequence + :param pos: position of the output tensor + + :return: True if position is in-bounds + """ + seq_length = tf.shape(input_seq.to_sparse(), out_type=pos.dtype)[0] + + cond1 = tf.greater_equal(pos, tf.negative(seq_length)) + cond2 = tf.less_equal(pos, seq_length - 1) + + # pos >= -n and pos < n + return tf.reduce_all(tf.logical_and(cond1, cond2)) + + @classmethod + def version_11(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + input_sequence = tensor_dict[node.inputs[0]] + seq_length = tf.shape(input_sequence.to_sparse())[0] + position = tensor_dict[node.inputs[1]] if len( + node.inputs) == 2 else seq_length - 1 + + # check whether position is in-bounds and assert if not + result = cls.chk_pos_in_bounds(input_sequence, position) + assert_pos = tf.Assert(tf.equal(result, True), [result]) + + with tf.control_dependencies([assert_pos]): + s1 = input_sequence[:position] + s2 = input_sequence[position + 1:] + return [tf.concat([s1, s2], axis=0)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_insert.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_insert.py new file mode 100644 index 0000000..45b5337 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_insert.py @@ -0,0 +1,52 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("SequenceInsert") +class SequenceInsert(BackendHandler): + + @classmethod + def chk_pos_in_bounds(cls, input_seq, pos): + """ + Check the position is in-bounds with respect to the sequence. + Accepted range for 'position' is in [-n, n], where n is the + number of tensors in 'input_sequence'. + + :param input_seq: input sequence + :param pos: position to insert the tensor + + :return: True if position is in-bounds. + """ + seq_length = tf.shape(input_seq.to_sparse(), out_type=pos.dtype)[0] + + cond1 = tf.greater_equal(pos, tf.negative(seq_length)) + cond2 = tf.less_equal(pos, seq_length) + + # pos >= -n and pos <= n + return tf.reduce_all(tf.logical_and(cond1, cond2)) + + @classmethod + def version_11(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + input_sequence = tensor_dict[node.inputs[0]] + input_tensor = tensor_dict[node.inputs[1]] + + position = tensor_dict[node.inputs[2]] if len( + node.inputs) > 2 else tf.shape(input_sequence.to_sparse())[0] + + # check whether position is in-bounds and assert if not + result = cls.chk_pos_in_bounds(input_sequence, position) + assert_pos = tf.Assert(tf.equal(result, True), [result]) + + with tf.control_dependencies([assert_pos]): + input_tensor = tf.expand_dims(input_tensor, 0) + if input_sequence.shape[0] == 0: + output_seq = tf.RaggedTensor.from_tensor(input_tensor) + else: + s1 = input_sequence[:position] + s2 = input_sequence[position:] + output_seq = tf.concat([s1, input_tensor, s2], axis=0) + + return [output_seq] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_length.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_length.py new file mode 100644 index 0000000..0cfc2b3 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sequence_length.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("SequenceLength") +class SequenceLength(BackendHandler): + + @classmethod + def version_11(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + input_sequence = tensor_dict[node.inputs[0]] + + return [tf.shape(input_sequence.to_sparse(), out_type=tf.int64)[0]] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/shape.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/shape.py new file mode 100644 index 0000000..a730f4e --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/shape.py @@ -0,0 +1,18 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Shape") +@tf_func(tf.shape) +class Shape(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"out_type": tf.int64}} + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/shrink.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/shrink.py new file mode 100644 index 0000000..d670217 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/shrink.py @@ -0,0 +1,36 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("Shrink") +class Shrink(BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + input_tensor = tensor_dict[node.inputs[0]] + input_shape = tf.shape(input_tensor, out_type=tf.int64) + + # handle defaults for attributes + lambd = node.attrs["lambd"] if "lambd" in node.attrs else 0.5 + bias = node.attrs["bias"] if "bias" in node.attrs else 0.0 + + # make tensors in the right shape + lambd_tensor = tf.fill(input_shape, tf.constant(lambd, input_tensor.dtype)) + lambd_neg_tensor = tf.fill(input_shape, + tf.constant(lambd * -1, input_tensor.dtype)) + bias_tensor = tf.fill(input_shape, tf.constant(bias, input_tensor.dtype)) + zeros_tensor = tf.zeros(input_shape, input_tensor.dtype) + + # prepare return values and conditions + input_plus = tf.add(input_tensor, bias_tensor) + input_minus = tf.subtract(input_tensor, bias_tensor) + greater_cond = tf.greater(input_tensor, lambd_tensor) + less_cond = tf.less(input_tensor, lambd_neg_tensor) + + return [ + tf.where(less_cond, input_plus, + tf.where(greater_cond, input_minus, zeros_tensor)) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sigmoid.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sigmoid.py new file mode 100644 index 0000000..36cc641 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sigmoid.py @@ -0,0 +1,18 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Sigmoid") +@tf_func(tf.nn.sigmoid) +class Sigmoid(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sign.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sign.py new file mode 100644 index 0000000..429b965 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sign.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Sign") +@tf_func(tf.sign) +class Sign(BasicMathMixin, BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sin.py new file mode 100644 index 0000000..2847524 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sin.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Sin") +@tf_func(tf.sin) +class Sin(BasicMathMixin, BackendHandler): + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sinh.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sinh.py new file mode 100644 index 0000000..c22f75a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sinh.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Sinh") +@tf_func(tf.sinh) +class Sinh(BasicMathMixin, BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/size.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/size.py new file mode 100644 index 0000000..185245f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/size.py @@ -0,0 +1,18 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Size") +@tf_func(tf.size) +class Size(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"out_type": tf.int64}} + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/slice.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/slice.py new file mode 100644 index 0000000..cc1bb13 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/slice.py @@ -0,0 +1,129 @@ +import numpy as np +import tensorflow as tf +try: + from tensorflow.math import floormod as tf_floormod +except ImportError: # for older tf-1.x versions + from tensorflow import floormod as tf_floormod + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Slice") +@tf_func(tf.strided_slice) +class Slice(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x = tensor_dict[node.inputs[0]] + + full_sizes = x.get_shape().as_list() + full_begin = [0] * len(full_sizes) + + starts = node.attrs.get("starts") + ends = node.attrs.get("ends") + slice_len = len(starts) + axes = node.attrs.get("axes", list(range(slice_len))) + + for i in range(slice_len): + starts[i] = full_sizes[ + axes[i]] + starts[i] if starts[i] < 0 else starts[i] + ends[i] = full_sizes[axes[i]] + ends[i] if ends[i] < 0 else ends[i] + if full_sizes[axes[i]] is not None: + ends[i] = np.min([full_sizes[axes[i]], ends[i]]) + starts[i] = np.min([full_sizes[axes[i]], starts[i]]) + full_begin[axes[i]] = starts[i] + full_sizes[axes[i]] = ends[i] - starts[i] + + return [ + cls.make_tensor_from_onnx_node( + node, + tf_func=tf.slice, + inputs=[ + tensor_dict[node.inputs[0]], + tf.constant(full_begin), + tf.constant(full_sizes) + ], + **kwargs) + ] + + @classmethod + def version_10(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + input_tensor = tensor_dict[node.inputs[0]] + starts = tensor_dict[node.inputs[1]] + ends = tensor_dict[node.inputs[2]] + + # first of all, get the input tensor shape + input_tensor_shape = tf.shape(input_tensor, out_type=ends.dtype) + + axes = tensor_dict[node.inputs[3]] if len( + node.inputs) >= 4 else tf.range(tf.shape(starts, out_type=ends.dtype)[0]) + + # process negative axes + input_rank = tf.cast(tf.rank(input_tensor), axes.dtype) + axes = tf_floormod(tf.add(axes, input_rank), input_rank) + + # expand a dimension of 1 at the end + sparse_indices = tf.expand_dims(axes, -1) + + # build the indexed dimension sizes as sparse_shape + sparse_shape = tf.gather_nd( + params=input_tensor_shape, indices=sparse_indices) + sparse_shape = tf.cast(sparse_shape, ends.dtype) + + # take care of starts, ends that are larger than the dim size. + starts_min = tf.minimum(starts, sparse_shape) + ends_min = tf.minimum(ends, sparse_shape) + + # take care of starts, ends that are negative + is_starts_negative = tf.less(starts_min, tf.zeros_like(starts_min)) + starts_final = tf.where(is_starts_negative, starts_min + sparse_shape, + starts_min) + is_ends_negative = tf.less(ends_min, tf.zeros_like(ends_min)) + ends_final = tf.where(is_ends_negative, ends_min + sparse_shape, ends_min) + + # need to densify everything for the inputs to slice + # the output shape is the input_tensor rank + output_shape = tf.reshape(tf.rank(input_tensor), [1]) + output_shape = tf.cast(output_shape, ends.dtype) + + # create dense tensor, pad 0 as default begins + dense_begins = tf.sparse_to_dense(sparse_indices, output_shape, + starts_final) + # create dense tensor, pad -1 for next step + dense_ends = tf.sparse_to_dense( + sparse_indices, + output_shape, + ends_final, + default_value=tf.constant(-1, dtype=dense_begins.dtype)) + # replace -1 with respective dimension sizes + dense_ends = tf.where( + tf.equal(dense_ends, tf.constant(-1, dtype=dense_begins.dtype)), + input_tensor_shape, dense_ends) + + # create dense tensor for steps if not already so + if len(node.inputs) >= 5: + dense_steps = tf.sparse_to_dense( + sparse_indices, + output_shape, + tensor_dict[node.inputs[4]], + default_value=tf.constant(1, dtype=tensor_dict[node.inputs[4]].dtype)) + else: + dense_steps = tf.ones(input_tensor_shape.shape, ends.dtype) + + return [ + cls.make_tensor_from_onnx_node( + node, + inputs=[ + tensor_dict[node.inputs[0]], dense_begins, dense_ends, + dense_steps + ], + **kwargs) + ] + + @classmethod + def version_11(cls, node, **kwargs): + return cls.version_10(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softmax.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softmax.py new file mode 100644 index 0000000..e729187 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softmax.py @@ -0,0 +1,35 @@ +import numpy as np +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Softmax") +@tf_func(tf.nn.softmax) +class Softmax(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + axis = node.attrs.get("axis", 1) + axis = axis if axis >= 0 else len(np.shape(x)) + axis + + if axis == len(np.shape(x)) - 1: + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + shape = tf.shape(x) + cal_shape = (tf.reduce_prod(shape[0:axis]), + tf.reduce_prod(shape[axis:tf.size(shape)])) + x = tf.reshape(x, cal_shape) + + return [tf.reshape(tf.nn.softmax(x), shape)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softplus.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softplus.py new file mode 100644 index 0000000..ba2e532 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softplus.py @@ -0,0 +1,14 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Softplus") +@tf_func(tf.nn.softplus) +class Softplus(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softsign.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softsign.py new file mode 100644 index 0000000..4a148cf --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/softsign.py @@ -0,0 +1,14 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Softsign") +@tf_func(tf.nn.softsign) +class Softsign(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/space_to_depth.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/space_to_depth.py new file mode 100644 index 0000000..fe079d0 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/space_to_depth.py @@ -0,0 +1,29 @@ +import copy + +import tensorflow as tf + +from onnx_tf.common import get_data_format +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("SpaceToDepth") +@tf_func(tf.space_to_depth) +class SpaceToDepth(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"rename": {"blocksize": "block_size"}} + + @classmethod + def version_1(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_rank = len(x.get_shape()) + storage_format, compute_format = get_data_format(x_rank) + attrs = copy.deepcopy(node.attrs) + attrs["data_format"] = storage_format + return [ + cls.make_tensor_from_onnx_node( + node, attrs=attrs, c_first_cuda_only=True, **kwargs) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/split.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/split.py new file mode 100644 index 0000000..680d38f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/split.py @@ -0,0 +1,56 @@ +import copy + +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Split") +@tf_func(tf.split) +class Split(BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + axis = node.attrs.get("axis", 0) + x_rank = len(kwargs["tensor_dict"][node.inputs[0]].get_shape().as_list()) + if axis > x_rank - 1 or axis < -x_rank: + raise ValueError("Axis is out of bound") + + @classmethod + def get_attrs_processor_param(cls): + return {"default": {"axis": 0}} + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + x_shape = tensor_dict[node.inputs[0]].get_shape().as_list() + attrs = copy.deepcopy(node.attrs) + axis = attrs.get("axis", 0) + axis = axis if axis >= 0 else len(x_shape) + axis + if "split" in node.attrs: + split = attrs["split"] + elif len(node.inputs) == 2: # since version 1 + split = tensor_dict[node.inputs[1]] + else: + per_part = x_shape[axis] / len(node.outputs) + if int(per_part) != per_part: + raise ValueError("Split can not be evenly divided.") + split = [int(per_part)] * len(node.outputs) + attrs["num_or_size_splits"] = split + return list( + cls.make_tensor_from_onnx_node( + node, inputs=[tensor_dict[node.inputs[0]]], attrs=attrs, **kwargs)) + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_2(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sqrt.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sqrt.py new file mode 100644 index 0000000..010c370 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sqrt.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Sqrt") +@tf_func(tf.sqrt) +class Sqrt(BasicMathMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/squeeze.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/squeeze.py new file mode 100644 index 0000000..ac53de7 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/squeeze.py @@ -0,0 +1,22 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Squeeze") +@tf_func(tf.squeeze) +class Squeeze(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"rename": {"axes": "axis"}} + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_11(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sub.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sub.py new file mode 100644 index 0000000..663e8ef --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sub.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ArithmeticMixin + + +@onnx_op("Sub") +@tf_func(tf.subtract) +class Sub(ArithmeticMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sum.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sum.py new file mode 100644 index 0000000..c7f749d --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/sum.py @@ -0,0 +1,33 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import ArithmeticMixin + + +@onnx_op("Sum") +@tf_func(tf.add_n) +class Sum(ArithmeticMixin, BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + tensor_dict = kwargs["tensor_dict"] + return [ + cls.make_tensor_from_onnx_node( + node, + inputs=[[tensor_dict.get(inp, None) for inp in node.inputs]], + **kwargs) + ] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_6(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_8(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tan.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tan.py new file mode 100644 index 0000000..b2eb463 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tan.py @@ -0,0 +1,15 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Tan") +@tf_func(tf.tan) +class Tan(BasicMathMixin, BackendHandler): + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tanh.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tanh.py new file mode 100644 index 0000000..a123e5a --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tanh.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .math_mixin import BasicMathMixin + + +@onnx_op("Tanh") +@tf_func(tf.tanh) +class Tanh(BasicMathMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tfidf_vectorizer.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tfidf_vectorizer.py new file mode 100644 index 0000000..051f336 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tfidf_vectorizer.py @@ -0,0 +1,136 @@ +import numpy as np +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("TfIdfVectorizer") +class TfIdfVectorizer(BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + if "pool_int64s" in node.attrs and "pool_strings" in node.attrs: + raise ValueError( + "Cannot set the pool_int64s and pool_strings in an input at the same time." + ) + + @classmethod + def _prepare_ngrams(cls, x, n, skip): + # This method transform input into n-grams for a specific skip + # input x is a 1D tensor + # ex1: x=[1,2,3,4] n=1 skip=0 output=[[1],[2],[3],[4]] + # ex2: x=[1,2,3,4] n=2 skip=0 output=[[1,2],[2,3],[3,4]] + # ex3: x=[1,2,3,4] n=2 skip=1 output=[[1,3],[2,4]] + count = x.shape[0] - n + 1 - skip + multiplier = skip + 1 + ngrams = [x[i * multiplier:i * multiplier + count] for i in range(n)] + ngrams = tf.stack(ngrams) + ngrams = tf.transpose(ngrams, [1, 0]) + return ngrams + + @classmethod + def _calc_ngram_skip(cls, x, pool, n, skip=0): + # This method calculates ngram counts for specific n and skip + + # Make pool into an array of ngrams + pool = np.reshape(pool, (int(len(pool) / n), n)) + + # Make input as an array of ngrams + new_x = cls._prepare_ngrams(x, n, skip) + + # Loop through the ngram targets in the pool + tensor_list = [] + for i in range(len(pool)): + # There is a pending issue in running tf.map_fn with strings + # on GPU, https://github.com/tensorflow/tensorflow/issues/28007 + # So this is a temporary solution to ensure tf.map_fn + # runs on CPU. Later can be removed once Tensorflow has the + # issue resolved. + with tf.device("/cpu:0"): + ngram_count = tf.map_fn(lambda in_x: tf.where( + tf.reduce_all( + tf.equal(in_x, tf.constant(pool[i], dtype=new_x.dtype))), + tf.constant([1]), tf.constant([0])), + new_x, + dtype=tf.int32) + ngram_count = tf.math.count_nonzero(ngram_count, dtype=tf.int32) + ngram_count = tf.reshape(ngram_count, [1]) + tensor_list.append(ngram_count) + + return tf.concat(tensor_list, 0) + + @classmethod + def _calc_ngram(cls, x, pool, n, max_skip): + # This method calculates ngram counts for a specific n and + # all allowable skips + + # For 1gram, skip is not in use. Not clearly described in ONNX + # spec, this code logic is based on observation of ONNX examples, + # tf_batch_uniandbigrams_skip5 and tf_uniandbigrams_skip5, + # where the 1-gram results [0, 3, 0, 0] and [0, 3, 1, 0] + # are not the accumulated counts from multiple skips. + if n == 1: + return cls._calc_ngram_skip(x, pool, n) + + # Loop through maximum allowable skip count and sum up the results + result = tf.zeros([int(len(pool) / n)], dtype=tf.int32) + max_allowable_skip = np.minimum(max_skip, + int((int(x.shape[0]) - 1) / (n - 1) - 1)) + + for skip in range(max_allowable_skip + 1): + # For each skip calculate the ngram counts + result += cls._calc_ngram_skip(x, pool, n, skip) + + return result + + @classmethod + def version_9(cls, node, **kwargs): + input_tensor = kwargs["tensor_dict"][node.inputs[0]] + mode = node.attrs.get("mode") + max_skip_count = node.attrs.get("max_skip_count") + min_gram_len = node.attrs.get("min_gram_length") + max_gram_len = node.attrs.get("max_gram_length") + ngram_counts = node.attrs.get("ngram_counts") + ngram_indexes = node.attrs.get("ngram_indexes") + pool_int64s = node.attrs.get("pool_int64s") + pool_strings = node.attrs.get("pool_strings") + weights = node.attrs.get("weights", np.ones(len(ngram_indexes))) + + def process_ngram(input_t): + # This is the main method that processes and produces ngram counts + # for one row of inputs regardless of the operator input dimension. + size = len(ngram_indexes) + new_ngram_counts = np.append(ngram_counts, size) + result_ngram = np.zeros(size) + for i in range(len(new_ngram_counts) - 1): + gram_len = i + 1 + count = new_ngram_counts[i + 1] - new_ngram_counts[i] + total_len = count * gram_len + if gram_len >= min_gram_len and gram_len <= max_gram_len: + idx = ngram_indexes[new_ngram_counts[i]:new_ngram_counts[i + 1]] + process_pool = pool_int64s[ + new_ngram_counts[i]:new_ngram_counts[i] + + total_len] if pool_int64s is not None else pool_strings[ + new_ngram_counts[i]:new_ngram_counts[i] + total_len] + result = cls._calc_ngram(input_t, process_pool, gram_len, + max_skip_count) + idx = tf.constant(idx, shape=[len(idx), 1]) + result_ngram = result_ngram + tf.scatter_nd(idx, result, [size]) + return result_ngram + + # The input can be either 1d or 2d. Need to loop through + # each element for 2d inputs + n = len(input_tensor.shape) + final_out = [ + process_ngram(input_tensor[i]) for i in range(input_tensor.shape[0]) + ] if n > 1 else process_ngram(input_tensor) + tf_out = tf.cast(final_out, tf.float32) + + # Apply the mode based of the TF output + if mode == 'IDF': + return [tf.minimum(tf_out, 1) * weights] + elif mode == 'TFIDF': + return [tf_out * weights] + else: + return [tf_out] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/thresholded_relu.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/thresholded_relu.py new file mode 100644 index 0000000..90a75ec --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/thresholded_relu.py @@ -0,0 +1,23 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op + + +@onnx_op("ThresholdedRelu") +class ThresholdedRelu(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + alpha = node.attrs.get("alpha", 1.0) + epsilon = 1e-5 + return [tf.nn.relu(x) - tf.nn.relu(tf.sign(alpha - x + epsilon) * x)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_10(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tile.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tile.py new file mode 100644 index 0000000..a170150 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/tile.py @@ -0,0 +1,29 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Tile") +@tf_func(tf.tile) +class Tile(BackendHandler): + + @classmethod + def get_attrs_processor_param(cls): + return {"rename": {"axes": "axis"}} + + @classmethod + def version_1(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_rank = len(x.get_shape()) + multiples = [1] * x_rank + axis = node.attrs["axis"] + tiles = node.attrs["tiles"] + multiples[axis] = tiles + inputs = [x, multiples] + return [cls.make_tensor_from_onnx_node(node, inputs=inputs, **kwargs)] + + @classmethod + def version_6(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/top_k.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/top_k.py new file mode 100644 index 0000000..665a767 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/top_k.py @@ -0,0 +1,80 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("TopK") +@tf_func(tf.nn.top_k) +class TopK(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_rank = len(x.get_shape()) + axes = list(range(x_rank)) + axis = node.attrs.get("axis", -1) + axis = axis if axis >= 0 else axis + x_rank + + if axis != x_rank - 1: + pre_perm = [a for a in axes if a != axis] + [axis] + post_perm = axes[:axis] + [x_rank - 1] + axes[axis:x_rank - 1] + x = tf.transpose(x, perm=pre_perm) + values, indices = tf.nn.top_k(x, k=node.attrs["k"]) + values = tf.transpose(values, perm=post_perm) + return [values, tf.cast(indices, dtype=tf.int64)] + + values, indices = tf.nn.top_k(x, k=node.attrs["k"]) + return [values, tf.cast(indices, dtype=tf.int64)] + + @classmethod + def version_10(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_rank = len(x.get_shape()) + axes = list(range(x_rank)) + axis = node.attrs.get("axis", -1) + axis = axis if axis >= 0 else axis + x_rank + k = kwargs["tensor_dict"][node.inputs[1]][0] + k = tf.cast(k, dtype=tf.int32) + + if axis != x_rank - 1: + pre_perm = [a for a in axes if a != axis] + [axis] + post_perm = axes[:axis] + [x_rank - 1] + axes[axis:x_rank - 1] + x = tf.transpose(x, perm=pre_perm) + values, indices = tf.nn.top_k(x, k) + values = tf.transpose(values, perm=post_perm) + return [values, tf.cast(indices, dtype=tf.int64)] + + values, indices = tf.nn.top_k(x, k) + return [values, tf.cast(indices, dtype=tf.int64)] + + @classmethod + def version_11(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_rank = len(x.get_shape()) + axes = list(range(x_rank)) + axis = node.attrs.get("axis", -1) + axis = axis if axis >= 0 else axis + x_rank + largest = node.attrs.get("largest", 1) + sort = node.attrs.get("sorted", 1) + sort = False if sort == 0 else True + k = kwargs["tensor_dict"][node.inputs[1]][0] + k = tf.cast(k, dtype=tf.int32) + + if largest == 0: + x = tf.negative(x) + + if axis != x_rank - 1: + pre_perm = [a for a in axes if a != axis] + [axis] + post_perm = axes[:axis] + [x_rank - 1] + axes[axis:x_rank - 1] + x = tf.transpose(x, perm=pre_perm) + values, indices = tf.nn.top_k(x, k, sort) + values = tf.transpose(values, perm=post_perm) + else : + values, indices = tf.nn.top_k(x, k, sort) + + if largest == 0: + values = tf.negative(values) + + return [values, tf.cast(indices, dtype=tf.int64)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/transpose.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/transpose.py new file mode 100644 index 0000000..9910fe4 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/transpose.py @@ -0,0 +1,14 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Transpose") +@tf_func(tf.transpose) +class Transpose(BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/unpool_mixin.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/unpool_mixin.py new file mode 100644 index 0000000..c071ed0 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/unpool_mixin.py @@ -0,0 +1,155 @@ +import tensorflow as tf + +from onnx_tf.common import get_data_format +from onnx_tf.common import get_perm_from_formats + + +class UnpoolMixin(object): + + @classmethod + def max_unpool(cls, node, input_dict): + """ + MaxUnpooling operation + """ + x = input_dict[node.inputs[0]] + ind = input_dict[node.inputs[1]] + if len(node.inputs) > 2: + output_shape = input_dict.get(node.inputs[2], None) + else: + output_shape = None + + input_shape = x.get_shape() + x_rank = len(x.get_shape()) + spatial_size = x_rank - 2 + storage_format, _ = get_data_format(x_rank) + + kernel_shape = node.attrs["kernel_shape"] + # if strides are not provided default is 1 along each spatial axis + strides = node.attrs.get("strides", [1] * spatial_size) + pads = node.attrs.get("pads", None) + + default_shape = cls._get_default_shape(input_shape, kernel_shape, + strides) + + need_trans = storage_format != "NHWC" + if need_trans: + x = tf.transpose(x, perm=get_perm_from_formats(storage_format, + "NHWC")) + ind = tf.transpose(ind, perm=get_perm_from_formats(storage_format, + "NHWC")) + + # default_shape to NHWC storage format + default_shape = [int(input_shape[0])] + default_shape + \ + [int(input_shape[1])] + + unpooled = cls._unpool(x, ind, default_shape) + + if need_trans: + unpooled = tf.transpose( + unpooled, perm=get_perm_from_formats("NHWC", storage_format)) + + if output_shape is not None: + pads = cls._get_pads_from_output_shape(unpooled, output_shape) + if pads is not None: + unpooled = cls._pad_output(unpooled, pads, 0) + + return [unpooled] + + @classmethod + def _get_default_shape(cls, input_shape, kernel_shape, strides): + """ + Calculates default shape from kernel_shape and strides + Args: + input_shape: shape of the input to unpool op + kernel_shape: the size of the kernel along each axis + output_shape: stride along each spatial axis + Return: + default_shape: calculated default_shape + """ + default_shape = [] + for d in range(len(kernel_shape)): + default_shape.append((int(input_shape[d + 2]) - 1) * + int(strides[d]) + int(kernel_shape[d])) + return default_shape + + @classmethod + def _get_pads_from_output_shape(cls, unpool, output_shape): + """ + Calculates the paddings from specified output_shape + Args: + unpool: result from unpool operation + output_shape: expected shape of the output + Return: + pads: calculated paddings in format + [x1_begin, x2_begin,.., x1_end, x2_end] + where xi_... represent pads added to begin + or end of axis i + """ + unpool_shape = tf.cast(tf.shape(unpool), dtype=tf.int32) + new_shape = tf.cast(output_shape, dtype=tf.int32) + + pads_begin = [] + pads_end = [] + + for d in range(len(unpool.get_shape())): + pad_total = new_shape[d] - unpool_shape[d] + pad_begin = tf.cast(pad_total / 2, tf.int32) + pad_end = pad_total - pad_begin + pads_begin = pads_begin + [pad_begin] + pads_end = pads_end + [pad_end] + + pads = pads_begin + pads_end + return pads + + @classmethod + def _pad_output(cls, unpool, pads, constant_values): + """ + Pad the output from unpool op + Args: + unpool: result from unpool op + pads: paddings in format + [x1_begin, x2_begin,..., x1_end, x2_end] + constant_values: constant value to fill up the padded spaces + Return: + padded: padded tensor + """ + unpool_shape = unpool.get_shape() + paddings = [] + for d in range(len(unpool_shape)): + paddings = paddings + [[pads[d], pads[d + len(unpool_shape)]]] + padded = tf.pad(unpool, paddings, 'CONSTANT', + constant_values=constant_values) + return padded + + @classmethod + def _unpool(cls, pool, ind, output_shape, scope='unpool'): + """ + Unpooling layer after max_pool_with_argmax. + + Args: + pool: max pooled output tensor + ind: argmax indices + output_shape: the shape of the output + Return: + unpool: unpooling tensor + """ + with tf.variable_scope(scope): + input_shape = tf.shape(pool) + + flat_input_size = tf.reduce_prod(input_shape) + flat_output_shape = [output_shape[0], output_shape[1] * + output_shape[2] * output_shape[3]] + + pool_ = tf.reshape(pool, [flat_input_size]) + batch_range = tf.reshape( + tf.range(tf.cast(output_shape[0], tf.int64), + dtype=ind.dtype), shape=[input_shape[0], 1, 1, 1]) + b = tf.ones_like(ind) * batch_range + b1 = tf.reshape(b, [flat_input_size, 1]) + ind_ = tf.reshape(ind, [flat_input_size, 1]) + ind_ = tf.concat([b1, ind_], 1) + + ret = tf.scatter_nd(ind_, pool_, shape=tf.cast(flat_output_shape, + tf.int64)) + ret = tf.reshape(ret, output_shape) + return ret diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/unsqueeze.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/unsqueeze.py new file mode 100644 index 0000000..061ef96 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/unsqueeze.py @@ -0,0 +1,32 @@ +import copy + +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Unsqueeze") +@tf_func(tf.expand_dims) +class Unsqueeze(BackendHandler): + + @classmethod + def _common(cls, node, **kwargs): + attrs = copy.deepcopy(node.attrs) + axes = attrs.pop("axes") + if len(axes) != 1: + x = kwargs["tensor_dict"][node.inputs[0]] + for axis in sorted(axes): + x = tf.expand_dims(x, axis=axis) + return [x] + attrs["axis"] = axes[0] + return [cls.make_tensor_from_onnx_node(node, attrs=attrs, **kwargs)] + + @classmethod + def version_1(cls, node, **kwargs): + return cls._common(node, **kwargs) + + @classmethod + def version_11(cls, node, **kwargs): + return cls._common(node, **kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/upsample.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/upsample.py new file mode 100644 index 0000000..6df8ec8 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/upsample.py @@ -0,0 +1,87 @@ +import copy + +import numpy as np +import tensorflow as tf + +from onnx_tf.common import exception +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import partial_support +from onnx_tf.handlers.handler import ps_description +from onnx_tf.handlers.handler import tf_func +from onnx_tf.common.tf_helper import tf_shape + + +@onnx_op("Upsample") +@tf_func(tf.image.resize_images) +@partial_support(True) +@ps_description("Upsample required 4D input in Tensorflow.") +class Upsample(BackendHandler): + + @classmethod + def args_check(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_shape = x.get_shape().as_list() + if len(x_shape) != 4: + exception.OP_UNSUPPORTED_EXCEPT("Upsample without 4D input", "Tensorflow") + + if node.attrs.get("mode", "nearest").lower() not in ["nearest", "bilinear", "linear"]: + exception.OP_UNSUPPORTED_EXCEPT("Upsample without nearest or bilinear", + "Tensorflow") + + @classmethod + def version_7(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_shape = x.get_shape().as_list() + attrs = copy.deepcopy(node.attrs) + scales = attrs["scales"] + new_height = np.floor(x_shape[2] * scales[2]) + new_weight = np.floor(x_shape[3] * scales[3]) + + mode = attrs.get("mode", "nearest") + if mode.lower() == "bilinear" or mode.lower() == "linear": + mode = tf.image.ResizeMethod.BILINEAR + else: + mode = tf.image.ResizeMethod.NEAREST_NEIGHBOR + + attrs["size"] = np.array((new_height, new_weight), dtype=np.int32) + attrs["method"] = mode + + return [ + cls.make_tensor_from_onnx_node( + node, attrs=attrs, c_last_only=True, **kwargs) + ] + + @classmethod + def version_9(cls, node, **kwargs): + x = kwargs["tensor_dict"][node.inputs[0]] + x_shape = tf_shape(x) + attrs = copy.deepcopy(node.attrs) + scales = kwargs["tensor_dict"][node.inputs[1]] + + assert_n_c_scale_is_one = tf.Assert( + tf.logical_and(tf.equal(scales[0], 1), tf.equal(scales[1], 1)), + [scales]) + + with tf.control_dependencies([assert_n_c_scale_is_one]): + h_w_scale = scales[2:] + h_w_shape = x_shape[2:] + new_h_w_shape = tf.cast(h_w_scale * tf.cast(h_w_shape, scales.dtype), + tf.int32) + + mode = attrs.get("mode", "nearest") + if mode.lower() == "bilinear" or mode.lower() == "linear": + mode = tf.image.ResizeMethod.BILINEAR + else: + mode = tf.image.ResizeMethod.NEAREST_NEIGHBOR + + attrs["size"] = new_h_w_shape + attrs["method"] = mode + + # Remove scale. + upsample_node = copy.deepcopy(node) + del upsample_node.inputs[1] + return [ + cls.make_tensor_from_onnx_node( + upsample_node, attrs=attrs, c_last_only=True, **kwargs) + ] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/where.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/where.py new file mode 100644 index 0000000..0f8b04f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/where.py @@ -0,0 +1,14 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func + + +@onnx_op("Where") +@tf_func(tf.where) +class Where(BackendHandler): + + @classmethod + def version_9(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/xor.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/xor.py new file mode 100644 index 0000000..9339a8f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend/xor.py @@ -0,0 +1,19 @@ +import tensorflow as tf + +from onnx_tf.handlers.backend_handler import BackendHandler +from onnx_tf.handlers.handler import onnx_op +from onnx_tf.handlers.handler import tf_func +from .control_flow_mixin import LogicalMixin + + +@onnx_op("Xor") +@tf_func(tf.logical_xor) +class Xor(LogicalMixin, BackendHandler): + + @classmethod + def version_1(cls, node, **kwargs): + return cls.limited_broadcast(node, **kwargs) + + @classmethod + def version_7(cls, node, **kwargs): + return [cls.make_tensor_from_onnx_node(node, **kwargs)] diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend_handler.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend_handler.py new file mode 100644 index 0000000..279c873 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/backend_handler.py @@ -0,0 +1,188 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import copy +import inspect + +import tensorflow as tf + +from onnx_tf.common import IS_PYTHON3 +from onnx_tf.common import get_data_format +from onnx_tf.common import get_perm_from_formats +from onnx_tf.common import supports_device +from .handler import Handler + + +class BackendHandler(Handler): + """ This class is base backend handler class. + All backend operator handler class MUST inherit this class. + In backend, operator handler class's name should be pascal case of file name + which should be snake case. + Use ONNX operator name as class name. + """ + + TF_FUNC = None + + @classmethod + def get_attrs_processor_param(cls): + """ Get param for attrs processor. + + :return: Dict. + """ + return {} + + @classmethod + def _process_attrs(cls, attrs): + """ Private method for processing attrs. + Param for this processor got from `get_attrs_processor_param`. + Param is dict contains two key: `default` and `raname`. + First add default value to attrs if key does not exist. + Second rename key to new key. + + For example: + attrs = {"keep_dims": True} + param = {"default": {"axis": 1}, + "rename": {"keep_dims": "keepdims"}} + + processed_attrs = {"axis": "1", "keepdims": True} + + :param attrs: Process target attrs. + :return: Processed attrs. + """ + param = {"rename": {}, "default": {}} + param.update(cls.get_attrs_processor_param()) + + for k, v in param["default"].items(): + attrs.setdefault(k, v) + + for k, new_k in param["rename"].items(): + if k in attrs: + attrs[new_k] = attrs.pop(k) + + return attrs + + @classmethod + def make_tensor_from_onnx_node(cls, + node, + tf_func=None, + inputs=None, + attrs=None, + name="", + c_first_cuda_only=False, + c_last_only=False, + **kwargs): + """ Helper method to make tensor. + + :param node: OnnxNode object. + :param tf_func: Callable Tf function. Default is cls.TF_FUNC. + :param inputs: Inputs tensor. Default is got from node.inputs. + :param attrs: Attributes. Default is node.attrs. + :param name: Node name. + :param c_first_cuda_only: If channel first is only supported by cuda. + If true and not cuda, do pre and post transpose. + :param c_last_only: If only channel last is support, + do pre and post transpose. + :param kwargs: Other args. + :return: Tensor. + """ + tensor_dict = kwargs.get("tensor_dict", {}) + tf_func = tf_func or cls.TF_FUNC + if tf_func is None: + raise RuntimeError("No Tensorflow function is given.") + if inputs is None: + inputs = [tensor_dict.get(inp, None) for inp in node.inputs] + if attrs is None: + attrs = copy.deepcopy(node.attrs) + name = name or node.name + if name != "": + attrs["name"] = name + + if c_first_cuda_only and c_last_only: + raise ValueError( + "c_first_cuda_only and c_last_only can not both be True.") + + if c_first_cuda_only: + return cls.c_first_cuda_only(tf_func, inputs, attrs) + elif c_last_only: + return cls.c_last_only(tf_func, inputs, attrs) + + return cls._run_tf_func(tf_func, inputs, attrs) + + @classmethod + def c_first_cuda_only(cls, tf_func, inputs, attrs): + """ Handle operator that channel first is only supported by CUDA. + When using CPU, two transposes should be added. + + :param tf_func: Callable Tf function. + :param inputs: Inputs tensor. + :param attrs: Attributes. + :return: Tensor. + """ + support_cuda = supports_device("CUDA") + if not support_cuda: + return cls._tuck_transpose(tf_func, inputs, attrs) + return cls._run_tf_func(tf_func, inputs, attrs) + + @classmethod + def c_last_only(cls, tf_func, inputs, attrs): + """ Handle operator that channel last only is supported. + Add two transposes anyway. + + :param tf_func: Callable Tf function. + :param inputs: Inputs tensor. + :param attrs: Attributes. + :return: Tensor. + """ + storage_format, compute_format = get_data_format(len(inputs[0].get_shape())) + compute_format = compute_format.replace("C", "") + "C" + return cls._tuck_transpose(tf_func, inputs, attrs, + (storage_format, compute_format)) + + @classmethod + def _tuck_transpose(cls, tf_func, inputs, attrs, data_format=None): + x = inputs[0] + x_rank = len(x.get_shape()) + if not data_format: + data_format = get_data_format(x_rank) + pre_perm = get_perm_from_formats(data_format[0], data_format[1]) + post_perm = get_perm_from_formats(data_format[1], data_format[0]) + attrs["data_format"] = data_format[1] + if pre_perm != list(range(x_rank)): + x_t = tf.transpose(x, perm=pre_perm) + y = cls._run_tf_func(tf_func, [x_t] + inputs[1:], attrs) + y_t = tf.transpose(y, perm=post_perm) + return y_t + return cls._run_tf_func(tf_func, inputs, attrs) + + @classmethod + def _run_tf_func(cls, tf_func, inputs, attrs): + """ Run Tensorflow function. + Use only acceptable attributes of function from attrs. + + :param tf_func: Tensorflow function. + :param inputs: Inputs. + :param attrs: Attributes. + :return: Tensor. + """ + if IS_PYTHON3: + params = list(inspect.signature(tf_func).parameters.keys()) + else: + # use closure to get args for function using decorator + if tf_func.__closure__ is not None: + while "__wrapped__" in tf_func.func_dict: + tf_func = tf_func.func_dict["__wrapped__"] + params = inspect.getargspec(tf_func).args + else: + params = inspect.getargspec(tf_func).args + + attrs = cls._process_attrs(attrs) + attrs = {p: v for p, v in attrs.items() if p in params} + kwargs = dict(zip(params, inputs)) + ambiguous_arguments = any(kwargs.get(p) is not None and v is not None + for p, v in attrs.items()) + if ambiguous_arguments: + raise TypeError('Ambiguous arguments for {}()'.format(tf_func.__name__)) + kwargs.update((p, v) for p, v in attrs.items() if v is not None) + return tf_func(**kwargs) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/handlers/handler.py b/pt2tf/onnx-tensorflow/onnx_tf/handlers/handler.py new file mode 100644 index 0000000..03e1868 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/handlers/handler.py @@ -0,0 +1,114 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import inspect + +from onnx import defs +from onnx.backend.test.runner import BackendIsNotSupposedToImplementIt + +import onnx_tf.common as common + + +class Handler(object): + """ This class is base handler class. + Base backend and frontend base handler class inherit this class. + + All operator handler MUST put decorator @onnx_op to register corresponding op. + """ + + ONNX_OP = None + + DOMAIN = defs.ONNX_DOMAIN + VERSION = 0 + SINCE_VERSION = 0 + PARTIAL_SUPPORT = False + PS_DESCRIPTION = '' + + @classmethod + def check_cls(cls): + if not cls.ONNX_OP: + common.logger.warning( + "{} doesn't have ONNX_OP. " + "Please use Handler.onnx_op decorator to register ONNX_OP.".format( + cls.__name__)) + + @classmethod + def args_check(cls, node, **kwargs): + """ Check args. e.g. if shape info is in graph. + Raise exception if failed. + + :param node: NodeProto for backend. + :param kwargs: Other args. + """ + pass + + @classmethod + def handle(cls, node, **kwargs): + """ Main method in handler. It will find corresponding versioned handle method, + whose name format is `version_%d`. So prefix `version_` is reserved in onnx-tensorflow. + DON'T use it for other purpose. + + :param node: NodeProto for backend. + :param kwargs: Other args. + :return: TensorflowNode for backend. + """ + ver_handle = getattr(cls, "version_{}".format(cls.SINCE_VERSION), None) + if ver_handle: + cls.args_check(node, **kwargs) + return ver_handle(node, **kwargs) + + raise BackendIsNotSupposedToImplementIt("{} version {} is not implemented.".format(node.op_type, cls.SINCE_VERSION)) + + @classmethod + def get_versions(cls): + """ Get all support versions. + + :return: Version list. + """ + versions = [] + for k, v in inspect.getmembers(cls, inspect.ismethod): + if k.startswith("version_"): + versions.append(int(k.replace("version_", ""))) + return versions + + @staticmethod + def onnx_op(op): + return Handler.property_register("ONNX_OP", op) + + @staticmethod + def tf_func(func): + return Handler.property_register("TF_FUNC", func) + + @staticmethod + def domain(d): + return Handler.property_register("DOMAIN", d) + + @staticmethod + def partial_support(ps): + return Handler.property_register("PARTIAL_SUPPORT", ps) + + @staticmethod + def ps_description(psd): + return Handler.property_register("PS_DESCRIPTION", psd) + + @staticmethod + def property_register(name, value): + + def deco(cls): + if inspect.isfunction(value) and not common.IS_PYTHON3: + setattr(cls, name, staticmethod(value)) + else: + setattr(cls, name, value) + return cls + + return deco + + +domain = Handler.domain +onnx_op = Handler.onnx_op +tf_func = Handler.tf_func +partial_support = Handler.partial_support +ps_description = Handler.ps_description +property_register = Handler.property_register diff --git a/pt2tf/onnx-tensorflow/onnx_tf/opset_version.py b/pt2tf/onnx-tensorflow/onnx_tf/opset_version.py new file mode 100644 index 0000000..46aeee3 --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/opset_version.py @@ -0,0 +1,256 @@ +backend_opset_version = { + 'Abs': [1, 6], + 'Acos': [7], + 'Acosh': [9], + 'Adagrad': [], + 'Adam': [], + 'Add': [1, 6, 7], + 'And': [1, 7], + 'ArgMax': [1, 11, 12], + 'ArgMin': [1, 11, 12], + 'ArrayFeatureExtractor': [], + 'Asin': [7], + 'Asinh': [9], + 'Atan': [7], + 'Atanh': [9], + 'AveragePool': [1, 7, 10, 11], + 'BatchNormalization': [1, 6, 7, 9], + 'Binarizer': [], + 'BitShift': [11], + 'Cast': [1, 6, 9], + 'CastMap': [], + 'CategoryMapper': [], + 'Ceil': [1, 6], + 'Celu': [], + 'Clip': [1, 6, 11, 12], + 'Compress': [9, 11], + 'Concat': [1, 4, 11], + 'ConcatFromSequence': [], + 'Constant': [1, 9, 11, 12], + 'ConstantFill': [1], + 'ConstantOfShape': [9], + 'Conv': [1, 11], + 'ConvInteger': [10], + 'ConvTranspose': [1, 11], + 'Cos': [7], + 'Cosh': [9], + 'CumSum': [11], + 'DepthToSpace': [1, 11], + 'DequantizeLinear': [10], + 'Det': [11], + 'DictVectorizer': [], + 'Div': [1, 6, 7], + 'Dropout': [1, 6, 7, 10], + 'DynamicQuantizeLinear': [11], + 'Einsum': [], + 'Elu': [1, 6], + 'Equal': [1, 7, 11], + 'Erf': [9], + 'Exp': [1, 6], + 'Expand': [8], + 'EyeLike': [9], + 'FeatureVectorizer': [], + 'Flatten': [1, 9, 11], + 'Floor': [1, 6], + 'GRU': [1, 3, 7], + 'Gather': [1, 11], + 'GatherElements': [11], + 'GatherND': [11], + 'Gemm': [1, 6, 7, 9, 11], + 'GlobalAveragePool': [1], + 'GlobalLpPool': [1, 2], + 'GlobalMaxPool': [1], + 'Gradient': [], + 'GraphCall': [], + 'Greater': [1, 7, 9], + 'GreaterOrEqual': [], + 'HardSigmoid': [1, 6], + 'Hardmax': [1, 11], + 'Identity': [1], + 'If': [1, 11], + 'ImageScaler': [1], + 'Imputer': [], + 'InstanceNormalization': [1, 6], + 'IsInf': [10], + 'IsNaN': [9], + 'LRN': [1], + 'LSTM': [1, 7], + 'LabelEncoder': [], + 'LeakyRelu': [1, 6], + 'Less': [1, 7, 9], + 'LessOrEqual': [], + 'LinearClassifier': [], + 'LinearRegressor': [], + 'Log': [1, 6], + 'LogSoftmax': [1, 11], + 'Loop': [1, 11], + 'LpNormalization': [1], + 'LpPool': [1, 2, 11], + 'MatMul': [1, 9], + 'MatMulInteger': [10], + 'Max': [1, 6, 8], + 'MaxPool': [1, 8, 10, 11, 12], + 'MaxRoiPool': [], + 'MaxUnpool': [9, 11], + 'Mean': [1, 6, 8], + 'MeanVarianceNormalization': [1, 9], + 'Min': [1, 6, 8], + 'Mod': [10], + 'Momentum': [], + 'Mul': [1, 6, 7], + 'Multinomial': [], + 'Neg': [1, 6], + 'NegativeLogLikelihoodLoss': [], + 'NonMaxSuppression': [10, 11], + 'NonZero': [9], + 'Normalizer': [], + 'Not': [1], + 'OneHot': [9, 11], + 'OneHotEncoder': [], + 'Or': [1, 7], + 'PRelu': [1, 6, 7, 9], + 'Pad': [1, 2, 11], + 'Pow': [1, 7], + 'QLinearConv': [10], + 'QLinearMatMul': [10], + 'QuantizeLinear': [10], + 'RNN': [1, 7], + 'RandomNormal': [1], + 'RandomNormalLike': [1], + 'RandomUniform': [1], + 'RandomUniformLike': [1], + 'Range': [11], + 'Reciprocal': [1, 6], + 'ReduceL1': [1, 11], + 'ReduceL2': [1, 11], + 'ReduceLogSum': [1, 11], + 'ReduceLogSumExp': [1, 11], + 'ReduceMax': [1, 11, 12], + 'ReduceMean': [1, 11], + 'ReduceMin': [1, 11, 12], + 'ReduceProd': [1, 11], + 'ReduceSum': [1, 11], + 'ReduceSumSquare': [1, 11], + 'Relu': [1, 6], + 'Reshape': [1, 5], + 'Resize': [10, 11], + 'ReverseSequence': [10], + 'RoiAlign': [], + 'Round': [11], + 'SVMClassifier': [], + 'SVMRegressor': [], + 'Scaler': [], + 'Scan': [8, 9, 11], + 'Scatter': [9], + 'ScatterElements': [11], + 'ScatterND': [11], + 'Selu': [1, 6], + 'SequenceAt': [11], + 'SequenceConstruct': [11], + 'SequenceEmpty': [11], + 'SequenceErase': [11], + 'SequenceInsert': [11], + 'SequenceLength': [11], + 'Shape': [1], + 'Shrink': [9], + 'Sigmoid': [1, 6], + 'Sign': [9], + 'Sin': [7], + 'Sinh': [9], + 'Size': [1], + 'Slice': [1, 10, 11], + 'Softmax': [1, 11], + 'SoftmaxCrossEntropyLoss': [], + 'Softplus': [1], + 'Softsign': [1], + 'SpaceToDepth': [1], + 'Split': [1, 2, 11], + 'SplitToSequence': [], + 'Sqrt': [1, 6], + 'Squeeze': [1, 11], + 'StringNormalizer': [], + 'Sub': [1, 6, 7], + 'Sum': [1, 6, 8], + 'Tan': [7], + 'Tanh': [1, 6], + 'TfIdfVectorizer': [9], + 'ThresholdedRelu': [1, 10], + 'Tile': [1, 6], + 'TopK': [1, 10, 11], + 'Transpose': [1], + 'TreeEnsembleClassifier': [], + 'TreeEnsembleRegressor': [], + 'Unique': [], + 'Unsqueeze': [1, 11], + 'Upsample': [7, 9], + 'Where': [9], + 'Xor': [1, 7], + 'ZipMap': [] +} + +backend_partial_support = { + 'Cast': 'Cast string to float32/float64/int32/int64 are not supported in ' + 'Tensorflow.', + 'Clip': 'Clip input in uint64 is not supported in Tensorflow.', + 'ConvTranspose': 'ConvTranspose with dilations != 1, or transposed ' + 'convolution for 4D or higher are not supported in ' + 'Tensorflow.', + 'CumSum': 'CumSum inputs in uint32/uint64 are not supported in Tensorflow.', + 'Equal': 'Equal inputs in uint16/uint32/uint64 are not supported in ' + 'Tensorflow.', + 'GRU': 'GRU with clip or GRU with linear_before_reset, or GRU not using ' + 'sigmoid for z and r, or GRU using Elu as the activation function ' + 'with alpha != 1, or GRU using HardSigmoid as the activation ' + 'function with alpha != 0.2 or beta != 0.5 are not supported in ' + 'TensorFlow.', + 'LSTM': 'LSTM not using sigmoid for `f`, or LSTM not using the same ' + 'activation for `g` and `h` are not supported in Tensorflow.', + 'MaxPool': 'MaxPoolWithArgmax with pad is None or incompatible mode, or ' + 'MaxPoolWithArgmax with 4D or higher input, orMaxPoolWithArgmax ' + 'with column major are not supported in Tensorflow.', + 'Mod': 'Mod Dividend or Divisor in int8/int16/uint8/uint16/uint32/uint64 ' + 'are not supported in Tensorflow.', + 'OneHot': 'OneHot indices in ' + 'uint16/uint32/uint64/int8/int16/float16/float/double, or OneHot ' + 'depth in ' + 'uint8/uint16/uint32/uint64/int8/int16/int64/float16/float/double ' + 'are not supported in Tensorflow.', + 'RNN': 'RNN with clip is not supported in Tensorflow.', + 'Resize': 'Resize required 4D input in Tensorflow. For opset 11, only the ' + 'following attributes and inputs conbination are supported in ' + 'Tensorflow:\n' + '\t1. mode=nearest, ' + 'coordinate_transformation_mode=align_corners, ' + 'nearest_mode=round_prefer_ceil, can use scales(*) or sizes.\n' + '\t2. mode=nearest, coordinate_transformation_mode=asymmetric, ' + 'nearest_mode=floor, can use scales(*) or sizes.\n' + '\t3. mode=nearest, ' + 'coordinate_transformation_mode=tf_half_pixel_for_nn, ' + 'nearest_mode=floor, can use scales(*) or sizes.\n' + '\t4. mode=linear, coordinate_transformation_mode=align_corners, ' + 'can use scales(*) or sizes.\n' + '\t5. mode=linear, coordinate_transformation_mode=asymmetric, ' + 'can use scales(*) or sizes.\n' + '\t6. mode=linear, coordinate_transformation_mode=half_pixel, ' + 'can use scales(*) or sizes.\n' + '\t7. mode=cubic, coordinate_transformation_mode=align_corners, ' + 'cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) or ' + 'sizes.\n' + '\t8. mode=cubic, coordinate_transformation_mode=asymmetric, ' + 'cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) or ' + 'sizes.\n' + '\t9. mode=cubic, coordinate_transformation_mode=half_pixel, ' + 'cubic_coeff_a=-0.5, exclude_outside=1, can use scales(*) or ' + 'sizes.\n' + '\t10. mode=nearest, ' + 'coordinate_transformation_mode=tf_crop_and_resize, ' + 'extrapolation_value=any_float_value, ' + 'nearest_mode=round_prefer_ceil, can use scales or sizes.\n' + '\t11. mode=linear, ' + 'coordinate_transformation_mode=tf_crop_and_resize, ' + 'extrapolation_value=any_float_value, can use scales or sizes.\n' + '\t- Note (*): The accuracy of your model will go down, if the ' + 'height and the width of the new sizes(scales * origial sizes) ' + 'are not in whole numbers.', + 'Upsample': 'Upsample required 4D input in Tensorflow.' +} diff --git a/pt2tf/onnx-tensorflow/onnx_tf/pb_wrapper.py b/pt2tf/onnx-tensorflow/onnx_tf/pb_wrapper.py new file mode 100644 index 0000000..7b7bcaf --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/pb_wrapper.py @@ -0,0 +1,461 @@ +import inspect +from itertools import chain + +import numpy as np +from onnx import NodeProto +from onnx import TensorProto +from onnx import ValueInfoProto +from onnx import numpy_helper +from onnx.helper import make_graph +from onnx.helper import make_tensor +from onnx.helper import make_tensor_value_info +from onnx.helper import mapping +import tensorflow as tf +from tensorflow.core.framework.attr_value_pb2 import AttrValue +from tensorflow.core.framework.node_def_pb2 import NodeDef + +from onnx_tf.common import attr_converter +from onnx_tf.common import attr_translator +from onnx_tf.common import CONST_MINUS_ONE_INT32 +from onnx_tf.common import CONST_ONE_FP32 +from onnx_tf.common import CONST_ONE_INT32 +from onnx_tf.common import CONST_ZERO_INT32 +from onnx_tf.common import IS_PYTHON3 +from onnx_tf.common import logger +from onnx_tf.common.data_type import any_dtype_to_onnx_dtype + + +class TensorflowNode(object): + + def __init__(self, + node=None, + name=None, + inputs=None, + outputs=None, + attr=None, + domain=None, + op_type=None): + # storing a reference to the original protobuf object + if node is None: + self.node = None + self.name = name or "" + self.inputs = inputs or [] + self.attr = attr or {} + self.domain = domain or "" + self.op_type = op_type or "" + self.outputs = outputs or self.get_outputs_names() + elif isinstance(node, (OnnxNode, NodeProto)): + self._load_onnx_node(node) + elif isinstance(node, NodeDef): + self._load_tf_node(node) + + def _load_onnx_node(self, node): + if isinstance(node, NodeProto): + node = OnnxNode(node) + self.name = node.name + self.inputs = node.inputs + self.outputs = node.outputs + self.attr = node.attrs + self.domain = node.domain + self.op_type = node.op_type + + def _load_tf_node(self, node): + self.node = node + self.name = node.name + self.inputs = list(node.input) + self.attr = {} + for key, val in node.attr.items(): + new_val = attr_translator.translate_tf(key, val) + if isinstance(new_val, AttrValue): + new_val = attr_converter.convert_tf(new_val) + self.attr[key] = new_val + splitted_op_name = node.op.split(".") + self.domain = "" if len(splitted_op_name) == 1 else ".".join( + splitted_op_name[:-1]) + self.op_type = splitted_op_name[-1] + self.outputs = self.get_outputs_names() + + def get_outputs_names(self, num=None): + """ Helper method to get outputs names. + e.g. tf.split: [Split, Split:1, Split:2] + + :param num: Force to get `num` outputs names. + :return: List of outputs names. + """ + if num is None: + if "_output_shapes" in self.attr: + num = len(self.attr["_output_shapes"]) + else: + num = 1 + logger.warning("_output_shapes is not in node.attr. " + "The num of output is set to 1 for commonly. " + "It will cause problem with case of multiple outputs.") + return [ + self.name + ":{}".format(i) if i > 0 else self.name for i in range(num) + ] + + +class TensorflowGraph(object): + + def __init__(self, graph_def, outputs=(), graph_name="graph"): + self._graph_name = graph_name + self._graph_def = self._process_graph_def(graph_def) + self._nodes = self._create_util_nodes() + [ + TensorflowNode(node) for node in self.graph_def.node + ] + self._nodes_dict = {n.name: n for n in self._nodes} + self._outputs = outputs or self.get_output_node_names(self.graph_def) + + @staticmethod + def _create_util_nodes(): + util_nodes = [(CONST_MINUS_ONE_INT32, np.array([-1]).astype(np.int32)), + (CONST_ZERO_INT32, np.array([0]).astype(np.int32)), + (CONST_ONE_INT32, np.array([1]).astype(np.int32))] + return [ + TensorflowNode( + op_type="Const", + name=name, + attr={ + "value": value, + "dtype": any_dtype_to_onnx_dtype(value.dtype), + "_output_shapes": [value.shape] + }) for name, value in util_nodes + ] + + def get_node_by_name(self, name): + node = self._nodes_dict.get(name, None) + if node is None: + raise ValueError( + "Node {} is not found in the graph provided".format(name)) + return node + + def _process_graph_def(self, graph_def): + if "_output_shapes" not in TensorflowNode(graph_def.node[0]).attr: + graph_def = self._add_infer_shapes(graph_def) + return graph_def + + @staticmethod + def _add_infer_shapes(graph_def): + with tf.Graph().as_default(): + with tf.Session( + config=tf.ConfigProto( + graph_options=tf.GraphOptions(infer_shapes=True))) as sess: + tf.import_graph_def(graph_def, name="") + return sess.graph_def + + @staticmethod + def get_output_node_names(graph_def): + """Get output node names from GraphDef. + + Args: + graph_def: GraphDef object. + + Returns: + List of output node names. + """ + input_names, output_names = set(), set() + for node in graph_def.node: + output_names.add(node.name) + input_names.update(set(node.input)) + return list(output_names - input_names) + + def update_nodes(self, nodes): + self._nodes = nodes + self._nodes_dict = {n.name: n for n in self._nodes} + + @property + def graph_def(self): + return self._graph_def + + @property + def graph_name(self): + return self._graph_name + + @property + def nodes(self): + return self._nodes + + @property + def nodes_dict(self): + return self._nodes_dict + + @property + def outputs(self): + return self._outputs + + +# TODO: Move this into ONNX main library +class OnnxNode(object): + """ + Reimplementation of NodeProto from ONNX, but in a form + more convenient to work with from Python. + """ + + def __init__(self, node): + self.name = str(node.name) + self.op_type = str(node.op_type) + self.domain = str(node.domain) + self.attrs = dict([(attr.name, + attr_translator.translate_onnx( + attr.name, attr_converter.convert_onnx(attr))) + for attr in node.attribute]) + self.inputs = list(node.input) + self.outputs = list(node.output) + self.node_proto = node + + +class OnnxGraph(object): + """ A helper class for making ONNX graph. + This class holds all information ONNX graph needs. + """ + + def __init__(self, name=None, graph_proto=None): + if graph_proto: + self._name = graph_proto.name + self._inputs_proto = list(graph_proto.input) + self._outputs_proto = list(graph_proto.output) + self._nodes_proto = list(graph_proto.node) + self._consts_proto = list(graph_proto.initializer) + self._value_info_proto = list(graph_proto.value_info) + self._consts = dict([(init.name, numpy_helper.to_array(init)) + for init in graph_proto.initializer]) + else: + self._name = name or "" + self._inputs_proto = [] + self._outputs_proto = [] + self._nodes_proto = [] + self._consts = {} + self._consts_proto = [] + self._value_info_proto = [] + # Either way, data_type_cast_map is empty when initialized. + self._data_type_cast_map = {} + + self._add_utility_constants() + + def _add_utility_constants(self): + util_consts = {CONST_ONE_FP32: np.array([1.0]).astype(np.float32)} + # Add a few useful utility constants: + for name, value in util_consts.items(): + self.add_const_explicit(name=name, value=value) + self.add_const_proto_explicit( + name=name, value=value, np_dtype=value.dtype) + self.add_input_proto_explicit( + name=name, shape=value.shape, np_dtype=value.dtype) + + # This list holds the protobuf objects of type ValueInfoProto + # representing the input to the converted ONNX graph. + @property + def inputs_proto(self): + return self._inputs_proto + + @inputs_proto.setter + def inputs_proto(self, inputs_proto): + self._inputs_proto = inputs_proto + + @property + def all_node_inputs(self): + return list(chain.from_iterable(map(lambda p: p.input, self._nodes_proto))) + + @property + def outputs(self): + return list(map(lambda p: p.name, self._outputs_proto)) + + @property + def outputs_proto(self): + return self._outputs_proto + + # This list holds the protobuf objects of type NodeProto + # representing the ops in the converted ONNX graph. + @property + def nodes_proto(self): + return self._nodes_proto + + @nodes_proto.setter + def nodes_proto(self, nodes_proto): + self._nodes_proto = nodes_proto + + # This dictionary contains a map from the name of the constant + # op to the array of values it holds. This is useful because + # tensorflow is less eager to know about input values at + # graph construction time than ONNX. That is to say, some ONNX + # attributes are input tensors in TF. This dictionary extracts + # those values of constant tensors that are known at graph + # construction time. + @property + def consts(self): + return self._consts + + @consts.setter + def consts(self, consts): + self._consts = consts + + # Sometimes the constants are used as inputs to ops. This list + # holds initializers that creates global constant tensors available + # to be accessed by ops as inputs (as oppose to attributes which + # is supplied by the `consts` map above). + @property + def consts_proto(self): + return self._consts_proto + + @consts_proto.setter + def consts_proto(self, consts_proto): + self._consts_proto = consts_proto + + # A map holds nodes name and new data type. Will be used to + # process protos to match ONNX type constraints. + @property + def data_type_cast_map(self): + return self._data_type_cast_map + + @data_type_cast_map.setter + def data_type_cast_map(self, data_type_cast_map): + self._data_type_cast_map = data_type_cast_map + + # This list holds the protobuf objects of type ValueInfoProto + # representing the all nodes' outputs to the converted ONNX graph. + @property + def value_info_proto(self): + return self._value_info_proto + + def add_input_proto_explicit(self, + name, + shape, + np_dtype=None, + tf_dtype=None, + onnx_dtype=None): + onnx_dtype = any_dtype_to_onnx_dtype( + np_dtype=np_dtype, tf_dtype=tf_dtype, onnx_dtype=onnx_dtype) + input_proto = make_tensor_value_info(name, onnx_dtype, shape) + self._inputs_proto.append(input_proto) + + def add_input_proto(self, node): + name = node.name + onnx_dtype = node.attr["dtype"] + shape = node.attr["shape"] if node.op_type != "Const" else node.attr[ + 'value'].shape + self.add_input_proto_explicit(name, shape, onnx_dtype=onnx_dtype) + + def add_output_proto(self, node): + output_onnx_type = node.attr.get("T", TensorProto.BOOL) + for i, output_shape in enumerate(node.attr["_output_shapes"]): + output_name = node.name + ":{}".format(i) if i > 0 else node.name + self._outputs_proto.append( + make_tensor_value_info(output_name, output_onnx_type, output_shape)) + + def add_node_proto(self, node_proto): + if not isinstance(node_proto, (list, tuple)): + node_proto = [node_proto] + self._nodes_proto.extend(node_proto) + + def remove_node_proto(self, names): + if not isinstance(names, (list, tuple)): + names = [names] + self._nodes_proto = list( + filter(lambda x: x.name not in names, self._nodes_proto)) + + def add_const_explicit(self, name, value): + self._consts[name] = value + + def add_const(self, node): + self.add_const_explicit(node.name, node.attr["value"]) + + def add_const_proto_explicit(self, + name, + value, + np_dtype=None, + tf_dtype=None, + onnx_dtype=None): + onnx_dtype = any_dtype_to_onnx_dtype( + np_dtype=np_dtype, tf_dtype=tf_dtype, onnx_dtype=onnx_dtype) + + const_dim = len(value.shape) + + if const_dim == 0: + raw_values = [value.tolist()] + values = [value] + else: + raw_values = value.flatten().tolist() + values = value + + shape = np.array(values).shape + const_proto = make_tensor( + name=name, data_type=onnx_dtype, dims=shape, vals=raw_values) + self._consts_proto.append(const_proto) + + def add_const_proto(self, node): + self.add_const_proto_explicit( + node.name, node.attr["value"], onnx_dtype=node.attr["dtype"]) + + def add_value_info_proto(self, node): + node_onnx_type = node.attr.get("T", TensorProto.BOOL) + for i, output_shape in enumerate(node.attr["_output_shapes"]): + node_name = node.name + ":{}".format(i) if i > 0 else node.name + value_info_proto = make_tensor_value_info(node_name, node_onnx_type, + output_shape) + self._value_info_proto.append(value_info_proto) + + # Remove proto in inputs_proto and consts_proto + # if proto is not used as input or an output in ONNX + def _clean_graph(self): + in_out = self.all_node_inputs + self.outputs + self._inputs_proto = list( + filter(lambda x: x.name in in_out, self.inputs_proto)) + self._consts_proto = list( + filter(lambda x: x.name in in_out, self.consts_proto)) + + def _fix_data_type(self): + self.inputs_proto = self._data_type_caster(self.inputs_proto, + self.data_type_cast_map) + self.consts_proto = self._data_type_caster(self.consts_proto, + self.data_type_cast_map) + + @classmethod + def _data_type_caster(cls, protos, data_type_cast_map): + """Cast to a new data type if node name is in data_type_cast_map. + Be used to process protos to match ONNX type constraints. + + :param protos: Target protos. + TensorProto for inputs and ValueInfoProto for consts. + :param data_type_cast_map: A {node.name: new_data_type} dict. + :return: Processed protos. + """ + if not data_type_cast_map: + return protos + result = [] + for proto in protos: + new_proto = proto + if proto.name in data_type_cast_map: + new_data_type = data_type_cast_map[proto.name] + if type(proto) == TensorProto and proto.data_type != new_data_type: + field = mapping.STORAGE_TENSOR_TYPE_TO_FIELD[ + mapping.TENSOR_TYPE_TO_STORAGE_TENSOR_TYPE[proto.data_type]] + vals = getattr(proto, field) + new_proto = make_tensor( + name=proto.name, + data_type=new_data_type, + dims=proto.dims, + vals=vals) + elif type( + proto + ) == ValueInfoProto and proto.type.tensor_type.elem_type != new_data_type: + new_proto.type.tensor_type.elem_type = new_data_type + result.append(new_proto) + return result + + def make_graph_proto(self): + self._clean_graph() + self._fix_data_type() + + if IS_PYTHON3: + params = list(inspect.signature(make_graph).parameters.keys()) + else: + params = inspect.getargspec(make_graph).args + + kwargs = { + "initializer": self.consts_proto, + "value_info": self.value_info_proto + } + + return make_graph(self.nodes_proto, self._name, self.inputs_proto, + self.outputs_proto, + **dict([(k, kwargs[k]) for k in kwargs if k in params])) diff --git a/pt2tf/onnx-tensorflow/onnx_tf/version.py b/pt2tf/onnx-tensorflow/onnx_tf/version.py new file mode 100644 index 0000000..3284f5f --- /dev/null +++ b/pt2tf/onnx-tensorflow/onnx_tf/version.py @@ -0,0 +1,7 @@ +# This file is generated by setup.py. DO NOT EDIT! +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals +version = '1.6.0' +git_version = '6b9e76d6fca74d5ddbf47049b9670120abaaf70f' diff --git a/pt2tf/onnx-tensorflow/setup.cfg b/pt2tf/onnx-tensorflow/setup.cfg new file mode 100644 index 0000000..76200df --- /dev/null +++ b/pt2tf/onnx-tensorflow/setup.cfg @@ -0,0 +1,3 @@ +[metadata] +description-file = README.md +license-file = LICENSE diff --git a/pt2tf/onnx-tensorflow/setup.py b/pt2tf/onnx-tensorflow/setup.py new file mode 100644 index 0000000..97e33d6 --- /dev/null +++ b/pt2tf/onnx-tensorflow/setup.py @@ -0,0 +1,59 @@ +import os +import setuptools +import subprocess +from textwrap import dedent + +TOP_DIR = os.path.realpath(os.path.dirname(__file__)) +SRC_DIR = os.path.join(TOP_DIR, 'onnx_tf') + +with open(os.path.join(TOP_DIR, 'VERSION_NUMBER')) as version_file: + version = version_file.read().strip() + +if os.getenv('TRAVIS'): + # On travis, we install from source, therefore no need to specify version. + onnx_dep = "onnx" +else: + # For user, we install the onnx release known to work with our release. + with open(os.path.join(TOP_DIR, 'ONNX_VERSION_NUMBER')) as onnx_version_file: + onnx_version = onnx_version_file.read().strip() + onnx_dep = "onnx>=" + onnx_version + +try: + git_version = subprocess.check_output(['git', 'rev-parse', 'HEAD'], + cwd=TOP_DIR).decode('ascii').strip() +except (OSError, subprocess.CalledProcessError): + git_version = None + +with open(os.path.join(SRC_DIR, 'version.py'), 'w') as f: + f.write(dedent('''\ + # This file is generated by setup.py. DO NOT EDIT! + from __future__ import absolute_import + from __future__ import division + from __future__ import print_function + from __future__ import unicode_literals + version = '{}' + git_version = '{}' + '''.format(version, git_version))) + +setuptools.setup( + name='onnx-tf', + version=version, + description= + 'Tensorflow backend for ONNX (Open Neural Network Exchange).', + install_requires=[onnx_dep, "PyYAML"], + entry_points={ + "console_scripts": [ + "onnx-tf=onnx_tf.cli:main", + ], + }, + url='https://github.com/onnx/onnx-tensorflow/', + author='Arpith Jacob, Tian Jin, Gheorghe-Teodor Bercea, Wenhao Hu', + author_email='tian.jin1@ibm.com', + license='Apache License 2.0', + packages=setuptools.find_packages(), + zip_safe=False, + classifiers=[ + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3" + ] +) diff --git a/pt2tf/onnx-tensorflow/test/__init__.py b/pt2tf/onnx-tensorflow/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pt2tf/onnx-tensorflow/test/backend/__init__.py b/pt2tf/onnx-tensorflow/test/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pt2tf/onnx-tensorflow/test/backend/test_dynamic_shape.py b/pt2tf/onnx-tensorflow/test/backend/test_dynamic_shape.py new file mode 100644 index 0000000..752c856 --- /dev/null +++ b/pt2tf/onnx-tensorflow/test/backend/test_dynamic_shape.py @@ -0,0 +1,305 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import numpy as np +import tensorflow as tf +import unittest + +from onnx_tf.backend import onnx_graph_to_tensorflow_rep +from onnx_tf.common.legacy import legacy_opset_pre_ver +from onnx import defs +from onnx import helper +from onnx import TensorProto + +# Run the following test in graph mode +tf.compat.v1.disable_eager_execution() + + +class TestDynamicShape(unittest.TestCase): + """ Tests for dynamic shape support + """ + + def _get_rnd_float32(self, low=-1.0, high=1.0, shape=None): + output = np.random.uniform(low, high, shape) + if shape is None: + return np.float32(output) + else: + return output.astype(np.float32) + + def _get_rnd_int(self, low, high=None, shape=None, dtype=np.int32): + return np.random.randint(low, high, size=shape, dtype=dtype) + + def test_arg_max(self): + if legacy_opset_pre_ver(12): + raise unittest.SkipTest( + "ONNX version {} doesn't support select_last_index attribute for ArgMax that depends on shape.".format( + defs.onnx_opset_version())) + axis = 1 + node_def = helper.make_node("ArgMax", + inputs=['X'], + outputs=['Y'], + axis=axis, + keepdims=0, + select_last_index=1) + graph_def = helper.make_graph( + [node_def], + name="test_unknown_shape", + inputs=[ + helper.make_tensor_value_info("X", TensorProto.FLOAT, [None, None]) + ], + outputs=[ + helper.make_tensor_value_info("Y", TensorProto.FLOAT, [None, None]) + ]) + x = np.array([[ 1, 2, 3, 5, 3, 4, 5, 1 ], [ 2, 9, 3, 5, 9, 4, 5, 1 ]]) + tf_rep = onnx_graph_to_tensorflow_rep(graph_def) + output = tf_rep.run({"X": x}) + expected_output = np.argmax(np.flip(x, axis), axis=axis) + expected_output = x.shape[axis] - expected_output - 1 + np.testing.assert_almost_equal(output['Y'], expected_output) + + def test_arg_min(self): + if legacy_opset_pre_ver(12): + raise unittest.SkipTest( + "ONNX version {} doesn't support select_last_index attribute for ArgMin that depends on shape.".format( + defs.onnx_opset_version())) + axis = 1 + node_def = helper.make_node("ArgMin", + inputs=['X'], + outputs=['Y'], + axis=axis, + keepdims=0, + select_last_index=1) + graph_def = helper.make_graph( + [node_def], + name="test_unknown_shape", + inputs=[ + helper.make_tensor_value_info("X", TensorProto.FLOAT, [None, None]) + ], + outputs=[ + helper.make_tensor_value_info("Y", TensorProto.FLOAT, [None, None]) + ]) + x = np.array([[ 1, 2, 3, 5, 3, 4, 5, 1 ], [ 2, 7, 3, 5, 2, 4, 5, 6 ]]) + tf_rep = onnx_graph_to_tensorflow_rep(graph_def) + output = tf_rep.run({"X": x}) + expected_output = np.argmin(np.flip(x, axis), axis=axis) + expected_output = x.shape[axis] - expected_output - 1 + np.testing.assert_almost_equal(output['Y'], expected_output) + + def _batch_normalization(self, x, mean, variance, bias, scale, + variance_epsilon): + inv = np.reciprocal(np.sqrt(variance + variance_epsilon)) + if scale is not None: + inv *= scale + return x * inv + (bias - mean * inv if bias is not None else -mean * inv) + + def test_batch_normalization(self): + if legacy_opset_pre_ver(6): + raise unittest.SkipTest("Backend doesn't support consumed flag") + node_def = helper.make_node("BatchNormalization", + ["X", "scale", "bias", "mean", "var"], ["Y"], + epsilon=0.001) + graph_def = helper.make_graph( + [node_def], + name="test_unknown_shape", + inputs=[ + helper.make_tensor_value_info("X", TensorProto.FLOAT, [None, None, None, None]), + helper.make_tensor_value_info("scale", TensorProto.FLOAT, [None]), + helper.make_tensor_value_info("bias", TensorProto.FLOAT, [None]), + helper.make_tensor_value_info("mean", TensorProto.FLOAT, [None]), + helper.make_tensor_value_info("var", TensorProto.FLOAT, [None]) + ], + outputs=[ + helper.make_tensor_value_info("Y", TensorProto.FLOAT, [None, None, None, None]) + ]) + x_shape = [3, 5, 4, 2] + param_shape = [5] + _param_shape = [1, 5, 1, 1] + x = self._get_rnd_float32(0, 1, shape=x_shape) + m = self._get_rnd_float32(0, 1, shape=param_shape) + _m = m.reshape(_param_shape) + v = self._get_rnd_float32(0, 1, shape=param_shape) + _v = v.reshape(_param_shape) + scale = self._get_rnd_float32(0, 1, shape=param_shape) + _scale = scale.reshape(_param_shape) + bias = self._get_rnd_float32(0, 1, shape=param_shape) + _bias = bias.reshape(_param_shape) + golden = self._batch_normalization(x, _m, _v, _bias, _scale, 0.001) + tf_rep = onnx_graph_to_tensorflow_rep(graph_def) + output = tf_rep.run({"X": x, "scale": scale, "bias": bias, "mean": m, "var": v}) + np.testing.assert_almost_equal(output["Y"], golden, decimal=5) + + def test_conv_transpose(self): + # test dynamic batch size on transpose of 2d convolution + pads = [1, 1, 1, 1] + x_shape = [1, 3, 4, 6] + x = self._get_rnd_float32(shape=x_shape) + weight_shape = [3, 5, 2, 2] + weights = self._get_rnd_float32(shape=weight_shape) + + node_def = helper.make_node("ConvTranspose", ["X", "weights"], ["Y"], + pads=pads) + graph_def = helper.make_graph( + [node_def], + name="test_unknown_shape", + inputs=[ + helper.make_tensor_value_info("X", TensorProto.FLOAT, [None, 3, 4, 6]), + helper.make_tensor_value_info("weights", TensorProto.FLOAT, weight_shape) + ], + outputs=[ + helper.make_tensor_value_info("Y", TensorProto.FLOAT, [None, None, None, None]) + ]) + + tf_rep = onnx_graph_to_tensorflow_rep(graph_def) + output = tf_rep.run({"X": x, "weights": weights}) + + padh_left = weight_shape[2] - 1 - pads[0] + padh_right = weight_shape[2] - 1 - pads[1] + padw_left = weight_shape[3] - 1 - pads[2] + padw_right = weight_shape[3] - 1 - pads[3] + + kh = weight_shape[2] + kw = weight_shape[3] + outh = x_shape[2] + padh_right + padh_right - (kh - 1) + outw = x_shape[3] + padw_right + padw_right - (kw - 1) + + out_shape = [x_shape[0], weight_shape[1], outh, outw] + + test_output = np.zeros(out_shape) + for b in range(0, x_shape[0]): + for m in range(0, weight_shape[1]): + for c in range(0, x_shape[1]): + for h in range(0, outh): + for w in range(0, outw): + for k1 in range(h, h + kh): + for k2 in range(w, w + kw): + if (k1 - padh_left >= 0 and k2 - padw_left >= 0): + test_output[b][m][h][w] += x[b][c][k1 - padh_left][ + k2 - padw_left] * weights[c][m][kh + h - 1 - + k1][kw + w - 1 - k2] + + np.testing.assert_almost_equal(output["Y"], test_output, decimal=5) + + def test_slice(self): + # test case 1 with normal inputs + axes = [0, 1, 2] + starts = [0, 0, 0] + ends = [2, 2, 2] + + if legacy_opset_pre_ver(10): + node_def = helper.make_node("Slice", ["X"], ["S"], + axes=axes, + starts=starts, + ends=ends) + graph_def = helper.make_graph( + [node_def], + name="test_unknown_shape", + inputs=[ + helper.make_tensor_value_info("X", TensorProto.FLOAT, + [None, None, None]) + ], + outputs=[ + helper.make_tensor_value_info("S", TensorProto.FLOAT, + [None, None, None]) + ]) + else: + node_def = helper.make_node("Slice", + ["X", "starts", "ends", "axes"], + ["S"]) + graph_def = helper.make_graph( + [node_def], + name="test_unknown_shape", + inputs=[ + helper.make_tensor_value_info("X", TensorProto.FLOAT, + [None, None, None]), + helper.make_tensor_value_info("starts", TensorProto.INT32, + [None]), + helper.make_tensor_value_info("ends", TensorProto.INT32, + [None]), + helper.make_tensor_value_info("axes", TensorProto.INT32, + [None]), + ], + outputs=[ + helper.make_tensor_value_info("S", TensorProto.FLOAT, + [None, None, None]) + ]) + tf_rep = onnx_graph_to_tensorflow_rep(graph_def) + + if legacy_opset_pre_ver(10): + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = tf_rep.run({"X": x}) + np.testing.assert_almost_equal(output["S"], x[0:2, 0:2, 0:2]) + else: + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = tf_rep.run({"X": x, "starts": starts, "ends": ends, "axes": axes}) + np.testing.assert_almost_equal(output["S"], x[0:2, 0:2, 0:2]) + + # test case 2 with negative, out-of-bound and default inputs + axes = [0, 2] + starts = [0, -7] + ends = [-8, 20] + steps = [1, 1] + + if legacy_opset_pre_ver(10): + node_def = helper.make_node("Slice", ["X"], ["S"], + axes=axes, + starts=starts, + ends=ends) + graph_def = helper.make_graph( + [node_def], + name="test_unknown_shape", + inputs=[ + helper.make_tensor_value_info("X", TensorProto.FLOAT, + [None, None, None]) + ], + outputs=[ + helper.make_tensor_value_info("S", TensorProto.FLOAT, + [None, None, None]) + ]) + else: + node_def = helper.make_node("Slice", + ["X", "starts", "ends", "axes", "steps"], + ["S"]) + graph_def = helper.make_graph( + [node_def], + name="test_unknown_shape", + inputs=[ + helper.make_tensor_value_info("X", TensorProto.FLOAT, + [None, None, None]), + helper.make_tensor_value_info("starts", TensorProto.INT32, + [None]), + helper.make_tensor_value_info("ends", TensorProto.INT32, + [None]), + helper.make_tensor_value_info("axes", TensorProto.INT32, + [None]), + helper.make_tensor_value_info("steps", TensorProto.INT32, + [None]), + ], + outputs=[ + helper.make_tensor_value_info("S", TensorProto.FLOAT, + [None, None, None]) + ]) + tf_rep = onnx_graph_to_tensorflow_rep(graph_def) + if legacy_opset_pre_ver(10): + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = tf_rep.run({"X": x}) + np.testing.assert_almost_equal(output["S"], x[0:-8, :, -7:20]) + else: + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = tf_rep.run({"X": x, "starts": starts, "ends": ends, "axes": axes, "steps": steps}) + np.testing.assert_almost_equal(output["S"], x[0:-8, :, -7:20]) + + # test case 3 with non-default steps + axes = [0, 1, 2] + starts = [0, 0, 0] + ends = [2, 2, 2] + steps = [2, -2, -1] + + if not legacy_opset_pre_ver(10): + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = tf_rep.run({"X": x, "starts": starts, "ends": ends, "axes": axes, "steps": steps}) + np.testing.assert_almost_equal(output["S"], x[0:2:2, 0:2:-2, 0:2:-1]) + +if __name__ == '__main__': + unittest.main() diff --git a/pt2tf/onnx-tensorflow/test/backend/test_model.py b/pt2tf/onnx-tensorflow/test/backend/test_model.py new file mode 100644 index 0000000..ffda278 --- /dev/null +++ b/pt2tf/onnx-tensorflow/test/backend/test_model.py @@ -0,0 +1,157 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import unittest + +import numpy as np +import onnx +from onnx_tf.backend import prepare +from onnx import helper +from onnx import TensorProto + +from onnx_tf.common.legacy import legacy_onnx_pre_ver + + +class TestModel(unittest.TestCase): + """ Tests for models + """ + + def _get_rnd(self, shape, low=-1.0, high=1.0): + return np.random.uniform(low, high, np.prod(shape)) \ + .reshape(shape) \ + .astype(np.float32) + + def test_sequence_ops(self): + # test SequenceConstruct and SequenceAt + a = np.random.randn(2, 1, 2).astype(np.float32) + b = np.random.randn(1, 1, 2).astype(np.float32) + c = np.random.randn(3, 1, 2).astype(np.float32) + seq_construct_node = helper.make_node('SequenceConstruct', ['a', 'b', 'c'], ['S']) + seq_at_node = helper.make_node('SequenceAt', ['S','at'], ['Y']) + out_value_info = helper.make_tensor_value_info('Y',onnx.TensorProto.FLOAT,[None]) + a_value_info = helper.make_tensor_value_info('a',onnx.TensorProto.FLOAT,[2, 1, 2]) + b_value_info = helper.make_tensor_value_info('b',onnx.TensorProto.FLOAT,[1, 1, 2]) + c_value_info = helper.make_tensor_value_info('c',onnx.TensorProto.FLOAT,[3, 1, 2]) + at_value_info = helper.make_tensor_value_info('at',onnx.TensorProto.INT32,[]) + + graph = helper.make_graph([seq_construct_node, seq_at_node], + name='seq_construct_at_test', + inputs=[a_value_info, b_value_info, c_value_info, at_value_info], + outputs=[out_value_info]) + model = helper.make_model(graph, producer_name='backend-test') + tf_rep = prepare(model) + output = tf_rep.run({'a':a, 'b':b, 'c':c, 'at':0}) + np.testing.assert_almost_equal(output["Y"], a) + output = tf_rep.run({'a':a, 'b':b, 'c':c, 'at':-2}) + np.testing.assert_almost_equal(output["Y"], b) + output = tf_rep.run({'a':a, 'b':b, 'c':c, 'at':2}) + np.testing.assert_almost_equal(output["Y"], c) + + # test SequenceEmpty, SequenceInsert, and SequenceAt + p = np.int32(0) + seq_empty_node = helper.make_node('SequenceEmpty', [], ['S']) + seq_insert_node1 = helper.make_node('SequenceInsert', ['S','a'], ['S1']) + seq_insert_node2 = helper.make_node('SequenceInsert', ['S1','b'], ['S2']) + seq_insert_node3 = helper.make_node('SequenceInsert', ['S2','c','p'], ['S3']) + seq_at_node = helper.make_node('SequenceAt', ['S3','at'], ['Y']) + + p_value_info = helper.make_tensor_value_info('p',onnx.TensorProto.INT32,[]) + + graph = helper.make_graph([seq_empty_node, seq_insert_node1, seq_insert_node2, seq_insert_node3, seq_at_node], + name='seq_empty_insert_at_test', + inputs=[a_value_info, b_value_info, c_value_info, p_value_info, at_value_info], + outputs=[out_value_info]) + model = helper.make_model(graph, producer_name='backend-test') + tf_rep = prepare(model) + output = tf_rep.run({'a':a, 'b':b, 'c':c, 'p':p, 'at':0}) + np.testing.assert_almost_equal(output["Y"], c) + + # test SequenceConstruct, SequenceErase, and SequenceLength + seq_construct_node = helper.make_node('SequenceConstruct', ['a', 'b', 'c'], ['S']) + seq_erase_node = helper.make_node('SequenceErase', ['S','p'], ['S1']) + seq_length_node = helper.make_node('SequenceLength', ['S1'], ['Y']) + + graph = helper.make_graph([seq_construct_node, seq_erase_node, seq_length_node], + name='seq_construct_erase_length_test', + inputs=[a_value_info, b_value_info, c_value_info, p_value_info], + outputs=[out_value_info]) + model = helper.make_model(graph, producer_name='backend-test') + tf_rep = prepare(model) + output = tf_rep.run({'a':a, 'b':b, 'c':c, 'p':p}) + np.testing.assert_almost_equal(output["Y"], 2) + + # test SequenceConstruct and SequenceErase + seq_construct_node = helper.make_node('SequenceConstruct', ['a', 'b', 'c'], ['S']) + seq_erase_node = helper.make_node('SequenceErase', ['S','p'], ['S1']) + seq_at_node = helper.make_node('SequenceAt', ['S1', 'at'], ['Y']) + + graph = helper.make_graph([seq_construct_node, seq_erase_node, seq_at_node], + name='seq_construct_erase_test', + inputs=[a_value_info, b_value_info, c_value_info, p_value_info, at_value_info], + outputs=[out_value_info]) + model = helper.make_model(graph, producer_name='backend-test') + tf_rep = prepare(model) + output = tf_rep.run({'a':a, 'b':b, 'c':c, 'p':p, 'at':0}) + np.testing.assert_almost_equal(output["Y"], b) + output = tf_rep.run({'a':a, 'b':b, 'c':c, 'p':p, 'at':1}) + np.testing.assert_almost_equal(output["Y"], c) + + def test_relu_node_inplace(self): + X = np.random.randn(3, 2).astype(np.float32) + Y_ref = np.clip(X, 0, np.inf) + + node_def = helper.make_node("Relu", ["X"], ["X1"]) + + graph_def = helper.make_graph( + [node_def], + name="test", + inputs=[helper.make_tensor_value_info("X", TensorProto.FLOAT, [3, 2])], + outputs=[ + helper.make_tensor_value_info("X1", TensorProto.FLOAT, [3, 2]) + ]) + tf_rep = prepare(helper.make_model(graph_def)) + output = tf_rep.run({"X": X}) + np.testing.assert_almost_equal(output.X1, Y_ref) + + def test_initializer(self): + if legacy_onnx_pre_ver(1, 2): + raise unittest.SkipTest( + "The current version of ONNX does not record correctly the opset of Cast." + ) + X = np.array([[1, 2], [3, 4]]).astype(np.float32) + Y = np.array([[1, 2], [3, 4]]).astype(np.float32) + weight = np.array([[1, 0], [0, 1]]) + graph_def = helper.make_graph( + [ + helper.make_node("Add", ["X", "Y"], ["Z0"]), + helper.make_node("Cast", ["Z0"], ["Z"], to=TensorProto.FLOAT), + helper.make_node("Mul", ["Z", "weight"], ["W"]), + helper.make_node("Tanh", ["W"], ["W1"]), + helper.make_node("Sigmoid", ["W1"], ["W2"]) + ], + name="test_initializer", + inputs=[ + helper.make_tensor_value_info("X", TensorProto.FLOAT, (2, 2)), + helper.make_tensor_value_info("Y", TensorProto.FLOAT, (2, 2)), + helper.make_tensor_value_info("weight", TensorProto.FLOAT, (2, 2)), + ], + outputs=[ + helper.make_tensor_value_info("W2", TensorProto.FLOAT, (2, 2)) + ], + initializer=[ + helper.make_tensor("weight", TensorProto.FLOAT, [2, 2], + weight.flatten().astype(float)) + ]) + + def sigmoid(x): + return 1 / (1 + np.exp(-x)) + + W_ref = sigmoid(np.tanh((X + Y) * weight)) + tf_rep = prepare(helper.make_model(graph_def)) + output = tf_rep.run({"X": X, "Y": Y}) + np.testing.assert_almost_equal(output["W2"], W_ref) + +if __name__ == '__main__': + unittest.main() diff --git a/pt2tf/onnx-tensorflow/test/backend/test_node.py b/pt2tf/onnx-tensorflow/test/backend/test_node.py new file mode 100644 index 0000000..832f1e8 --- /dev/null +++ b/pt2tf/onnx-tensorflow/test/backend/test_node.py @@ -0,0 +1,3724 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import math +import unittest +import numpy as np +import tensorflow as tf +from onnx_tf.backend import onnx_graph_to_tensorflow_rep +from onnx_tf.backend import run_node +from onnx_tf.common import supports_device +from onnx_tf.common.legacy import legacy_onnx_pre_ver, legacy_opset_pre_ver +from onnx_tf.common.pooling_helper import py_pool +from onnx import helper +from onnx import TensorProto +from onnx import defs + + +class TestNode(unittest.TestCase): + """ Tests for nodes + """ + + def _get_rnd_float32(self, low=-1.0, high=1.0, shape=None): + output = np.random.uniform(low, high, shape) + if shape is None: + return np.float32(output) + else: + return output.astype(np.float32) + + def _get_rnd_int(self, low, high=None, shape=None, dtype=np.int32): + return np.random.randint(low, high, size=shape, dtype=dtype) + + def _elu(self, x): + # f(x) = alpha * (exp(x) - 1.) for x < 0, + # f(x) = x for x >= 0 + if x < 0.: + return np.expm1(x) + return x + + def _leaky_relu(self, x, alpha): + # f(x) = alpha * x for x < 0, + # f(x) = x for x >= 0 + if x < 0.: + return alpha * x + return x + + def test_abs(self): + node_def = helper.make_node("Abs", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[1000]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.abs(x)) + + def test_acosh(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support Acosh.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Acosh", ["X"], ["Y"]) + x = self._get_rnd_float32(low=1.0, high=np.finfo(np.float32).max, shape=[3, 4, 5]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.arccosh(x)) + + def test_add(self): + node_def = helper.make_node("Add", ["X", "Y"], ["Z"]) + x = self._get_rnd_float32(shape=[5, 10, 5, 5]) + y = self._get_rnd_float32(shape=[10, 1, 1]) + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], + np.add(x, y.reshape([1, 10, 1, 1]))) + + # node_def = helper.make_node("Add", ["A", "B"], ["C"], broadcast=1) + # a = self._get_rnd([10, 10]) + # b = self._get_rnd([10, 10]) + # output = run_node(node_def, [a, b]) + # np.testing.assert_almost_equal(output["C"], np.add(a, b)) + + # node_def = helper.make_node("Add", ["A", "B"], ["C"], broadcast=1) + # a = self._get_rnd([10, 10]) + # b = self._get_rnd([10,]) + # output = run_node(node_def, [a, b]) + # np.testing.assert_almost_equal(output["C"], np.add(a, b)) + + def test_arg_max(self): + for axis in [0, 1]: + node_def = helper.make_node("ArgMax", ["data"], ["reduced"], + axis=axis, + keepdims=0) + data = self._get_rnd_float32(shape=[10, 10]) + output = run_node(node_def, [data]) + np.testing.assert_almost_equal(output["reduced"], + np.argmax(data, axis=axis)) + # test select_last_index + if not legacy_opset_pre_ver(12): + # select_last_index = 0 + node_def = helper.make_node("ArgMax", ["data"], ["reduced"], + axis=axis, + keepdims=0, + select_last_index=0) + data = self._get_rnd_float32(shape=[10, 10]) + output = run_node(node_def, [data]) + np.testing.assert_almost_equal(output["reduced"], + np.argmax(data, axis=axis)) + # select_last_index = 1 + node_def = helper.make_node("ArgMax", ["data"], ["reduced"], + axis=axis, + keepdims=0, + select_last_index=1) + data = np.array([[1, 2, 3, 5, 3, 4, 5, 1], [2, 9, 3, 5, 9, 4, 5, 1]]) + output = run_node(node_def, [data]) + data = np.flip(data, axis) + result = np.argmax(data, axis=axis) + result = data.shape[axis] - result - 1 + np.testing.assert_almost_equal(output["reduced"], result) + + def test_arg_min(self): + for axis in [0, 1]: + node_def = helper.make_node("ArgMin", ["data"], ["reduced"], + axis=axis, + keepdims=0) + data = self._get_rnd_float32(shape=[10, 10]) + output = run_node(node_def, [data]) + np.testing.assert_almost_equal(output["reduced"], + np.argmin(data, axis=axis)) + # test select_last_index + if not legacy_opset_pre_ver(12): + # select_last_index = 0 + node_def = helper.make_node("ArgMin", ["data"], ["reduced"], + axis=axis, + keepdims=0, + select_last_index=0) + data = self._get_rnd_float32(shape=[10, 10]) + output = run_node(node_def, [data]) + np.testing.assert_almost_equal(output["reduced"], + np.argmin(data, axis=axis)) + # select_last_index = 1 + node_def = helper.make_node("ArgMin", ["data"], ["reduced"], + axis=axis, + keepdims=0, + select_last_index=1) + data = np.array([[1, 2, 3, 5, 3, 4, 5, 1], [2, 7, 3, 5, 2, 4, 5, 6]]) + output = run_node(node_def, [data]) + data = np.flip(data, axis) + result = np.argmin(data, axis=axis) + result = data.shape[axis] - result - 1 + np.testing.assert_almost_equal(output["reduced"], result) + + def test_asinh(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support Asinh.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Asinh", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[3, 4, 5]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.arcsinh(x)) + + def test_atanh(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support Atanh.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Atanh", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[3, 4, 5]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.arctanh(x)) + + def _batch_normalization(self, x, mean, variance, bias, scale, + variance_epsilon): + inv = np.reciprocal(np.sqrt(variance + variance_epsilon)) + if scale is not None: + inv *= scale + return x * inv + (bias - mean * inv if bias is not None else -mean * inv) + + def test_batch_normalization(self): + if legacy_opset_pre_ver(6): + raise unittest.SkipTest("Backend doesn't support consumed flag") + node_def = helper.make_node("BatchNormalization", + ["X", "scale", "bias", "mean", "var"], ["Y"], + epsilon=0.001) + x_shape = [3, 5, 4, 2] + param_shape = [5] + _param_shape = [1, 5, 1, 1] + x = self._get_rnd_float32(0, 1, shape=x_shape) + m = self._get_rnd_float32(0, 1, shape=param_shape) + _m = m.reshape(_param_shape) + v = self._get_rnd_float32(0, 1, shape=param_shape) + _v = v.reshape(_param_shape) + scale = self._get_rnd_float32(0, 1, shape=param_shape) + _scale = scale.reshape(_param_shape) + bias = self._get_rnd_float32(0, 1, shape=param_shape) + _bias = bias.reshape(_param_shape) + golden = self._batch_normalization(x, _m, _v, _bias, _scale, 0.001) + output = run_node(node_def, [x, scale, bias, m, v]) + np.testing.assert_almost_equal(output["Y"], golden, decimal=5) + + def test_cast(self): + if legacy_onnx_pre_ver(1, 2) or legacy_opset_pre_ver(6): + test_cases = [("FLOAT", tf.float32), ("UINT8", tf.uint8), + ("INT8", tf.int8), + ("UINT16", tf.uint16), ("INT16", tf.int16), + ("INT32", tf.int32), ("INT64", tf.int64), ("BOOL", tf.bool), + ("FLOAT16", tf.float16), ("DOUBLE", tf.float64), + ("COMPLEX64", tf.complex64), ("COMPLEX128", tf.complex128)] + else: + test_cases = [(TensorProto.FLOAT, tf.float32), + (TensorProto.UINT8, tf.uint8), (TensorProto.INT8, tf.int8), + (TensorProto.UINT16, tf.uint16), + (TensorProto.INT16, tf.int16), + (TensorProto.INT32, tf.int32), + (TensorProto.INT64, tf.int64), (TensorProto.BOOL, tf.bool), + (TensorProto.FLOAT16, tf.float16), + (TensorProto.DOUBLE, tf.float64), + (TensorProto.COMPLEX64, tf.complex64), + (TensorProto.COMPLEX128, tf.complex128)] + if not legacy_opset_pre_ver(9): + test_cases.append((TensorProto.STRING, tf.string)) + for ty, tf_type in test_cases: + node_def = helper.make_node("Cast", ["input"], ["output"], to=ty) + vector = [2, 3] + output = run_node(node_def, [vector]) + np.testing.assert_equal(output["output"].dtype, tf_type) + + if not legacy_opset_pre_ver(9): + test_cases2 = [(TensorProto.FLOAT, tf.float32), + (TensorProto.INT32, tf.int32), + (TensorProto.INT64, tf.int64), + (TensorProto.DOUBLE, tf.float64)] + for ty, tf_type in test_cases2: + node_def = helper.make_node("Cast", ["input"], ["output"], to=ty) + vector = ['2', '3'] + output = run_node(node_def, [vector]) + np.testing.assert_equal(output["output"].dtype, tf_type) + + def test_ceil(self): + node_def = helper.make_node("Ceil", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[1000]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.ceil(x)) + + def test_compress(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest( + "ONNX version {} doesn't support Compress.".format( + defs.onnx_opset_version())) + axis = 1 + node_def = helper.make_node("Compress", + inputs=['X', 'condition'], + outputs=['Y'], + axis=axis) + x = self._get_rnd_float32(shape=[5, 5, 5]) + cond = np.array([1, 0, 1]) + output = run_node(node_def, inputs=[x, cond]) + np.testing.assert_almost_equal(output['Y'], np.compress(cond, x, axis=axis)) + + def test_concat(self): + shape = [10, 20, 5] + for axis in range(len(shape)): + node_def = helper.make_node("Concat", ["X1", "X2"], ["Y"], axis=axis) + x1 = self._get_rnd_float32(shape=shape) + x2 = self._get_rnd_float32(shape=shape) + output = run_node(node_def, [x1, x2]) + np.testing.assert_almost_equal(output["Y"], np.concatenate((x1, x2), + axis)) + + def test_constant(self): + shape = [16, 16] + values = np.random.randn(*shape).flatten().astype(float) + const2_onnx = helper.make_tensor("const2", TensorProto.DOUBLE, shape, + values) + node_def = helper.make_node("Constant", [], ["Y"], value=const2_onnx) + output = run_node(node_def, []) + np.testing.assert_equal(output["Y"].shape, shape) + np.testing.assert_almost_equal(output["Y"].flatten(), values) + + # test sparse tensor + if not legacy_opset_pre_ver(11): + expected = np.array([[1, 0, 0, 0], [0, 0, 2, 0], [0, 0, 0, 0]]) + x = np.array([[0, 0], [1, 2]]).flatten().astype(np.int64) + values = helper.make_tensor("values", TensorProto.INT32, [2], [1, 2]) + indices = helper.make_tensor("indices", TensorProto.INT64, [2, 2], x) + a = helper.make_sparse_tensor(values, indices, [3, 4]) + node_def = helper.make_node("Constant", [], ["Y"], sparse_value=a) + output = run_node(node_def, []) + b = tf.sparse_to_dense(output["Y"].indices, output["Y"].dense_shape, + output["Y"].values) + result = b.eval(session=tf.Session()) + np.testing.assert_equal(result, expected) + + if not legacy_opset_pre_ver(12): + float_attr = 1.0 + floats_attr = [1.0, 2.0, 3.0] + int_attr = np.int64(123) + ints_attr = [np.int64(4), np.int64(5), np.int64(6)] + string_attr = 'The Cat in the Hat' + strings_attr = [ + 'Green Eggs and Ham', 'How the Grinch Stole Christmas!', + 'The Cat in the Hat Comes Back' + ] + testcases = [(helper.make_node("Constant", [], ["Y"], + value_float=float_attr), float_attr), + (helper.make_node("Constant", [], ["Y"], + value_floats=floats_attr), floats_attr), + (helper.make_node("Constant", [], ["Y"], + value_int=int_attr), int_attr), + (helper.make_node("Constant", [], ["Y"], + value_ints=ints_attr), ints_attr), + (helper.make_node("Constant", [], ["Y"], + value_string=string_attr), string_attr), + (helper.make_node("Constant", [], ["Y"], + value_strings=strings_attr), strings_attr)] + for node_def, expected in testcases: + output = run_node(node_def, []) + if isinstance(expected, str): + np.testing.assert_string_equal(output["Y"].decode('UTF-8'), expected) + elif isinstance(expected, list) and isinstance(expected[0], str): + for i in range(len(expected)): + np.testing.assert_string_equal(output['Y'][i].decode('UTF-8'), + expected[i]) + else: + np.testing.assert_equal(output["Y"], expected) + + def test_constant_fill(self): + if not legacy_opset_pre_ver(9): + raise unittest.SkipTest( + "ONNX version {} doesn't support ConstantFill.".format( + defs.onnx_opset_version())) + shape = [1, 2, 3, 4] + extra_shape = [5, 6] + value = 3. + node_def = helper.make_node( + "ConstantFill", + ["X"], + ["Y"], + value=value, + extra_shape=extra_shape, + dtype=1, + ) + x = self._get_rnd_float32(shape=shape) + y = np.zeros(shape + extra_shape) + y.fill(value) + output = run_node(node_def, [x]) + np.testing.assert_equal(output["Y"].dtype, tf.float32) + np.testing.assert_equal(output["Y"], y) + + def test_constant_of_shape(self): + if defs.onnx_opset_version() < 9: + raise unittest.SkipTest( + "ONNX version {} doesn't support ConstantOfShape.".format( + defs.onnx_opset_version())) + v = helper.make_tensor("value", TensorProto.FLOAT, [1], [1]) + node_def = helper.make_node("ConstantOfShape", ["X"], ["Y"], value=v) + x = np.array([4, 3, 2]) + output = run_node(node_def, inputs=[x]) + np.testing.assert_almost_equal(output["Y"], np.ones(x, dtype=np.float32)) + v = helper.make_tensor("value", TensorProto.INT32, [1], [0]) + node_def = helper.make_node("ConstantOfShape", ["X"], ["Y"], value=v) + x = np.array([10, 6]) + output = run_node(node_def, inputs=[x]) + np.testing.assert_almost_equal(output["Y"], np.zeros(x, dtype=np.int32)) + + def test_conv(self): + device = "CUDA" if supports_device("CUDA") else "CPU" + + N, C, H, W = 4, 3, 5, 5 + x_shape = [N, C, H, W] + K, kH, kW = 6, 3, 3 + weight_shape = [K, C, kH, kW] + node_def = helper.make_node("Conv", ["X", "weights"], ["Y"], + pads=[1, 1, 1, 1], + kernel_shape=[kH, kW]) + + x = self._get_rnd_float32(shape=x_shape) + weights = self._get_rnd_float32(shape=weight_shape) + output = run_node(node_def, [x, weights], device=device) + + out_shape = [N, K, H, W] + test_output = np.zeros(out_shape) + for n in range(N): + for c in range(C): + for h in range(H): + for w in range(W): + for k in range(K): + for kh in range(kH): + for kw in range(kW): + h_in_range = (h - kH // 2 + kh) < H and (h - kH // 2 + + kh) >= 0 + w_in_range = (w - kW // 2 + kw) < W and (w - kW // 2 + + kw) >= 0 + if h_in_range and w_in_range: + test_output[n][k][h][w] += ( + x[n][c][h - kH // 2 + kh][w - kW // 2 + kw] * + weights[k][c][kh][kw]) + + np.testing.assert_almost_equal(output["Y"], test_output, decimal=5) + + def test_conv_integer(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support ConvInteger.".format( + defs.onnx_opset_version())) + + # Test w_zero_point + x = np.array([2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.int8).reshape( + (1, 1, 3, 3)) + w = np.array([2, 2, 2, 2]).astype(np.int8).reshape((1, 1, 2, 2)) + w_zero_point = np.int8(1) + y = np.array([16, 20, 28, 32]).astype(np.int32).reshape((1, 1, 2, 2)) + + node = helper.make_node("ConvInteger", + ["X", "W", "x_zero_point", "w_zero_point"], ["Y"], + kernel_shape=[2, 2], + pads=[0, 0, 0, 0], + dilations=[1, 1]) + output = run_node(node, [x, w, np.int8(0), w_zero_point]) + np.testing.assert_almost_equal(output["Y"], y) + + # Test x_zero_point and w_zero_point + x = np.array([2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.int8).reshape( + (1, 1, 3, 3)) + x_zero_point = np.int8(1) + w = np.array([2, 2, 2, 2]).astype(np.int8).reshape((1, 1, 2, 2)) + w_zero_point = np.int8(1) + y = np.array([12, 16, 24, 28]).astype(np.int32).reshape((1, 1, 2, 2)) + + node = helper.make_node("ConvInteger", + ["X", "W", "x_zero_point", "w_zero_point"], ["Y"], + kernel_shape=[2, 2], + pads=[0, 0, 0, 0], + dilations=[1, 1]) + output = run_node(node, [x, w, x_zero_point, w_zero_point]) + np.testing.assert_almost_equal(output["Y"], y) + + # Test w_zero_point as 1d tensor + x = np.array([2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.int8).reshape( + (1, 1, 3, 3)) + w = np.array([2, 2, 2, 2]).astype(np.int8).reshape((1, 1, 2, 2)) + w_zero_point = np.array([1]).astype(np.int8) + y = np.array([16, 20, 28, 32]).astype(np.int32).reshape((1, 1, 2, 2)) + + node = helper.make_node("ConvInteger", + ["X", "W", "x_zero_point", "w_zero_point"], ["Y"], + kernel_shape=[2, 2], + pads=[0, 0, 0, 0], + dilations=[1, 1]) + output = run_node(node, [x, w, np.int8(0), w_zero_point]) + np.testing.assert_almost_equal(output["Y"], y) + + # Test w_zero_point as 1d tensor shape 2 + x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]).astype(np.int8).reshape( + (1, 1, 3, 3)) + w = np.array([2, 2, 2, 2, 2, 2, 2, 2]).astype(np.int8).reshape((2, 1, 2, 2)) + w_zero_point = np.array([1, 2]).astype(np.int8) + y = np.array([12, 16, 24, 28, 0, 0, 0, 0]).astype(np.int32).reshape( + (1, 2, 2, 2)) + + node = helper.make_node("ConvInteger", + ["X", "W", "x_zero_point", "w_zero_point"], ["Y"], + kernel_shape=[2, 2], + pads=[0, 0, 0, 0], + dilations=[1, 1]) + output = run_node(node, [x, w, np.int8(0), w_zero_point]) + np.testing.assert_almost_equal(output["Y"], y) + + def test_conv_transpose(self): + device = "CUDA" if supports_device("CUDA") else "CPU" + + pads = [1, 1] + node_def = helper.make_node("ConvTranspose", ["X", "weights"], ["Y"], + pads=pads) + x_shape = [1, 3, 4] + x = self._get_rnd_float32(shape=x_shape) + weight_shape = [3, 5, 2] + weights = self._get_rnd_float32(shape=weight_shape) + output = run_node(node_def, [x, weights], device=device) + + padh_left = weight_shape[2]-1-pads[0] + padh_right = weight_shape[2]-1-pads[1] + kh = weight_shape[2] + outh = x_shape[2] + padh_right + padh_right - (kh - 1) + + out_shape = [x_shape[0], weight_shape[1], outh] + + test_output = np.zeros(out_shape) + for b in range(0, x_shape[0]): + for m in range(0, weight_shape[1]): + for c in range(0, x_shape[1]): + for h in range(0, outh): + for k in range(h , h + kh): + if (k - padh_left >= 0): + test_output[b][m][h] += x[b][c][k-padh_left] * weights[c][m][kh+h-1-k] + + np.testing.assert_almost_equal(output["Y"], test_output, decimal=5) + + # test for spatial dimension of colnolution is 2 + pads = [1, 1, 1, 1] + node_def = helper.make_node("ConvTranspose", ["X", "weights"], ["Y"], + pads=pads) + x_shape = [1, 3, 4, 6] + x = self._get_rnd_float32(shape=x_shape) + weight_shape = [3, 5, 2, 2] + weights = self._get_rnd_float32(shape=weight_shape) + output = run_node(node_def, [x, weights],device=device) + + padh_left = weight_shape[2]-1-pads[0] + padh_right = weight_shape[2]-1-pads[1] + padw_left = weight_shape[3]-1-pads[2] + padw_right = weight_shape[3]-1-pads[3] + + kh = weight_shape[2] + kw = weight_shape[3] + outh = x_shape[2] + padh_right + padh_right - (kh - 1) + outw = x_shape[3] + padw_right + padw_right - (kw - 1) + + out_shape = [x_shape[0], weight_shape[1], outh, outw] + + test_output = np.zeros(out_shape) + for b in range(0, x_shape[0]): + for m in range(0, weight_shape[1]): + for c in range(0, x_shape[1]): + for h in range(0, outh): + for w in range(0, outw): + for k1 in range(h , h + kh): + for k2 in range(w , w + kw): + if (k1 - padh_left >= 0 and k2 - padw_left >= 0): + test_output[b][m][h][w] += x[b][c][k1-padh_left][k2-padw_left] * weights[c][m][kh+h-1-k1][kw+w-1-k2] + + np.testing.assert_almost_equal(output["Y"], test_output, decimal=5) + + def test_cosh(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support Cosh.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Cosh", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[3, 4, 5]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.cosh(x)) + + def test_cumsum(self): + if legacy_opset_pre_ver(11): + raise unittest.SkipTest("ONNX version {} doesn't support CumSum.".format( + defs.onnx_opset_version())) + x = np.array([[1, 2, 3], [4, 5, 6]]).astype(np.int32) + axis = 0 + node_def = helper.make_node("CumSum", ["x", "axis"], ["y"]) + # note: if axis is not provided, np.cumsum() will compute over flattened array, + # which is different than the TensorFlow behavior + y = np.cumsum(x, axis).astype(np.int32) + output = run_node(node_def, [x, axis]) + np.testing.assert_almost_equal(output["y"], y) + + def test_depth_to_space(self): + node_def = helper.make_node("DepthToSpace", ["X"], ["Y"], blocksize=2) + x_shape = [1, 12, 1, 1] + x = self._get_rnd_float32(shape=x_shape) + output = run_node(node_def, [x]) + x = np.transpose(x, (0, 2, 3, 1)) + y = np.reshape(np.swapaxes(x.reshape(1, 1, 1, 2, 2, 3), 2, 3), (1, 2, 2, 3)) + y = np.transpose(y, (0, 3, 1, 2)) + np.testing.assert_almost_equal(output["Y"], y, decimal=5) + + def test_dequantize_linear(self): + node_def = helper.make_node("DequantizeLinear", + ["x", "x_scale", "x_zero_point"], ["y"]) + for x, x_zero_point in [[ + self._get_rnd_int(-128, 127, [2, 6], np.int8), + self._get_rnd_int(-128, 127, dtype=np.int8) + ], + [ + self._get_rnd_int(0, 255, [2, 6], np.uint8), + self._get_rnd_int(0, 255, dtype=np.uint8) + ], + [self._get_rnd_int(-512, 512, [2, 6]), + np.int32(0)]]: + x_scale = self._get_rnd_float32(-10., 10) + y = np.subtract(np.float32(x), np.float32(x_zero_point)) + y = np.multiply(y, x_scale) + output = run_node(node_def, [x, x_scale, x_zero_point]) + np.testing.assert_almost_equal(output["y"], y) + + def test_div(self): + node_def = helper.make_node("Div", ["X", "Y"], ["Z"]) + x = self._get_rnd_float32(shape=[10, 10]) + y = self._get_rnd_float32(shape=[10, 10]) + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], np.divide(x, y)) + + def test_dropout(self): + # Since current ONNX only support inference and + # dropout at inference mode is a no-op, + # therefore dropout is always a no-op operator + # in ONNX. + node_def = helper.make_node("Dropout", ["X"], ["Y"]) + if legacy_opset_pre_ver(7): + # at inference mode, is_test is always set to 1 + node_def = helper.make_node("Dropout", ["X"], ["Y"], is_test=1) + x = self._get_rnd_float32(shape=[3, 4, 5]) + y = x + output = run_node(node_def, [x]) + np.testing.assert_equal(output["Y"], y) + + def test_dot(self): + # this op is removed + # remove this test in the future + return + node_def = helper.make_node("Dot", ["X", "Y"], ["Z"]) + x = np.floor(self._get_rnd_float32(shape=[10, 10])) + y = np.floor(self._get_rnd_float32(shape=[10, 10])) + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], np.dot(x, y)) + + def test_dynamic_quantize_linear(self): + if legacy_opset_pre_ver(11): + raise unittest.SkipTest( + "ONNX version {} doesn't support DynamicQuantizeLinear.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("DynamicQuantizeLinear", ["X"], + ["Y", "Y_Scale", "Y_Zero_Point"]) + x = self._get_rnd_float32(shape=[3, 4]) + min_x = np.minimum(0, np.min(x)) + max_x = np.maximum(0, np.max(x)) + y_scale = np.float32((max_x - min_x) / (255 - 0)) # uint8 -> [0, 255] + y_zero_point = np.clip(round((0 - min_x) / y_scale), 0, + 255).astype(np.uint8) + y = np.clip(np.round(x / y_scale) + y_zero_point, 0, 255).astype(np.uint8) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], y) + np.testing.assert_almost_equal(output["Y_Scale"], y_scale) + np.testing.assert_almost_equal(output["Y_Zero_Point"], y_zero_point) + + def test_elu(self): + node_def = helper.make_node("Elu", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[100]) + output = run_node(node_def, [x]) + test_output = [self._elu(a) for a in x] + np.testing.assert_almost_equal(output["Y"], test_output) + + def test_equal(self): + node_def = helper.make_node("Equal", ["X", "Y"], ["Z"]) + x = self._get_rnd_float32(shape=[5, 3, 3, 2]) + y = self._get_rnd_float32(shape=[3, 3, 1]) + output = run_node(node_def, [x, y]) + np.testing.assert_equal(output["Z"], np.equal(x, + np.reshape(y, [1, 3, 3, 1]))) + + def test_erf(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support Erf.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Erf", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[3, 4, 5]) + output = run_node(node_def, [x]) + exp_output = np.vectorize(math.erf)(x).astype(np.float32) + np.testing.assert_allclose(output['Y'], exp_output, rtol=1e-6, atol=1e-6) + + def test_exp(self): + node_def = helper.make_node("Exp", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[100]) + x = x - 3.6 + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.exp(x)) + + def test_expand(self): + node_def = helper.make_node("Expand", ["X", "shape"], ["Y"]) + x = [[True], [False], [True]] + shape = [2, 1, 6] + y = x * np.ones(shape, dtype=np.bool) + output = run_node(node_def, [x, shape]) + np.testing.assert_almost_equal(output["Y"], y) + + def test_eye_like(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support EyeLike.".format( + defs.onnx_opset_version())) + for shape in [[6, 10], [10, 6]]: + for off_diagonal_offset in [-10, -6, -3, 0, 3, 6, 7, 10]: + node_def = helper.make_node("EyeLike", ['x'], ['y'], + dtype=1, + k=off_diagonal_offset) + x = self._get_rnd_int(0, 100, shape=shape) + y = np.eye(shape[0], shape[1], k=off_diagonal_offset, dtype=np.float32) + output = run_node(node_def, [x]) + np.testing.assert_equal(output['y'], y) + + def test_flatten(self): + shape = [10, 2, 3, 4, 5] + x = self._get_rnd_float32(shape=shape) + for axis in range(-len(shape), len(shape)): + node_def = helper.make_node("Flatten", ["X"], ["Y"], axis=axis) + output = run_node(node_def, [x]) + if axis == 0: + new_shape = (1, -1) + else: + new_shape = (np.prod(shape[0:axis]).astype(int), -1) + np.testing.assert_almost_equal(output["Y"], np.reshape(x, new_shape)) + + def test_gather(self): + node_def = helper.make_node("Gather", ["X", "Y"], ["Z"]) + x = self._get_rnd_float32(shape=[10, 10]) + y = [[0, 1], [1, 2]] + output = run_node(node_def, [x, y]) + test_output = np.zeros((2, 2, 10)) + for i in range(0, 2): + for j in range(0, 10): + test_output[0][i][j] = x[i][j] + for i in range(0, 2): + for j in range(0, 10): + test_output[1][i][j] = x[i + 1][j] + np.testing.assert_almost_equal(output["Z"], test_output) + if defs.onnx_opset_version() >= 11: + # test negative indices + y = [[-10, -9], [1, -8]] + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], test_output) + # test out of bound indices + for y in ([[-10, 11], [1, -8]], [[-10, -11], [1, -8]]): + try: + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], test_output) + raise AssertionError("Expected ValueError not raised for indices %d" % + str(y)) + except tf.errors.InvalidArgumentError as e: + assert 'Gather indices are out of bound' in str(e), str(y) + # test non-0 and negative axis + axis = -3 + node_def = helper.make_node("Gather", ["X", "Y"], ["Z"], axis=axis) + x = np.reshape(np.arange(5 * 4 * 3 * 2), (5, 4, 3, 2)) + y = np.array([0, 1, 3]) + test_output = np.take(x, y, axis=axis) + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], test_output) + # test axis attribute validation + for axis in [-5, 4, 10]: + try: + node_def = helper.make_node("Gather", ["X", "Y"], ["Z"], axis=axis) + run_node(node_def, [x, y]) + raise AssertionError( + "Expected ValueError not raised for axis value %d" % axis) + except ValueError as e: + assert 'out of bounds' in str(e), str(e) + ' for axis ' + str(axis) + + def test_gather_elements(self): + if legacy_opset_pre_ver(11): + raise unittest.SkipTest( + "ONNX version {} doesn't support GatherElements.".format( + defs.onnx_opset_version())) + + data_dtype = np.int32 + data = np.array([ + [[10, 11], [12, 13], [14, 15], [16, 17], [18, 19]], + [[20, 21], [22, 23], [24, 25], [26, 27], [28, 29]], + [[30, 31], [32, 33], [34, 35], [36, 37], [38, 39]], + [[40, 41], [42, 43], [44, 45], [46, 47], [48, 49]], + ], + dtype=data_dtype) + + # test default axis + indices = np.array([[[3, 0], [2, 0], [1, 0], [0, 0], [3, 1]]], + dtype=np.int64) + ref_output = np.array([[[40, 11], [32, 13], [24, 15], [16, 17], [48, 29]]], + dtype=data_dtype) + node_def = helper.make_node("GatherElements", ["data", "indices"], + ["outputs"]) + output = run_node(node_def, [data, indices]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + + # test non-default axis + indices = np.array([[[3, 0], [2, 1], [1, 2], [0, 3]]], dtype=data_dtype) + ref_output = np.array([ + [[16, 11], [14, 13], [12, 15], [10, 17]], + ], + dtype=data_dtype) + node_def = helper.make_node("GatherElements", ["data", "indices"], + ["outputs"], + axis=1) + output = run_node(node_def, [data, indices]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + + # test negative axis + indices = np.array([ + [[1, 1, -2], [1, -2, 1], [-1, 1, -1], [-2, 1, -2], [-2, 1, 1]], + ], + dtype=data_dtype) + ref_output = np.array([ + [[11, 11, 10], [13, 12, 13], [15, 15, 15], [16, 17, 16], [18, 19, 19]], + ], + dtype=data_dtype) + node_def = helper.make_node("GatherElements", ["data", "indices"], + ["outputs"], + axis=2) + output = run_node(node_def, [data, indices]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + + def test_gather_nd(self): + if legacy_opset_pre_ver(11): + raise unittest.SkipTest( + "ONNX version {} doesn't support GatherND.".format( + defs.onnx_opset_version())) + + # valid positive and negative indices for elements + data = np.array([[0, 1], [2, 3]], dtype=np.int64) + indices = np.array([[0, 0], [1, 1], [-1, -2]], dtype=np.int64) + ref_output = np.array([0, 3, 2], dtype=np.int64) + node_def = helper.make_node("GatherND", ["data", "indices"], ["outputs"]) + output = run_node(node_def, [data, indices]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + + # valid positive and negative indices for slices + data = np.arange(16, dtype=np.int32).reshape([2, 2, 4]) + indices = np.array([[0, 0], [-1, -2]], dtype=np.int64) + ref_output = np.array([[0, 1, 2, 3], [8, 9, 10, 11]], dtype=np.int32) + output = run_node(node_def, [data, indices]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + indices = np.array([[[0, 0]], [[-1, 0]]], dtype=np.int64) + ref_output = np.array([[[0, 1, 2, 3]], [[8, 9, 10, 11]]], dtype=np.int32) + output = run_node(node_def, [data, indices]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + + # indices out of bounds + indices = np.array([[5, 0], [-1, -3]], dtype=np.int64) + with np.testing.assert_raises(tf.errors.InvalidArgumentError): + output = run_node(node_def, [data, indices]) + indices = np.array([[1, 1, 6], [-2, -1, -9]], dtype=np.int32) + with np.testing.assert_raises(tf.errors.InvalidArgumentError): + output = run_node(node_def, [data, indices]) + + def test_gemm(self): + # Compute Y = alpha * A * B + beta * C + node_def = helper.make_node("Gemm", ["A", "B", "C"], ["Y"], + transA=0, + transB=0, + alpha=1.0, + beta=1.0) + x = np.floor(self._get_rnd_float32(shape=[10, 10])) + y = np.floor(self._get_rnd_float32(shape=[10, 10])) + z = np.floor(self._get_rnd_float32(shape=[10, 10])) + output = run_node(node_def, [x, y, z]) + test_output = np.matmul(x, y) + z + np.testing.assert_almost_equal(output["Y"], test_output) + + def test_global_average_pool(self): + # Image case: (N x C x H x W), where N is the batch size, + # C is the number of channels, and H and W are the height + # and the width of the data + # + # Non-image case: (N x C x D1 x D2 ... Dn) + # + # Output data tensor from pooling across the input tensor. + # Dimensions will be N x C x 1 x 1 + node_def = helper.make_node("GlobalAveragePool", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[10, 10, 2, 3]) + output = run_node(node_def, [x]) + test_output = np.zeros([10, 10, 1, 1]) + for i1 in range(0, 10): + for i2 in range(0, 10): + sum = 0 + for j1 in range(0, 2): + for j2 in range(0, 3): + sum += x[i1][i2][j1][j2] + test_output[i1][i2][0][0] = sum / 6. + np.testing.assert_almost_equal(output["Y"], test_output) + + def test_hardmax(self): + shape = [2, 3, 4, 5] + x = self._get_rnd_float32(shape=shape) + for axis in range(-len(shape), len(shape)): + node_def = helper.make_node("Hardmax", ["X"], ["Y"], axis=axis) + output = run_node(node_def, [x]) + shape_in_2d = (np.prod(shape[0:axis]).astype(int), + np.prod(shape[axis:len(shape)])) + x_in_2d = np.reshape(x, shape_in_2d) + y = np.eye(x_in_2d.shape[1], dtype=x.dtype)[np.argmax(x_in_2d, axis=1)] + np.testing.assert_almost_equal(output["Y"], np.reshape(y, shape)) + + def test_if(self): + true_val = helper.make_tensor(name='true_tensor', + data_type=TensorProto.INT64, + dims=(), + vals=[np.int64(1)]) + false_val = helper.make_tensor(name='false_tensor', + data_type=TensorProto.INT64, + dims=(), + vals=[np.int64(0)]) + true_node = helper.make_node('Constant', + inputs=[], + outputs=['true'], + value=true_val) + false_node = helper.make_node('Constant', + inputs=[], + outputs=['false'], + value=false_val) + + true_out = helper.make_tensor_value_info('true', TensorProto.INT64, []) + false_out = helper.make_tensor_value_info('false', TensorProto.INT64, []) + + true_graph = helper.make_graph(nodes=[true_node], + name="true_graph", + inputs=[], + outputs=[true_out]) + false_graph = helper.make_graph(nodes=[false_node], + name="false_graph", + inputs=[], + outputs=[false_out]) + + node_def = helper.make_node('If', ['cond'], ['outputs'], + then_branch=true_graph, + else_branch=false_graph) + + for cond, exp in [[True, true_val], [False, false_val]]: + output = run_node(node_def, [cond]) + np.testing.assert_equal(output['outputs'], exp.int64_data) + + x = self._get_rnd_int(low=-50, high=50, dtype=np.int64) + y = self._get_rnd_int(low=-50, high=50, dtype=np.int64) + z = self._get_rnd_int(low=-50, high=50, dtype=np.int64) + x_val = helper.make_tensor(name='x_tensor', + data_type=TensorProto.INT64, + dims=(), + vals=[x]) + y_val = helper.make_tensor(name='y_tensor', + data_type=TensorProto.INT64, + dims=(), + vals=[y]) + z_val = helper.make_tensor(name='z_tensor', + data_type=TensorProto.INT64, + dims=(), + vals=[z]) + x_node = helper.make_node('Constant', inputs=[], outputs=['x'], value=x_val) + y_node = helper.make_node('Constant', inputs=[], outputs=['y'], value=y_val) + z_node = helper.make_node('Constant', inputs=[], outputs=['z'], value=z_val) + add_node = helper.make_node('Add', inputs=['x', 'y'], outputs=['sum']) + sub_node = helper.make_node('Sub', inputs=['x', 'y'], outputs=['diff']) + mul1_node = helper.make_node('Mul', inputs=['sum', 'z'], outputs=['prod1']) + mul2_node = helper.make_node('Mul', inputs=['diff', 'z'], outputs=['prod2']) + + x_out = helper.make_tensor_value_info('x', TensorProto.INT64, []) + y_out = helper.make_tensor_value_info('y', TensorProto.INT64, []) + z_out = helper.make_tensor_value_info('z', TensorProto.INT64, []) + sum_out = helper.make_tensor_value_info('sum', TensorProto.INT64, []) + diff_out = helper.make_tensor_value_info('diff', TensorProto.INT64, []) + prod1_out = helper.make_tensor_value_info('prod1', TensorProto.INT64, []) + prod2_out = helper.make_tensor_value_info('prod2', TensorProto.INT64, []) + + true_graph = helper.make_graph(nodes=[add_node, mul1_node], + name="true_graph", + inputs=[x_out, y_out, z_out], + outputs=[sum_out, prod1_out]) + false_graph = helper.make_graph(nodes=[sub_node, mul2_node], + name="false_graph", + inputs=[x_out, y_out, z_out], + outputs=[diff_out, prod2_out]) + + less_node = helper.make_node('Less', inputs=['x', 'y'], outputs=['cond']) + if_node = helper.make_node('If', + inputs=['cond'], + outputs=['result'], + then_branch=true_graph, + else_branch=false_graph) + + result_out = helper.make_tensor_value_info('result', TensorProto.INT64, []) + + graph = helper.make_graph( + nodes=[x_node, y_node, z_node, less_node, if_node], + name="test_if", + inputs=[], + outputs=[result_out]) + + tf_rep = onnx_graph_to_tensorflow_rep(graph) + output = tf_rep.run({}) + expected = [x + y, (x + y) * z] if x < y else [x - y, (x - y) * z] + np.testing.assert_equal(output['result'], expected) + + def test_image_sacler(self): + # Input: (N x C x H x W), where N is the batch size, + # C is the number of channels, and H and W are the height + # and the width of the data + # Scale: (flout, default 1.0) the scale to apply + # Bias: applied to each channel, same size as C + # Output has same shape and type as input + x = self._get_rnd_float32(shape=[1, 3, 224, 224]) + #random distribution over [0,1), so add 0.1 + scale = np.random.rand(1)[0] + 0.1 + bias = np.random.rand(3) + node_def = helper.make_node("ImageScaler", ["X"], ["Y"], + scale=scale, + bias=bias) + output = run_node(node_def, [x]) + test_out = np.multiply(x, scale) + test_out = np.transpose(test_out, [0, 2, 3, 1]) + test_out = np.add(test_out, bias) + test_out = np.transpose(test_out, [0, 3, 1, 2]) + np.testing.assert_almost_equal(output["Y"], test_out) + + def test_is_inf(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest("ONNX version {} doesn't support IsInf.".format( + defs.onnx_opset_version())) + input = np.array([-1.2, np.nan, np.inf, 2.8, np.NINF, np.inf], + dtype=np.float32) + expected_output = { + "node_def": np.isinf(input), + "node_def_neg_false": np.isposinf(input), + "node_def_pos_false": np.isneginf(input) + } + node_defs = { + "node_def": + helper.make_node("IsInf", ["X"], ["Y"]), + "node_def_neg_false": + helper.make_node("IsInf", ["X"], ["Y"], detect_negative=0), + "node_def_pos_false": + helper.make_node("IsInf", ["X"], ["Y"], detect_positive=0) + } + for key in node_defs: + output = run_node(node_defs[key], [input]) + np.testing.assert_equal(output["Y"], expected_output[key]) + + def test_isnan(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support IsNaN.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("IsNaN", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[3, 3]) + x[0][1] = x[1][0] = x[2][2] = np.nan + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.isnan(x)) + + def test_global_lp_pool(self): + # Image case: (N x C x H x W), where N is the batch size, + # C is the number of channels, and H and W are the height + # and the width of the data + # + # Non-image case: (N x C x D1 x D2 ... Dn) + # + # Output data tensor from pooling across the input tensor. + # Dimensions will be N x C x 1 x 1 + node_def = helper.make_node("GlobalLpPool", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[10, 10, 2, 3]) + output = run_node(node_def, [x]) + test_output = np.zeros([10, 10, 1, 1]) + for i1 in range(0, 10): + for i2 in range(0, 10): + tmp = np.zeros([2, 3]) + for j1 in range(0, 2): + for j2 in range(0, 3): + tmp[j1][j2] = x[i1][i2][j1][j2] + test_output[i1][i2][0][0] = np.linalg.norm(tmp) + np.testing.assert_almost_equal(output["Y"], test_output, decimal=5) + + def test_global_max_pool(self): + # Image case: (N x C x H x W), where N is the batch size, + # C is the number of channels, and H and W are the height + # and the width of the data + # + # Non-image case: (N x C x D1 x D2 ... Dn) + # + # Output data tensor from pooling across the input tensor. + # Dimensions will be N x C x 1 x 1 + node_def = helper.make_node("GlobalMaxPool", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[10, 10, 2, 3]) + output = run_node(node_def, [x]) + test_output = np.zeros([10, 10, 1, 1]) + for i1 in range(0, 10): + for i2 in range(0, 10): + max = x[i1][i2][0][0] + for j1 in range(0, 2): + for j2 in range(0, 3): + if max < x[i1][i2][j1][j2]: + max = x[i1][i2][j1][j2] + test_output[i1][i2][0][0] = max + np.testing.assert_almost_equal(output["Y"], test_output) + + def test_less(self): + node_def = helper.make_node("Less", ["X", "Y"], ["Z"]) + x = self._get_rnd_float32(shape=[5, 3, 3, 2]) + y = self._get_rnd_float32(shape=[3, 3, 1]) + output = run_node(node_def, [x, y]) + np.testing.assert_equal(output["Z"], np.less(x, np.reshape(y, + [1, 3, 3, 1]))) + + def test_lp_normalization(self): + for ordr in range(1, 3): + node_def = helper.make_node("LpNormalization", ["X"], ["Y"], p=ordr) + x = self._get_rnd_float32(shape=[2, 2, 3, 2]) + output = run_node(node_def, [x]) + np.testing.assert_allclose( + output["Y"], + x / np.expand_dims(np.linalg.norm(x, axis=-1, ord=ordr), -1), + rtol=1e-3) + + def test_l_r_n(self): + # Each input value is divided by: + # + # (bias+(alpha/size)*sum(xi^2 for every xi in the local region))^beta + alpha = 2.0 + beta = 1.0 + bias = 5.0 + size = 3 + node_def = helper.make_node("LRN", ["X"], ["Y"], + alpha=alpha, + beta=beta, + bias=bias, + size=size) + x = self._get_rnd_float32(shape=[10, 2, 10, 10]) + output = run_node(node_def, [x]) + test_output = np.zeros([10, 10, 10, 2]) + x = np.transpose(x, axes=[0, 2, 3, 1]) + for i1 in range(0, 10): + for i2 in range(0, 10): + for j1 in range(0, 10): + for j2 in range(0, 2): + sqr_sum = 0. + # size of 3 means radius 1 in TF speak + # i.e. the immediate neighbouring values + # if "previous" neighbour exists + if j2 > 0: + sqr_sum += x[i1][i2][j1][j2 - 1] * x[i1][i2][j1][j2 - 1] + # current value + sqr_sum += x[i1][i2][j1][j2] * x[i1][i2][j1][j2] + # if "next" neighbour exists + if j2 < 2 - 1: + sqr_sum += x[i1][i2][j1][j2 + 1] * x[i1][i2][j1][j2 + 1] + test_output[i1][i2][j1][j2] = \ + x[i1][i2][j1][j2] / ((bias + (alpha * 1. / size) * sqr_sum) ** beta) + test_output = np.transpose(test_output, axes=[0, 3, 1, 2]) + np.testing.assert_almost_equal(output["Y"], test_output) + + def test_floor(self): + node_def = helper.make_node("Floor", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[100]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.floor(x)) + + def test_leakyrelu(self): + node_def = helper.make_node("LeakyRelu", ["X"], ["Y"], alpha=0.8) + x = np.floor(self._get_rnd_float32(shape=[100])) + output = run_node(node_def, [x]) + test_output = [self._leaky_relu(a, 0.8) for a in x] + np.testing.assert_almost_equal(output["Y"], test_output) + + def test_log(self): + node_def = helper.make_node("Log", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[100]) + x = x + 3.6 + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.log(x)) + + def test_loop(self): + add1_node = helper.make_node('Add', inputs=['x', 'x'], outputs=['sum1']) + neg_node = helper.make_node('Neg', inputs=['sum1'], outputs=['neg_sum1']) + add2_node = helper.make_node('Add', + inputs=['y', 'neg_sum1'], + outputs=['sum2']) + add3_node = helper.make_node('Add', + inputs=['sum1', 'sum2'], + outputs=['sum3']) + less_node = helper.make_node('Less', + inputs=['sum1', 'sum2'], + outputs=['new_cond']) + greater_node = helper.make_node('Greater', + inputs=['sum1', 'sum2'], + outputs=['new_cond']) + + m_in = helper.make_tensor_value_info('M', TensorProto.INT64, []) + cond_in = helper.make_tensor_value_info('cond', TensorProto.BOOL, []) + cond_int_in = helper.make_tensor_value_info('cond', TensorProto.INT32, []) + x_in = helper.make_tensor_value_info('x', TensorProto.INT32, [None]) + y_in = helper.make_tensor_value_info('y', TensorProto.INT32, [None]) + + cond_out = helper.make_tensor_value_info('cond', TensorProto.BOOL, []) + new_cond_out = helper.make_tensor_value_info('new_cond', TensorProto.BOOL, + []) + sum1_out = helper.make_tensor_value_info('sum1', TensorProto.INT32, [None]) + sum2_out = helper.make_tensor_value_info('sum2', TensorProto.INT32, [None]) + sum3_out = helper.make_tensor_value_info('sum3', TensorProto.INT32, [None]) + + v1_initial = np.array([1, 1], dtype=np.int32) + v2_initial = np.array([100, 100], dtype=np.int32) + + # test for loop + M = np.int64(10) + cond = True # value will be ignore because optional "cond" input will be skip + graph = helper.make_graph(nodes=[add1_node, neg_node, add2_node, add3_node], + name="for_loop_graph", + inputs=[m_in, cond_in, x_in, y_in], + outputs=[cond_out, sum1_out, sum2_out, sum3_out]) + node_def = helper.make_node('Loop', ['M', '', 'v1_initial', 'v2_initial'], + ['v_final', 'scan_outputs'], + body=graph) + output = run_node(node_def, [M, cond, v1_initial, v2_initial]) + v_final = [ + np.array([1024, 1024], dtype=np.int32), + np.array([-1946, -1946], dtype=np.int32) + ] + scan_outputs = [ + np.array([[100, 100], [98, 98], [94, 94], [86, 86], [70, 70], [38, 38], + [-26, -26], [-154, -154], [-410, -410], [-922, -922]], + dtype=np.int32) + ] + np.testing.assert_almost_equal(output['v_final'], v_final) + np.testing.assert_almost_equal(output['scan_outputs'], scan_outputs) + + # test while loop + M = 0 # value will be ignore because optional "M" input will be skip + cond = v1_initial < v2_initial + graph = helper.make_graph( + nodes=[add1_node, neg_node, add2_node, add3_node, less_node], + name="while_loop_graph", + inputs=[m_in, cond_in, x_in, y_in], + outputs=[new_cond_out, sum1_out, sum2_out, sum3_out]) + node_def = helper.make_node('Loop', + ['', 'cond', 'v1_initial', 'v2_initial'], + ['v_final', 'scan_outputs'], + body=graph) + output = run_node(node_def, [M, cond, v1_initial, v2_initial]) + v_final = [ + np.array([64, 64], dtype=np.int32), + np.array([-26, -26], dtype=np.int32) + ] + scan_outputs = [ + np.array([[100, 100], [98, 98], [94, 94], [86, 86], [70, 70], [38, 38]], + dtype=np.int32) + ] + np.testing.assert_almost_equal(output['v_final'], v_final) + np.testing.assert_almost_equal(output['scan_outputs'], scan_outputs) + + # test do-while loop + M = 0 # value will be ignore because optional "M" input will be skip + cond = 1 + graph = helper.make_graph( + nodes=[add1_node, neg_node, add2_node, add3_node, greater_node], + name="do_while_loop_graph", + inputs=[m_in, cond_int_in, x_in, y_in], + outputs=[new_cond_out, sum1_out, sum2_out, sum3_out]) + node_def = helper.make_node('Loop', + ['', 'cond', 'v1_initial', 'v2_initial'], + ['v_final', 'scan_outputs'], + body=graph) + output = run_node(node_def, [M, cond, v1_initial, v2_initial]) + v_final = [ + np.array([2, 2], dtype=np.int32), + np.array([98, 98], dtype=np.int32) + ] + scan_outputs = [np.array([[100, 100]], dtype=np.int32)] + np.testing.assert_almost_equal(output['v_final'], v_final) + np.testing.assert_almost_equal(output['scan_outputs'], scan_outputs) + + # test for loop and while loop conbine + M = np.int64(4) + cond = v1_initial < v2_initial + graph = helper.make_graph( + nodes=[add1_node, neg_node, add2_node, add3_node, less_node], + name="for_and_while_loop_graph", + inputs=[m_in, cond_in, x_in, y_in], + outputs=[new_cond_out, sum1_out, sum2_out, sum3_out]) + node_def = helper.make_node('Loop', + ['M', 'cond', 'v1_initial', 'v2_initial'], + ['v_final', 'scan_outputs'], + body=graph) + output = run_node(node_def, [M, cond, v1_initial, v2_initial]) + v_final = [ + np.array([16, 16], dtype=np.int32), + np.array([70, 70], dtype=np.int32) + ] + scan_outputs = [ + np.array([[100, 100], [98, 98], [94, 94], [86, 86]], dtype=np.int32) + ] + np.testing.assert_almost_equal(output['v_final'], v_final) + np.testing.assert_almost_equal(output['scan_outputs'], scan_outputs) + + # test for loop that doesn't run at all (M = 0) + M = np.int64(0) + cond = True # value will be ignore because optional "cond" input will be skip + graph = helper.make_graph(nodes=[add1_node, neg_node, add2_node, add3_node], + name="for_loop_graph", + inputs=[m_in, cond_in, x_in, y_in], + outputs=[cond_out, sum1_out, sum2_out, sum3_out]) + node_def = helper.make_node('Loop', ['M', '', 'v1_initial', 'v2_initial'], + ['v_final', 'scan_outputs'], + body=graph) + output = run_node(node_def, [M, cond, v1_initial, v2_initial]) + v_final = [ + np.array([1, 1], dtype=np.int32), + np.array([100, 100], dtype=np.int32) + ] + scan_outputs = np.array([], dtype=np.int32).reshape(1, 0, 2) + np.testing.assert_almost_equal(output['v_final'], v_final) + np.testing.assert_almost_equal(output['scan_outputs'], scan_outputs) + + # test while loop that doesn't run at all (cond = False) + M = 0 # value will be ignore because optional "M" input will be skip + cond = False + graph = helper.make_graph( + nodes=[add1_node, neg_node, add2_node, add3_node, less_node], + name="while_loop_graph", + inputs=[m_in, cond_in, x_in, y_in], + outputs=[new_cond_out, sum1_out, sum2_out, sum3_out]) + node_def = helper.make_node('Loop', + ['', 'cond', 'v1_initial', 'v2_initial'], + ['v_final', 'scan_outputs'], + body=graph) + output = run_node(node_def, [M, cond, v1_initial, v2_initial]) + v_final = [ + np.array([1, 1], dtype=np.int32), + np.array([100, 100], dtype=np.int32) + ] + scan_outputs = np.array([], dtype=np.int32).reshape(1, 0, 2) + np.testing.assert_almost_equal(output['v_final'], v_final) + np.testing.assert_almost_equal(output['scan_outputs'], scan_outputs) + + # test while loop that doesn't have any scan_outputs + M = np.int64(4) + cond = v1_initial < v2_initial + graph = helper.make_graph(nodes=[add1_node, neg_node, add2_node, less_node], + name="while_loop_graph", + inputs=[m_in, cond_in, x_in, y_in], + outputs=[new_cond_out, sum1_out, sum2_out]) + node_def = helper.make_node('Loop', + ['M', 'cond', 'v1_initial', 'v2_initial'], + ['v_final'], + body=graph) + output = run_node(node_def, [M, cond, v1_initial, v2_initial]) + v_final = [ + np.array([16, 16], dtype=np.int32), + np.array([70, 70], dtype=np.int32) + ] + np.testing.assert_almost_equal(output['v_final'], v_final) + + # test for loop that doesn't run at all (M = 0) + # and the scan_outputs shape is not the same as the inputs + v1_initial = np.array([[1, 1, 1], [2, 2, 2]], dtype=np.int32) + v3_initial = np.array([[1, 1], [2, 2], [3, 3]], dtype=np.int32) + matmul_node = helper.make_node('MatMul', + inputs=['x', 'z'], + outputs=['product']) + x_in = helper.make_tensor_value_info('x', TensorProto.INT32, [None, None]) + z_in = helper.make_tensor_value_info('z', TensorProto.INT32, [None, None]) + sum1_out = helper.make_tensor_value_info('sum1', TensorProto.INT32, + [None, None]) + z_out = helper.make_tensor_value_info('z', TensorProto.INT32, [None, None]) + product_out = helper.make_tensor_value_info('product', TensorProto.INT32, + [None, None]) + + M = np.int64(0) + cond = True # value will be ignore because optional "cond" input will be skip + graph = helper.make_graph(nodes=[add1_node, matmul_node], + name="for_loop_graph", + inputs=[m_in, cond_in, x_in, z_in], + outputs=[cond_out, sum1_out, z_out, product_out]) + node_def = helper.make_node('Loop', ['M', '', 'v1_initial', 'v3_initial'], + ['v_final', 'scan_outputs'], + body=graph) + output = run_node(node_def, [M, cond, v1_initial, v3_initial]) + v_final = [v1_initial, v3_initial] + scan_outputs = np.array([], dtype=np.int32).reshape(1, 0, 2, 2) + for i in range(len(output['v_final'])): + np.testing.assert_almost_equal(output['v_final'][i], v_final[i]) + np.testing.assert_almost_equal(output['scan_outputs'], scan_outputs) + + # verify infinite loop will get exception + M = 0 # value will be ignore because optional "M" input will be skip + cond = True # value will be ignore because optional "cond" input will be skip + graph = helper.make_graph( + nodes=[add1_node, neg_node, add2_node, add3_node, less_node], + name="while_loop_graph", + inputs=[m_in, cond_in, x_in, y_in], + outputs=[cond_out, sum1_out, sum2_out, sum3_out]) + node_def = helper.make_node('Loop', ['', '', 'v1_initial', 'v2_initial'], + ['v_final', 'scan_outputs'], + body=graph) + try: + output = run_node(node_def, [M, cond, v1_initial, v2_initial]) + raise AssertionError("Expected RuntimeError not raise when Loop inputs " + + "M and cond are both not set at the same time") + except RuntimeError as e: + assert "M and cond in Loop are not set" in str(e) + + def test_matmul_integer(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support MatMulInteger.".format( + defs.onnx_opset_version())) + + node_def = helper.make_node("MatMulInteger", + ["A", "B", "a_zero_point", "b_zero_point"], + ["Z"]) + lower_bound = {np.uint8: 0, np.int8: -20} + for dtype in [np.uint8, np.int8]: + # A & B are 3-D tensor and a_zero_point & b_zero_point are scalar + A = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(2, 3, 4), + dtype=dtype) + B = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(2, 4, 6), + dtype=dtype) + a_zero_point = self._get_rnd_int(lower_bound[dtype], 20, dtype=dtype) + b_zero_point = self._get_rnd_int(lower_bound[dtype], 20, dtype=dtype) + A_minus_zero_point = np.subtract(A.astype(np.int32), + a_zero_point.astype(np.int32)) + B_minus_zero_point = np.subtract(B.astype(np.int32), + b_zero_point.astype(np.int32)) + z = np.matmul(A_minus_zero_point, B_minus_zero_point) + output = run_node(node_def, [A, B, a_zero_point, b_zero_point]) + np.testing.assert_almost_equal(output["Z"], z) + # A & B are 4-D tensor and a_zero_point & b_zero_point are 1-D tensor + A = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(2, 5, 3, 4), + dtype=dtype) + B = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(2, 1, 4, 6), + dtype=dtype) + a_zero_point = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(A.shape[-2]), + dtype=dtype) + b_zero_point = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(B.shape[-1]), + dtype=dtype) + a_zero_point_with_reshape = np.reshape(a_zero_point, [A.shape[-2], 1]) + A_minus_zero_point = np.subtract( + A.astype(np.int32), a_zero_point_with_reshape.astype(np.int32)) + B_minus_zero_point = np.subtract(B.astype(np.int32), + b_zero_point.astype(np.int32)) + z = np.matmul(A_minus_zero_point, B_minus_zero_point) + output = run_node(node_def, [A, B, a_zero_point, b_zero_point]) + np.testing.assert_almost_equal(output["Z"], z) + + node_def = helper.make_node("MatMulInteger", ["A", "B"], ["Z"]) + for dtype in [np.uint8, np.int8]: + # A & B are 3-D tensor + A = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(2, 3, 4), + dtype=dtype) + B = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(2, 4, 6), + dtype=dtype) + z = np.matmul(A.astype(np.int32), B.astype(np.int32)) + output = run_node(node_def, [A, B]) + np.testing.assert_almost_equal(output["Z"], z) + # A & B are 4-D tensor + A = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(2, 5, 3, 4), + dtype=dtype) + B = self._get_rnd_int(lower_bound[dtype], + 20, + shape=(2, 1, 4, 6), + dtype=dtype) + z = np.matmul(A.astype(np.int32), B.astype(np.int32)) + output = run_node(node_def, [A, B]) + np.testing.assert_almost_equal(output["Z"], z) + + def test_max(self): + node_def = helper.make_node("Max", ["X1", "X2", "X3", "X4"], ["Z"]) + x1 = self._get_rnd_float32(shape=[10, 10]) + x2 = self._get_rnd_float32(shape=[10, 10]) + x3 = self._get_rnd_float32(shape=[10, 10]) + x4 = self._get_rnd_float32(shape=[10, 10]) + output = run_node(node_def, [x1, x2, x3, x4]) + test_output = np.maximum(np.maximum(np.maximum(x1, x2), x3), x4) + np.testing.assert_almost_equal(output["Z"], test_output) + + def _test_pooling(self, + input_shape, + kernel_shape, + strides=None, + dilations=None, + pads=None, + auto_pad=None, + ceil_mode=None, + count_include_pad=None, + pooling_type="MAX", + input_dtype=np.float32, + p=None): + + op = "MaxPool" if pooling_type.upper().startswith("MAX") else \ + "AveragePool" if pooling_type.upper() == "AVG" else "LpPool" + node_def_kwargs = { + "op_type": op, + "inputs": ["X"], + "outputs": ["Y"], + "kernel_shape": kernel_shape + } + + if strides is not None: + node_def_kwargs["strides"] = strides + if dilations is not None: + node_def_kwargs["dilations"] = dilations + if pads is not None: + node_def_kwargs["pads"] = pads + if auto_pad is not None: + node_def_kwargs["auto_pad"] = auto_pad + pads = auto_pad + if ceil_mode is not None: + node_def_kwargs["ceil_mode"] = ceil_mode + else: + ceil_mode = 0 + if count_include_pad is not None: + node_def_kwargs["count_include_pad"] = count_include_pad + if p is not None: + node_def_kwargs["p"] = p + + node_def = helper.make_node(**node_def_kwargs) + + if input_dtype == np.float32: + x = self._get_rnd_float32(shape=input_shape) + else: + x = self._get_rnd_int(low = np.iinfo(input_dtype).min, + high = np.iinfo(input_dtype).max, + shape=input_shape, dtype=input_dtype) + + x = self._get_rnd_float32(shape=input_shape) + output = run_node(node_def, [x]) + + test_output = py_pool(x, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + padding=pads, + ceil_mode=ceil_mode, + pooling_type=pooling_type, + include_indices=False, + p=p) + + np.testing.assert_almost_equal(output["Y"], test_output, + decimal=5 if pooling_type=="LP" else 7) + + def test_max_pool_2d(self): + kernel_shape = [1, 2] + strides = [1, 2] + + input_shape = [10, 10, 4, 4] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides) + + def test_max_pool_2d_same_lower(self): + kernel_shape = [1, 2] + strides = [1, 2] + auto_pad = "SAME_LOWER" + + input_shape = [10, 10, 7, 7] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + auto_pad=auto_pad) + + def test_max_pool_2d_ceil_same_lower(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support ceil mode.".format( + defs.onnx_opset_version())) + + kernel_shape = [2, 1] + strides = [1, 2] + auto_pad = "SAME_LOWER" + ceil_mode = 1 + + input_shape = [10, 10, 7, 7] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + auto_pad=auto_pad, + ceil_mode=ceil_mode) + + def test_max_pool_2d_same_upper(self): + kernel_shape = [1, 2] + strides = [1, 2] + auto_pad = "SAME_UPPER" + + input_shape = [10, 10, 7, 7] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + auto_pad=auto_pad) + + def test_max_pool_2d_ceil(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support ceil mode.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 3] + strides = [2, 2] + ceil_mode = 1 + + input_shape = [10, 3, 24, 24] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + ceil_mode=ceil_mode) + + def test_max_pool_2d_dilations(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 3] + strides = [2, 2] + dilations = [3, 3] + node_def = helper.make_node("MaxPool", ["X"], ["Y"], + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations) + + input_shape = [10, 3, 24, 24] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations) + + def test_max_pool_2d_dilations_ceil(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations nor ceil mode.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 3] + strides = [2, 2] + dilations = [3, 3] + ceil_mode = 1 + + input_shape = [10, 3, 23, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + ceil_mode=ceil_mode) + + def test_max_pool_2d_dilations_pads(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 3] + strides = [2, 2] + dilations = [3, 3] + pads = [1, 1, 2, 2] + + input_shape = [10, 3, 24, 24] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + pads=pads) + + def test_max_pool_2d_dilations_ceil_pads(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations nor ceil mode.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 3] + strides = [2, 2] + dilations = [3, 3] + pads = [1, 1, 2, 2] + ceil_mode = 1 + + input_shape = [10, 3, 23, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + pads=pads, + ceil_mode=ceil_mode) + + def test_max_pool_2d_dilations_same_lower(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 3] + strides = [2, 2] + dilations = [3, 3] + auto_pad = "SAME_LOWER" + + input_shape = [10, 3, 24, 24] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + auto_pad=auto_pad) + + def test_max_pool_2d_dilations_same_upper(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations.".format( + defs.onnx_opset_version())) + + kernel_shape = [2, 3] + strides = [4, 2] + dilations = [3, 5] + auto_pad = "SAME_UPPER" + + input_shape = [10, 3, 24, 24] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + auto_pad=auto_pad) + + def test_max_pool_2d_dilations_ceil_pads_int8(self): + if legacy_opset_pre_ver(12): + raise unittest.SkipTest( + "ONNX version {} does not support int8 input type.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 3] + strides = [2, 2] + dilations = [3, 3] + pads = [1, 1, 2, 2] + ceil_mode = 1 + + input_shape = [10, 3, 23, 23] + self._test_pooling(input_shape=input_shape, kernel_shape=kernel_shape, + strides=strides, dilations=dilations, pads=pads, + ceil_mode=ceil_mode, input_dtype=np.int8) + + def test_max_pool_3d(self): + kernel_shape = [3, 3, 3] + strides = [2, 2, 2] + + input_shape = [10, 3, 23, 23, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides) + + def test_max_pool_3d_dilations_ceil_pads(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations nor ceil mode.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 3, 3] + strides = [2, 2, 2] + dilations = [3, 3, 3] + pads = [1, 1, 2, 2, 1, 1] + ceil_mode = 1 + + input_shape = [10, 3, 23, 23, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + pads=pads, + ceil_mode=ceil_mode) + + def test_max_pool_3d_dilations_same_lower(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 1, 2] + strides = [2, 2, 1] + dilations = [3, 2, 5] + auto_pad = "SAME_LOWER" + + input_shape = [10, 3, 23, 23, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + auto_pad=auto_pad) + + def test_max_pool_1d_dilations_ceil_pads(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations nor ceil mode.".format( + defs.onnx_opset_version())) + + kernel_shape = [3] + strides = [2] + dilations = [3] + pads = [1, 2] + ceil_mode = 1 + + input_shape = [10, 3, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + pads=pads, + ceil_mode=ceil_mode) + + def test_max_pool_1d(self): + kernel_shape = [3] + strides = [2] + + input_shape = [10, 3, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides) + + def test_max_pool_with_argmax_2d_dilations_ceil_pads(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support dilations nor ceil mode.".format( + defs.onnx_opset_version())) + + kernel_shape = [3, 3] + strides = [2, 2] + dilations = [3, 3] + pads = [1, 1, 2, 2] + ceil_mode = True + node_def = helper.make_node("MaxPool", ["X"], ["Y", "Ind"], + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + pads=pads, + ceil_mode=ceil_mode) + + input_shape = [10, 1, 23, 23] + x = self._get_rnd_float32(shape=input_shape) - 2 + output = run_node(node_def, [x]) + + test_output, test_ind = py_pool(x, + kernel_shape=kernel_shape, + strides=strides, + dilations=dilations, + padding=pads, + ceil_mode=ceil_mode, + pooling_type="MAX") + + np.testing.assert_almost_equal(output["Y"], test_output) + np.testing.assert_almost_equal(output["Ind"], test_ind) + + def test_max_pool_with_argmax_3d(self): + kernel_shape = [3, 3, 3] + strides = [2, 2, 2] + node_def = helper.make_node("MaxPool", ["X"], ["Y", "Ind"], + kernel_shape=kernel_shape, + strides=strides) + + input_shape = [10, 1, 23, 23, 23] + x = self._get_rnd_float32(shape=input_shape) + self.assertRaises(RuntimeError, run_node, node_def, [x]) + + def test_max_pool_4d(self): + kernel_shape = [3, 3, 3, 3] + strides = [2, 2, 2, 2] + node_def = helper.make_node("MaxPool", ["X"], ["Y", "Ind"], + kernel_shape=kernel_shape, + strides=strides) + + input_shape = [1, 1, 4, 4, 4, 4] + x = self._get_rnd_float32(shape=input_shape) + self.assertRaises(RuntimeError, run_node, node_def, [x]) + + def test_max_unpool(self): + input_shape = [10, 10, 4, 4] + x = self._get_rnd_float32(shape=input_shape) + + X = helper.make_tensor_value_info('X', TensorProto.FLOAT, input_shape) + Y = helper.make_tensor_value_info('Y', TensorProto.FLOAT, input_shape) + + node_def = helper.make_node("MaxPool", ["X"], ["Pool", "Indices"], + kernel_shape=[2, 2], + strides=[2, 2]) + output_pool = run_node(node_def, [x]) + + node_def = helper.make_node("MaxUnpool", ["Pool", "Indices"], ["Y"], + kernel_shape=[2, 2], + strides=[2, 2]) + output_unpool = run_node(node_def, + [output_pool["Pool"], output_pool["Indices"]]) + + test_output = np.zeros(input_shape) + for i1 in range(0, input_shape[0]): + for i2 in range(0, input_shape[1]): + for i3 in range(0, input_shape[2], 2): + for i4 in range(0, input_shape[3], 2): + max_val = float('-inf') + for j1 in range(i3, i3 + 2): + for j2 in range(i4, i4 + 2): + if x[i1][i2][j1][j2] > max_val: + max_val = x[i1][i2][j1][j2] + max_ind = (j1, j2) + j1, j2 = max_ind + test_output[i1][i2][j1][j2] = max_val + np.testing.assert_almost_equal(output_unpool["Y"], test_output) + + def test_average_pool_1d(self): + kernel_shape = [3] + strides = [2] + + input_shape = [10, 3, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + pooling_type="AVG") + + def test_average_pool_2d(self): + kernel_shape = [1, 2] + strides = [1, 2] + + input_shape = [10, 10, 4, 4] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + pooling_type="AVG") + + def test_average_pool_2d_same_upper(self): + kernel_shape=[1, 2] + strides=[1, 2] + auto_pad="SAME_UPPER" + + input_shape = [10, 10, 7, 7] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + auto_pad=auto_pad, + pooling_type="AVG") + + def test_average_pool_3d(self): + kernel_shape = [3, 3, 3] + strides = [2, 2, 2] + + input_shape = [10, 3, 23, 23, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + pooling_type="AVG") + + def test_lp2_pool_2d(self): + kernel_shape = [1, 2] + strides = [1, 2] + p = 2 + + input_shape = [10, 10, 4, 4] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + pooling_type="LP", + p=p) + + def test_lp2_pool_2d_same_lower(self): + kernel_shape = [1, 2] + strides = [1, 2] + p = 2 + auto_pad = "SAME_LOWER" + + input_shape = [10, 10, 7, 7] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + auto_pad=auto_pad, + pooling_type="LP", + p=p) + + def test_lp2_pool_2d_same_upper(self): + kernel_shape = [1, 2] + strides = [1, 2] + p = 2 + auto_pad = "SAME_UPPER" + + input_shape = [10, 10, 7, 7] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + auto_pad=auto_pad, + pooling_type="LP", + p=p) + + def test_lp2_pool_2d_pads(self): + kernel_shape = [3, 3] + strides = [2, 2] + p = 2 + pads = [1, 1, 2, 2] + + input_shape = [10, 3, 24, 24] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + pads=pads, + pooling_type="LP", + p=p) + + def test_lp2_pool_3d(self): + kernel_shape = [3, 3, 3] + strides = [2, 2, 2] + p = 2 + + input_shape = [10, 3, 23, 23, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + pooling_type="LP", + p=p) + + def test_lp2_pool_1d(self): + kernel_shape = [3] + strides = [2] + p = 2 + + input_shape = [10, 3, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + pooling_type="LP", + p=p) + + def test_lp3_pool_2d_pads(self): + kernel_shape = [3, 3] + strides = [2, 2] + p = 3 + pads = [1, 1, 2, 2] + + input_shape = [10, 3, 24, 24] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + pads=pads, + pooling_type="LP", + p=p) + + def test_lp3_pool_3d(self): + kernel_shape = [3, 3, 3] + strides = [2, 2, 2] + p = 3 + + input_shape = [10, 3, 23, 23, 23] + self._test_pooling(input_shape=input_shape, + kernel_shape=kernel_shape, + strides=strides, + pooling_type="LP", + p=p) + + def test_mean_variance_normalization(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest( + "ONNX version {} doesn't have test for MeanVarianceNormalization". + format(defs.onnx_opset_version())) + + input_data = self._get_rnd_float32(shape=[2, 2, 2, 2]) + # Calculate expected output data using formula: + # (Input - Mean)/SD + mean = np.mean(input_data, keepdims=1, axis=(0, 2, 3)) + std = np.std(input_data, keepdims=1, axis=(0, 2, 3)) + expected_output = (input_data - mean) / std + # Testing without "axes" argument should default to axes=[0,2,3] + node_def = helper.make_node("MeanVarianceNormalization", ["X"], ["Y"]) + output = run_node(node_def, [input_data]) + np.testing.assert_almost_equal(output["Y"], expected_output, decimal=5) + + def test_min(self): + node_def = helper.make_node("Min", ["X1", "X2", "X3", "X4"], ["Z"]) + x1 = self._get_rnd_float32(shape=[10, 10]) + x2 = self._get_rnd_float32(shape=[10, 10]) + x3 = self._get_rnd_float32(shape=[10, 10]) + x4 = self._get_rnd_float32(shape=[10, 10]) + output = run_node(node_def, [x1, x2, x3, x4]) + test_output = np.minimum(np.minimum(np.minimum(x1, x2), x3), x4) + np.testing.assert_almost_equal(output["Z"], test_output) + + def test_mul(self): + node_def = helper.make_node("Mul", ["X", "Y"], ["Z"]) + x = self._get_rnd_float32(shape=[5, 10, 5, 5]) + y = self._get_rnd_float32(shape=[10, 1, 1]) + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], + np.multiply(x, y.reshape([1, 10, 1, 1]))) + + def test_mod(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest("ONNX version {} doesn't support Mod.".format( + defs.onnx_opset_version())) + x = self._get_rnd_float32(shape=[5, 5]) + y = self._get_rnd_float32(shape=[5, 5]) + node_def = helper.make_node("Mod", ["X", "Y"], ["Z"], fmod=0) + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], np.mod(x, y)) + node_def = helper.make_node("Mod", ["X", "Y"], ["Z"], fmod=1) + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], np.fmod(x, y)) + + def test_neg(self): + node_def = helper.make_node("Neg", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[1000]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.negative(x)) + + def test_non_zero(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support NonZero.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("NonZero", ["x"], ["y"]) + x = self._get_rnd_float32(shape=[3, 4, 5]) + y = np.array(np.nonzero(x)) + output = run_node(node_def, [x]) + np.testing.assert_equal(output["y"], y) + + def test_onehot(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support OneHot.".format( + defs.onnx_opset_version())) + indices = np.array([[0, 2], [1, 2], [0, 1]]) + depth = np.int32(5) + on_value = 6.0 + off_value = 2.0 + values = np.array([off_value, on_value]) + node_def = helper.make_node('OneHot', + inputs=['indices', 'depth', 'values'], + outputs=['y'], + axis=-1) + y = (np.arange(depth) == indices[..., None]).astype(int) + y = y * (on_value - off_value) + off_value + output = run_node(node_def, inputs=[indices, depth, values]) + np.testing.assert_equal(output['y'], y) + + def test_range(self): + if legacy_opset_pre_ver(11): + raise unittest.SkipTest("ONNX version {} doesn't support Range.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Range", ['start', 'limit', 'delta'], ['y']) + # test positive_delta + start = self._get_rnd_int(low=0, high=3) + limit = self._get_rnd_int(low=10, high=30) + delta = np.int32(3) + output = run_node(node_def, [start, limit, delta]) + np.testing.assert_equal(output['y'], range(start, limit, delta)) + # test negative_delta + start = self._get_rnd_int(low=20, high=30) + limit = self._get_rnd_int(low=1, high=5) + delta = np.int32(-2) + output = run_node(node_def, [start, limit, delta]) + np.testing.assert_equal(output['y'], range(start, limit, delta)) + + def test_resize(self): + if legacy_opset_pre_ver(11): + raise unittest.SkipTest( + "ONNX version {} doesn't support Resize with attributes: " + + "coordinate_transformation_mode, cubic_coeff_a, exclude_outside, " + + "extrapolation_value, nearest_mode and inputs: roi and sizes".format( + defs.onnx_opset_version())) + data = np.reshape(np.arange(1, 101, dtype=np.float32), [1, 1, 10, 10]) + roi = np.array([], dtype=np.float32) + + # resize_nearest_round_prefer_ceil_align_corners_scales + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + coordinate_transformation_mode='align_corners', + mode='nearest', + nearest_mode='round_prefer_ceil') + scales = np.array([1, 1, 0.9, 0.9], dtype=np.float32) + expected = np.array( + [[[[1, 2, 3, 4, 6, 7, 8, 9, 10], [11, 12, 13, 14, 16, 17, 18, 19, 20], + [21, 22, 23, 24, 26, 27, 28, 29, 30], + [31, 32, 33, 34, 36, 37, 38, 39, 40], + [51, 52, 53, 54, 56, 57, 58, 59, 60], + [61, 62, 63, 64, 66, 67, 68, 69, 70], + [71, 72, 73, 74, 76, 77, 78, 79, 80], + [81, 82, 83, 84, 86, 87, 88, 89, 90], + [91, 92, 93, 94, 96, 97, 98, 99, 100]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_nearest_round_prefer_ceil_align_corners_sizes + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + coordinate_transformation_mode='align_corners', + mode='nearest', + nearest_mode='round_prefer_ceil') + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array( + [[[[1, 3, 4, 6, 7, 9, 10], [21, 23, 24, 26, 27, 29, 30], + [31, 33, 34, 36, 37, 39, 40], [51, 53, 54, 56, 57, 59, 60], + [61, 63, 64, 66, 67, 69, 70], [81, 83, 84, 86, 87, 89, 90], + [91, 93, 94, 96, 97, 99, 100]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_nearest_floor_asymmetric_scales + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + coordinate_transformation_mode='asymmetric', + mode='nearest', + nearest_mode='floor') + scales = np.array([1.0, 1.0, 0.8, 0.8], dtype=np.float32) + expected = np.array( + [[[[1, 2, 3, 4, 6, 7, 8, 9], [11, 12, 13, 14, 16, 17, 18, 19], + [21, 22, 23, 24, 26, 27, 28, 29], [31, 32, 33, 34, 36, 37, 38, 39], + [51, 52, 53, 54, 56, 57, 58, 59], [61, 62, 63, 64, 66, 67, 68, 69], + [71, 72, 73, 74, 76, 77, 78, 79], [81, 82, 83, 84, 86, 87, 88, 89]]] + ], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_nearest_floor_asymmetric_sizes + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + coordinate_transformation_mode='asymmetric', + mode='nearest', + nearest_mode='floor') + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array( + [[[[1, 2, 3, 5, 6, 8, 9], [11, 12, 13, 15, 16, 18, 19], + [21, 22, 23, 25, 26, 28, 29], [41, 42, 43, 45, 46, 48, 49], + [51, 52, 53, 55, 56, 58, 59], [71, 72, 73, 75, 76, 78, 79], + [81, 82, 83, 85, 86, 88, 89]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_nearest_floor_half_pixel_scales + node_def = helper.make_node( + "Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + coordinate_transformation_mode='tf_half_pixel_for_nn', + mode='nearest', + nearest_mode='floor') + scales = np.array([1, 1, 0.8, 0.8], dtype=np.float32) + expected = np.array( + [[[[1, 2, 4, 5, 6, 7, 9, 10], [11, 12, 14, 15, 16, 17, 19, 20], + [31, 32, 34, 35, 36, 37, 39, 40], [41, 42, 44, 45, 46, 47, 49, 50], + [51, 52, 54, 55, 56, 57, 59, 60], [61, 62, 64, 65, 66, 67, 69, 70], + [81, 82, 84, 85, 86, 87, 89, 90], [91, 92, 94, 95, 96, 97, 99, 100]]] + ], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_nearest_floor_half_pixel_sizes + node_def = helper.make_node( + "Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + coordinate_transformation_mode='tf_half_pixel_for_nn', + mode='nearest', + nearest_mode='floor') + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array( + [[[[1, 3, 4, 6, 7, 8, 10], [21, 23, 24, 26, 27, 28, 30], + [31, 33, 34, 36, 37, 38, 40], [51, 53, 54, 56, 57, 58, 60], + [61, 63, 64, 66, 67, 68, 70], [71, 73, 74, 76, 77, 78, 80], + [91, 93, 94, 96, 97, 98, 100]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_linear_align_corners_scales + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + coordinate_transformation_mode="align_corners", + mode='linear') + scales = np.array([1, 1, 0.8, 0.8], dtype=np.float32) + expected = np.array( + [[[[ + 1., 2.2857141, 3.5714285, 4.857143, 6.142857, 7.428571, 8.714286, + 10. + ], + [ + 13.857142, 15.142857, 16.428572, 17.714287, 19., 20.285715, + 21.571428, 22.857143 + ], + [ + 26.714287, 28., 29.285713, 30.571426, 31.857141, 33.142857, + 34.428574, 35.714283 + ], + [ + 39.57143, 40.857143, 42.14286, 43.428574, 44.714287, 46., + 47.285717, 48.57143 + ], + [ + 52.428574, 53.714283, 55., 56.285713, 57.571426, 58.857143, + 60.142857, 61.428566 + ], + [ + 65.28571, 66.57143, 67.85714, 69.14285, 70.428566, 71.71428, 73., + 74.28571 + ], + [ + 78.14286, 79.42857, 80.71428, 82., 83.28572, 84.57143, 85.85715, + 87.14286 + ], + [ + 91., 92.28571, 93.57143, 94.85715, 96.14285, 97.42857, 98.71429, + 100. + ]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_allclose(output['Y'], expected, rtol=1e-6, atol=1e-6) + + # resize_linear_align_corners_sizes + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + coordinate_transformation_mode="align_corners", + mode='linear') + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array( + [[[[1., 2.5, 4., 5.5, 7., 8.5, 10.], + [16., 17.5, 19., 20.5, 22., 23.5, 25.], + [31., 32.5, 34., 35.5, 37., 38.5, 40.], + [46., 47.5, 49., 50.5, 52., 53.5, 55.], + [61., 62.5, 64., 65.5, 67., 68.5, 70.], + [76., 77.5, 79., 80.5, 82., 83.5, 85.], + [91., 92.5, 94., 95.5, 97., 98.5, 100.]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_linear_asymmetric_scales + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + coordinate_transformation_mode="asymmetric", + mode='linear') + scales = np.array([1, 1, 0.8, 0.8], dtype=np.float32) + expected = np.array( + [[[[1., 2.25, 3.5, 4.75, 6., 7.25, 8.5, 9.75], + [13.5, 14.75, 16., 17.25, 18.5, 19.75, 21., 22.25], + [26., 27.25, 28.5, 29.75, 31., 32.25, 33.5, 34.75], + [38.5, 39.75, 41., 42.25, 43.5, 44.75, 46., 47.25], + [51., 52.25, 53.5, 54.75, 56., 57.25, 58.5, 59.75], + [63.5, 64.75, 66., 67.25, 68.5, 69.75, 71., 72.25], + [76., 77.25, 78.5, 79.75, 81., 82.25, 83.5, 84.75], + [88.5, 89.75, 91., 92.25, 93.5, 94.75, 96., 97.25]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_linear_asymmetric_sizes + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + coordinate_transformation_mode="asymmetric", + mode='linear') + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array([[ + [[1., 2.4285715, 3.857143, 5.285714, 6.714286, 8.142857, 9.571428], + [15.285715, 16.714287, 18.142857, 19.571428, 21., 22.42857, 23.857141], + [29.571428, 31., 32.428574, 33.857143, 35.285717, 36.714287, 38.14286], + [43.857143, 45.28571, 46.714283, 48.14286, 49.571434, 51., 52.42857], + [ + 58.14286, 59.57143, 61.000004, 62.428574, 63.857143, 65.28572, + 66.71429 + ], [72.42857, 73.85713, 75.28572, 76.71429, 78.14286, 79.57143, 81.], + [86.71429, 88.14285, 89.57143, 91., 92.42857, 93.85714, 95.28571]] + ]], + dtype=np.float32 + ) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_allclose(output['Y'], expected, rtol=1e-6, atol=1e-6) + + # resize_linear_half_pixel_scales + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + mode='linear') + scales = np.array([1, 1, 0.8, 0.8], dtype=np.float32) + expected = np.array( + [[[[2.375, 3.625, 4.875, 6.125, 7.375, 8.625, 9.875, 11.125], + [14.875, 16.125, 17.375, 18.625, 19.875, 21.125, 22.375, 23.625], + [27.375, 28.625, 29.875, 31.125, 32.375, 33.625, 34.875, 36.125], + [39.875, 41.125, 42.375, 43.625, 44.875, 46.125, 47.375, 48.625], + [52.375, 53.625, 54.875, 56.125, 57.375, 58.625, 59.875, 61.125], + [64.875, 66.125, 67.375, 68.625, 69.875, 71.125, 72.375, 73.625], + [77.375, 78.625, 79.875, 81.125, 82.375, 83.625, 84.875, 86.125], + [89.875, 91.125, 92.375, 93.625, 94.875, 96.125, 97.375, 98.625]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_linear_half_pixel_sizes + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + mode='linear') + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array([[[[ + 3.357143, 4.785714, 6.214286, 7.642857, 9.071428, 10.5, 11.928572 + ], [ + 17.642857, 19.071428, 20.5, 21.92857, 23.357141, 24.785713, 26.214285 + ], [ + 31.928572, 33.357143, 34.785713, 36.214287, 37.642857, 39.071426, 40.5 + ], [ + 46.214287, 47.642857, 49.071426, 50.5, 51.928574, 53.357143, 54.785713 + ], [60.5, 61.928577, 63.357147, 64.78572, 66.21429, 67.64286, 69.07143 + ], [ + 74.78572, 76.21429, 77.64285, 79.07143, 80.50001, 81.92857, 83.35715 + ], [89.07143, 90.5, 91.928566, 93.35715, 94.78571, 96.21428, 97.64285]]] + ], + dtype=np.float32 + ) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_allclose(output['Y'], expected, rtol=1e-6, atol=1e-6) + + # resize_cubic_align_corners_scales + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + coordinate_transformation_mode="align_corners", + mode='cubic', + cubic_coeff_a=-0.5, + exclude_outside=1) + scales = np.array([1, 1, 0.8, 0.8], dtype=np.float32) + expected = np.array( + [[[[ + 1., 2.285714, 3.5714293, 4.857143, 6.142857, 7.4285717, 8.714287, + 10. + ], + [ + 13.857139, 15.142854, 16.42857, 17.714281, 18.999994, 20.28571, + 21.571426, 22.857138 + ], + [ + 26.71429, 28.000004, 29.285723, 30.571436, 31.85715, 33.142864, + 34.428577, 35.71429 + ], + [ + 39.57143, 40.857143, 42.142864, 43.428574, 44.714287, 46.000004, + 47.28572, 48.57143 + ], + [ + 52.42857, 53.714287, 55., 56.285717, 57.571423, 58.857143, + 60.14286, 61.42857 + ], + [ + 65.28571, 66.57144, 67.85715, 69.14285, 70.428566, 71.71429, + 73.00001, 74.28571 + ], + [ + 78.14287, 79.42857, 80.7143, 82.00001, 83.28573, 84.571434, + 85.857155, 87.14287 + ], + [ + 91., 92.28572, 93.57144, 94.85715, 96.14285, 97.42858, 98.714294, + 100. + ]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_allclose(output['Y'], expected, rtol=1e-1, atol=1e-6) + + # resize_cubic_align_corners_sizes + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + coordinate_transformation_mode="align_corners", + mode='cubic', + cubic_coeff_a=-0.5, + exclude_outside=1) + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array( + [[[[1., 2.5, 4., 5.5, 7., 8.5, 10.], + [16., 17.5, 19., 20.5, 22., 23.5, 25.], + [31., 32.5, 34., 35.5, 37., 38.5, 40.], + [46., 47.5, 49., 50.5, 52., 53.5, 55.], + [61., 62.5, 64., 65.5, 67., 68.5, 70.], + [76., 77.5, 79., 80.5, 82., 83.5, 85.], + [91., 92.5, 94., 95.5, 97., 98.5, 100.]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_almost_equal(output["Y"], expected) + + # resize_cubic_asymmetric_scales + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + coordinate_transformation_mode="asymmetric", + mode='cubic', + cubic_coeff_a=-0.5, + exclude_outside=1) + scales = np.array([1, 1, 0.8, 0.8], dtype=np.float32) + expected = np.array( + [[[[1., 2.25, 3.5, 4.75, 6., 7.25, 8.5, 9.832117], + [13.5, 14.75, 16., 17.25, 18.5, 19.75, 21., 22.332117], + [26., 27.25, 28.5, 29.75, 31., 32.25, 33.5, 34.83212], + [38.5, 39.75, 41., 42.25, 43.5, 44.75, 46., 47.332115], + [51., 52.25, 53.5, 54.75, 56., 57.25, 58.5, 59.83212], + [63.5, 64.75, 66., 67.25, 68.5, 69.75, 71., 72.332115], + [76., 77.25, 78.5, 79.75, 81., 82.25, 83.5, 84.832115], + [ + 89.32117, 90.57117, 91.82117, 93.07117, 94.32117, 95.57117, + 96.82117, 98.15329 + ]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_allclose(output['Y'], expected, rtol=1e-1, atol=1e-6) + + # resize_cubic_asymmetric_sizes + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + coordinate_transformation_mode="asymmetric", + mode='cubic', + cubic_coeff_a=-0.5, + exclude_outside=1) + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array( + [[[[1., 2.4285715, 3.8571432, 5.285714, 6.7142863, 8.142857, 9.66485], + [ + 15.285712, 16.714287, 18.142855, 19.571426, 21., 22.428568, + 23.950563 + ], + [ + 29.57143, 31.000004, 32.428574, 33.857147, 35.285713, 36.714283, + 38.236282 + ], + [ + 43.857143, 45.285717, 46.714287, 48.142868, 49.571434, 50.999992, + 52.52199 + ], + [ + 58.142864, 59.57144, 61.000004, 62.428585, 63.857155, 65.28572, + 66.80771 + ], + [ + 72.428566, 73.85715, 75.28572, 76.714294, 78.14285, 79.57143, + 81.09343 + ], + [ + 87.6485, 89.07708, 90.505646, 91.93422, 93.36279, 94.79135, + 96.313354 + ]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_allclose(output['Y'], expected, rtol=1e-1, atol=1e-6) + + # resize_cubic_half_pixel_scales + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + mode='cubic', + cubic_coeff_a=-0.5, + exclude_outside=1) + scales = np.array([1, 1, 0.8, 0.8], dtype=np.float32) + expected = np.array([[ + [[ + 1.8098788, 3.1112535, 4.3612537, 5.6112533, 6.8612533, 8.111254, + 9.361254, 10.662629 + ], + [14.823625, 16.125, 17.375, 18.625, 19.875, 21.125, 22.375, 23.676373], + [27.323626, 28.625, 29.875, 31.125, 32.375, 33.625, 34.875, 36.176376], + [39.823627, 41.125, 42.375, 43.625, 44.875, 46.125, 47.375, 48.676376], + [52.323624, 53.625, 54.875, 56.125, 57.375, 58.625, 59.875, 61.176373], + [64.82362, 66.125, 67.375, 68.625, 69.875, 71.125, 72.375, 73.67638], + [77.32362, 78.625, 79.875, 81.125, 82.375, 83.625, 84.875, 86.17638], + [ + 90.33737, 91.63874, 92.88875, 94.13875, 95.38875, 96.63875, + 97.88875, 99.190125 + ]] + ]], + dtype=np.float32 + ) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_allclose(output['Y'], expected, rtol=1e-6, atol=1e-6) + + # resize_cubic_half_pixel_sizes + node_def = helper.make_node("Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + mode='cubic', + cubic_coeff_a=-0.5, + exclude_outside=1) + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array([[[ + [2.52846, 4.0323663, 5.460938, 6.889509, 8.318081, 9.746653, 11.250559], + [ + 17.567522, 19.071426, 20.499996, 21.928568, 23.357141, 24.785715, + 26.28962 + ], + [ + 31.853237, 33.357143, 34.785713, 36.21429, 37.64286, 39.07143, + 40.575344 + ], + [46.13895, 47.642857, 49.071434, 50.5, 51.928566, 53.357147, 54.861053], + [ + 60.42467, 61.92858, 63.357147, 64.78572, 66.214294, 67.64287, + 69.14677 + ], + [ + 74.710396, 76.214294, 77.64286, 79.07144, 80.50001, 81.92858, + 83.432495 + ], + [89.749466, 91.253365, 92.68193, 94.1105, 95.53907, 96.96766, 98.47156] + ]]], + dtype=np.float32 + ) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_allclose(output['Y'], expected, rtol=1e-2, atol=1e-6) + + # crop_and_resize_nearest with scales + node_def = helper.make_node( + "Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + coordinate_transformation_mode='tf_crop_and_resize', + mode='nearest', + nearest_mode='round_prefer_ceil', + extrapolation_value=-20.0) + roi = np.array([0, 0, 0.4, 0.6, 1, 1, 1.2, 1.7], dtype=np.float32) + scales = np.array([1.0, 1.0, 0.8, 0.8], dtype=np.float32) + expected = np.array( + [[[[46., 48., 49., -20., -20., -20., -20., -20.], + [56., 58., 59., -20., -20., -20., -20., -20.], + [66., 68., 69., -20., -20., -20., -20., -20.], + [76., 78., 79., -20., -20., -20., -20., -20.], + [86., 88., 89., -20., -20., -20., -20., -20.], + [96., 98., 99., -20., -20., -20., -20., -20.], + [-20., -20., -20., -20., -20., -20., -20., -20.], + [-20., -20., -20., -20., -20., -20., -20., -20.]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_almost_equal(output["Y"], expected) + + # crop_and_resize_nearest with sizes + node_def = helper.make_node( + "Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + coordinate_transformation_mode='tf_crop_and_resize', + mode='nearest', + nearest_mode='round_prefer_ceil', + ) + roi = np.array([0, 0, 0.4, 0.6, 1, 1, 1.2, 1.7], dtype=np.float32) + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array( + [[[[46., 48., 50., 0., 0., 0., 0.], [56., 58., 60., 0., 0., 0., 0.], + [66., 68., 70., 0., 0., 0., 0.], [76., 78., 80., 0., 0., 0., 0.], + [86., 88., 90., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0.], + [0., 0., 0., 0., 0., 0., 0.]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_almost_equal(output["Y"], expected) + + # crop_and_resize_linear with scales + node_def = helper.make_node( + "Resize", + inputs=['X', 'roi', 'scales'], + outputs=['Y'], + mode='linear', + coordinate_transformation_mode='tf_crop_and_resize', + extrapolation_value=20.0) + roi = np.array([0, 0, 0.4, 0.6, 1, 1, 1.2, 1.7], dtype=np.float32) + scales = np.array([1.0, 1.0, 0.8, 0.8], dtype=np.float32) + expected = np.array( + [[[[42.4, 43.814285, 45.228573, 20., 20., 20., 20., 20.], + [52.685715, 54.100002, 55.514286, 20., 20., 20., 20., 20.], + [62.971436, 64.38572, 65.80001, 20., 20., 20., 20., 20.], + [73.25715, 74.67143, 76.08572, 20., 20., 20., 20., 20.], + [83.54286, 84.957146, 86.37143, 20., 20., 20., 20., 20.], + [93.82858, 95.24287, 96.65715, 20., 20., 20., 20., 20.], + [20., 20., 20., 20., 20., 20., 20., 20.], + [20., 20., 20., 20., 20., 20., 20., 20.]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales]) + np.testing.assert_allclose(output["Y"], expected, rtol=1e-6, atol=1e-6) + + # crop_and_resize_linear with sizes + node_def = helper.make_node( + "Resize", + inputs=['X', 'roi', 'scales', 'sizes'], + outputs=['Y'], + mode='linear', + coordinate_transformation_mode='tf_crop_and_resize', + extrapolation_value=50.0) + roi = np.array([0, 0, 0.4, 0.6, 1, 1, 1.2, 1.7], dtype=np.float32) + scales = np.array([], dtype=np.float32) + sizes = np.array([1, 1, 7, 7], dtype=np.int64) + expected = np.array( + [[[[42.4, 44.05, 45.7, 50., 50., 50., 50.], + [54.4, 56.050003, 57.700005, 50., 50., 50., 50.], + [66.40001, 68.05, 69.700005, 50., 50., 50., 50.], + [78.40001, 80.05001, 81.700005, 50., 50., 50., 50.], + [90.40001, 92.05, 93.70001, 50., 50., 50., 50.], + [50., 50., 50., 50., 50., 50., 50.], + [50., 50., 50., 50., 50., 50., 50.]]]], + dtype=np.float32) # expected value is calculated by onnx-runtime + output = run_node(node_def, [data, roi, scales, sizes]) + np.testing.assert_allclose(output["Y"], expected, rtol=1e-6, atol=1e-6) + + def test_round(self): + if legacy_opset_pre_ver(11): + raise unittest.SkipTest("ONNX version {} doesn't support Round.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Round", ["X"], ["Y"]) + x = self._get_rnd_float32(-20.0, 20.0, shape=[1000]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.round(x)) + + def test_qLinearMatMul(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support QLinearMatMul.".format( + defs.onnx_opset_version())) + + def qLinearMatMul(a, a_scale, a_zero_point, b, b_scale, b_zero_point, + y_scale, y_zero_point): + y_dtype = y_zero_point.dtype + # reshape 1-D a_scale, a_zero_point, y_scale and + # y_zero_point so it can broadcast in arithmetic + # operations later + a_scale_shape = a_scale.shape + if a_scale_shape and a_scale_shape[0] > 1: + a_scale = np.reshape(a_scale, [a_scale_shape[0], 1]) + a_zero_point = np.reshape(a_zero_point, [a_scale_shape[0], 1]) + y_scale_shape = y_scale.shape + if y_scale_shape and y_scale_shape[0] > 1: + y_scale = np.reshape(y_scale, [y_scale_shape[0], 1]) + y_zero_point = np.reshape(y_zero_point, [y_scale_shape[0], 1]) + # cast everything to float32 + a = a.astype(np.float32) + a_zero_point = a_zero_point.astype(np.float32) + b = b.astype(np.float32) + b_zero_point = b_zero_point.astype(np.float32) + y_zero_point = y_zero_point.astype(np.float32) + # dequantize a and b + dequantized_a = np.subtract(a, a_zero_point) + dequantized_a = np.multiply(dequantized_a, a_scale) + dequantized_b = np.subtract(b, b_zero_point) + dequantized_b = np.multiply(dequantized_b, b_scale) + # matmul a and b + x = np.matmul(dequantized_a, dequantized_b) + # quantize x + y = np.divide(x, y_scale) + y = np.round(y) + y = np.add(y, y_zero_point) + y = np.clip(y, np.iinfo(y_dtype).min, np.iinfo(y_dtype).max) + y = y.astype(y_dtype) + return y + + node_def = helper.make_node('QLinearMatMul', [ + 'a', 'a_scale', 'a_zero_point', 'b', 'b_scale', 'b_zero_point', + 'y_scale', 'y_zero_point' + ], ['y']) + for dtype in [np.int8, np.uint8]: + low = np.iinfo(dtype).min + high = np.iinfo(dtype).max + a = self._get_rnd_int(low, high, [3, 4, 5, 6], dtype) + a_scale = self._get_rnd_float32(-0.005, 0.005, [5]) + a_zero_point = self._get_rnd_int(low, high, [5], dtype) + b = self._get_rnd_int(low, high, [3, 4, 6, 2], dtype) + b_scale = self._get_rnd_float32(-0.005, 0.005, [2]) + b_zero_point = self._get_rnd_int(low, high, [2], dtype) + y_scale = self._get_rnd_float32(-0.05, 0.05, [5]) + y_zero_point = self._get_rnd_int(low, high, [5], dtype) + y = qLinearMatMul(a, a_scale, a_zero_point, b, b_scale, b_zero_point, + y_scale, y_zero_point) + output = run_node(node_def, [ + a, a_scale, a_zero_point, b, b_scale, b_zero_point, y_scale, + y_zero_point + ]) + np.testing.assert_almost_equal(output['y'], y) + + def test_relu(self): + node_def = helper.make_node("Relu", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[1000]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.maximum(x, 0)) + + def test_pad(self): + x = self._get_rnd_float32(shape=[100, 100]) + if legacy_opset_pre_ver(11): # for opset = 1 or 2 + # mode = constant + node_def = helper.make_node("Pad", ["X"], ["Y"], + mode="constant", + pads=[1, 1, 1, 1], + value=2.0) + output = run_node(node_def, [x]) + y = np.pad(x, ((1, 1), (1, 1)), 'constant', constant_values=(2, 2)) + np.testing.assert_almost_equal(output["Y"], y) + # mode = reflect and edge + for mode in ['edge', 'reflect']: + node_def = helper.make_node("Pad", ["X"], ["Y"], + mode=mode, + pads=[1, 1, 1, 1]) + output = run_node(node_def, [x]) + y = np.pad(x, ((1, 1), (1, 1)), mode) + np.testing.assert_almost_equal(output["Y"], y) + else: # for opset = 11 + # mode = constant + node_def = helper.make_node("Pad", ["X", "pads", "constant_values"], + ["Y"], + mode="constant") + pads = np.array([1, 1, 1, 1], dtype=np.int64) + constant_values = 2.0 + output = run_node(node_def, [x, pads, constant_values]) + y = np.pad(x, ((1, 1), (1, 1)), 'constant', constant_values=(2, 2)) + np.testing.assert_almost_equal(output["Y"], y) + # mode = reflect and edge + for mode in ['edge', 'reflect']: + node_def = helper.make_node("Pad", ["X", "pads"], ["Y"], mode=mode) + output = run_node(node_def, [x, pads]) + y = np.pad(x, ((1, 1), (1, 1)), mode) + np.testing.assert_almost_equal(output["Y"], y) + + def test_qlinearconv(self): + if legacy_opset_pre_ver(10): + raise unittest.SkipTest( + "ONNX version {} doesn't support QLinearConv.".format( + defs.onnx_opset_version())) + + # Test w_scale and w_zero_point as scalar + node_def = helper.make_node("QLinearConv", + inputs=[ + "x", "x_scale", "x_zero_point", "w", + "w_scale", "w_zero_point", "y_scale", + "y_zero_point" + ], + outputs=["Y"]) + x = np.array([ + [255, 174, 162, 25, 203, 168, 58], + [15, 59, 237, 95, 129, 0, 64], + [56, 242, 153, 221, 168, 12, 166], + [232, 178, 186, 195, 237, 162, 237], + [188, 39, 124, 77, 80, 102, 43], + [127, 230, 21, 83, 41, 40, 134], + [255, 154, 92, 141, 42, 148, 247], + ], + dtype=np.uint8).reshape((1, 1, 7, 7)) + x_scale = np.float32(0.00369204697) + x_zero_point = np.uint8(132) + + w = np.array([0], dtype=np.uint8).reshape((1, 1, 1, 1)) + w_scale = np.float32(0.00172794575) + w_zero_point = np.uint8(255) + + y = np.array([ + [0, 81, 93, 230, 52, 87, 197], + [240, 196, 18, 160, 126, 255, 191], + [199, 13, 102, 34, 87, 243, 89], + [23, 77, 69, 60, 18, 93, 18], + [67, 216, 131, 178, 175, 153, 212], + [128, 25, 234, 172, 214, 215, 121], + [0, 101, 163, 114, 213, 107, 8], + ], + dtype=np.uint8).reshape((1, 1, 7, 7)) + y_scale = np.float32(0.00162681262) + y_zero_point = np.uint8(123) + + output = run_node(node_def, [ + x, x_scale, x_zero_point, w, w_scale, w_zero_point, y_scale, + y_zero_point + ]) + np.testing.assert_almost_equal(output["Y"], y) + + def test_quantize_linear(self): + node_def = helper.make_node("QuantizeLinear", + ["x", "y_scale", "y_zero_point"], ["y"]) + for x in [ + self._get_rnd_float32(-512., 512., [2, 6]), + self._get_rnd_int(-512, 512, [2, 6]) + ]: + y_scale = self._get_rnd_float32(-10., 10.) + for y_zero_point in [ + self._get_rnd_int(-128, 127, dtype=np.int8), + self._get_rnd_int(0, 255, dtype=np.uint8) + ]: + y = np.divide(x, y_scale) + y = np.round(y) + y = np.add(y, y_zero_point) + if y_zero_point.dtype.type is np.int8: + y = np.clip(y, -128, 127).astype(np.int8) + else: + y = np.clip(y, 0, 255).astype(np.uint8) + output = run_node(node_def, [x, y_scale, y_zero_point]) + np.testing.assert_almost_equal(output["y"], y) + + def test_reciprocal(self): + node_def = helper.make_node("Reciprocal", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[1000]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], 1.0 / x) + + def test_reduce_l1(self): + node_def = helper.make_node("ReduceL1", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_float32(shape=[5, 10, 10, 3]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], + np.linalg.norm(x, 1, (1, 2), True)) + + def test_reduce_log_sum_exp(self): + node_def = helper.make_node("ReduceLogSumExp", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_float32(shape=[5, 10, 10, 3]) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.log( + np.sum(np.exp(x), axis=(1, 2), + keepdims=True)), + rtol=1e-3) + + def test_reduce_max(self): + node_def = helper.make_node("ReduceMax", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_float32(shape=[5, 10, 10, 3]) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.max(x, (1, 2), keepdims=True), + rtol=1e-3) + + # test tensor(uint8), tensor(int8) + node_def = helper.make_node("ReduceMax", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_int(0, 100, [5, 10, 10, 3], np.uint8) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.max(x, (1, 2), keepdims=True), + rtol=1e-3) + + node_def = helper.make_node("ReduceMax", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_int(-100, 100, [5, 10, 10, 3], np.int8) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.max(x, (1, 2), keepdims=True), + rtol=1e-3) + + def test_reduce_mean(self): + node_def = helper.make_node("ReduceMean", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_float32(shape=[5, 10, 10, 3]) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.mean(x, (1, 2), keepdims=True), + rtol=1e-3) + + def test_reduce_min(self): + node_def = helper.make_node("ReduceMin", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_float32(shape=[5, 10, 10, 3]) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.min(x, (1, 2), keepdims=True), + rtol=1e-3) + + # test tensor(uint8), tensor(int8) + node_def = helper.make_node("ReduceMin", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_int(0, 100, [5, 10, 10, 3], np.uint8) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.min(x, (1, 2), keepdims=True), + rtol=1e-3) + + node_def = helper.make_node("ReduceMin", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_int(-100, 100, [5, 10, 10, 3], np.int8) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.min(x, (1, 2), keepdims=True), + rtol=1e-3) + + def test_reduce_prod(self): + node_def = helper.make_node("ReduceProd", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_float32(shape=[1, 5, 5, 3]) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.prod(x, (1, 2), keepdims=True), + rtol=1e-3) + + def test_reduce_sum(self): + node_def = helper.make_node("ReduceSum", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_float32(shape=[5, 10, 10, 3]) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.sum(x, (1, 2), keepdims=True), + rtol=1e-3) + + def test_reduce_sum_square(self): + node_def = helper.make_node("ReduceSumSquare", ["X"], ["Y"], axes=[1, 2]) + x = self._get_rnd_float32(shape=[5, 10, 10, 3]) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], + np.sum(np.square(x), (1, 2), keepdims=True), + rtol=1e-3) + + def test_pow(self): + node_def = helper.make_node("Pow", ["X", "Y"], ["Z"]) + x = self._get_rnd_float32(shape=1000) / 2.0 + 0.5 + y = self._get_rnd_float32(shape=1000) / 2.0 + 0.5 + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], np.power(x, y)) + + def test_reshape(self): + x = self._get_rnd_float32(shape=100) + shape = [10, 10] + if defs.onnx_opset_version() < 5: + node_def = helper.make_node("Reshape", ["X"], ["Z"], shape=shape) + output = run_node(node_def, [x]) + else: + node_def = helper.make_node("Reshape", ["X", "Y"], ["Z"]) + output = run_node(node_def, [x, shape]) + + np.testing.assert_almost_equal(output["Z"], x.reshape([10, 10])) + + def test_reshape_with_copy(self): + x = self._get_rnd_float32(shape=[10, 20 * 30]) + shape = [0, 20, 30] + if defs.onnx_opset_version() < 5: + node_def = helper.make_node("Reshape", ["X"], ["Z"], shape=shape) + output = run_node(node_def, [x]) + else: + node_def = helper.make_node("Reshape", ["X", "Y"], ["Z"]) + output = run_node(node_def, [x, shape]) + + np.testing.assert_almost_equal(output["Z"], x.reshape([10, 20, 30])) + + def test_selu(self): + node_def = helper.make_node("Selu", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[1000]) + output = run_node(node_def, [x]) + alpha = 1.6732 + gamma = 1.0507 + x[x <= 0] = gamma * (alpha * np.exp(x[x <= 0]) - alpha) + x[x > 0] = gamma * x[x > 0] + np.testing.assert_allclose(output["Y"], x, rtol=1e-3, atol=1e-7) + + def _run_scan_node(self, + initial, + x1, + x2, + input_shape, + output_shape, + scan_input_axes=None, + scan_input_directions=None, + scan_output_axes=None, + scan_output_directions=None, + sequence_lens=None, + directions=None): + """ + Subgraph looks like this. + + [const1] state_in concat1_in concat2_in_ + \ | \ / + \--------[Add] [Concat] + | | + | concat_out + | | + | [Add]----------[const1] + | | + | add_out_1 + | | + | [Split] + | / | | \ + state_out split1_out ... split4_out + """ + val_1 = helper.make_tensor( + name='const_tensor', + data_type=TensorProto.FLOAT, + dims=[1], + vals=[1], + ) + constant_node = helper.make_node("Constant", [], ["const_1"], value=val_1) + state_add_node = helper.make_node("Add", ["state_in", "const_1"], + ["state_out"]) + concat_node = helper.make_node("Concat", ["concat1_in", "concat2_in"], + ["concat_out"], + axis=0) + add_node = helper.make_node("Add", ["concat_out", "const_1"], ["add_out"]) + split_node = helper.make_node( + "Split", ["add_out"], + ["split1_out", "split2_out", "split3_out", "split4_out"]) + + state_in = helper.make_tensor_value_info('state_in', TensorProto.FLOAT, [1]) + concat1_in = helper.make_tensor_value_info('concat1_in', TensorProto.FLOAT, + input_shape) + concat2_in = helper.make_tensor_value_info('concat2_in', TensorProto.FLOAT, + input_shape) + state_out = helper.make_tensor_value_info('state_out', TensorProto.FLOAT, + [1]) + split1_out = helper.make_tensor_value_info('split1_out', TensorProto.FLOAT, + output_shape) + split2_out = helper.make_tensor_value_info('split2_out', TensorProto.FLOAT, + output_shape) + split3_out = helper.make_tensor_value_info('split3_out', TensorProto.FLOAT, + output_shape) + split4_out = helper.make_tensor_value_info('split4_out', TensorProto.FLOAT, + output_shape) + + scan_body = helper.make_graph( + [constant_node, state_add_node, concat_node, add_node, split_node], + "scan_body", + [state_in, concat1_in, concat2_in], + [state_out, split1_out, split2_out, split3_out, split4_out], + ) + + node_kwargs = { + "op_type": "Scan", + "inputs": ["initial", "x1", "x2"], + "outputs": ["y", "z1", "z2", "z3", "z4"], + "num_scan_inputs": 2, + "body": scan_body + } + if sequence_lens is not None: + node_kwargs["inputs"] = ["" if sequence_lens is str else "seq_lens" + ] + node_kwargs["inputs"] + + if scan_input_axes is not None: + node_kwargs["scan_input_axes"] = scan_input_axes + if scan_input_directions is not None: + node_kwargs["scan_input_directions"] = scan_input_directions + if scan_output_axes is not None: + node_kwargs["scan_output_axes"] = scan_output_axes + if scan_output_directions is not None: + node_kwargs["scan_output_directions"] = scan_output_directions + if directions is not None: + node_kwargs["directions"] = directions + + scan_node = helper.make_node(**node_kwargs) + + if sequence_lens is None: + inputs = [initial, x1, x2] + else: + inputs = [sequence_lens, initial, x1, x2] + + return run_node(scan_node, inputs) + + def test_scan_v8(self): + if legacy_opset_pre_ver(8) or not legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} not supported.".format( + defs.onnx_opset_version())) + + initial = self._get_rnd_int(0, 100, shape=[5, 1]).astype(np.float32) + x1 = self._get_rnd_float32(0, 1000, shape=[5, 20, 6, 2]) + x2 = self._get_rnd_float32(0, 1000, shape=[5, 20, 6, 2]) + + directions = [0, 1] + sequence_lens = np.array([15, 20, 14, 18, 20]).astype(np.int32) + + Y = initial + (np.shape(x1)[1] if sequence_lens is str else \ + np.reshape(sequence_lens,[-1, 1])) + x1_out = x1 + 1 + # left-right flip x2 (reverse direction) + x2_out = x2[:, ::-1] + 1 + + Z = np.concatenate([x1_out, x2_out], 2) + if sequence_lens is not str: + for batch in range(len(sequence_lens)): + # zero pad from the sequence_lens + shape = list(np.shape(Z[batch])) + seq_len = sequence_lens[batch] + + zero_pad = np.zeros([shape[0] - seq_len] + shape[1:]) + Z[batch] = np.concatenate([Z[batch][:seq_len], zero_pad]) + + output = self._run_scan_node(initial, + x1, + x2, [6, 4], [3, 2], + sequence_lens=sequence_lens, + directions=directions) + output_z = np.concatenate( + [output["z1"], output["z2"], output["z3"], output["z4"]], 2) + + np.testing.assert_almost_equal(output["y"], Y) + np.testing.assert_almost_equal(output_z, Z) + + def test_scan(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} not supported.".format( + defs.onnx_opset_version())) + + initial = self._get_rnd_int(0, 100, shape=[2]).astype(np.float32) + x1 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + x2 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + + Y = initial + np.shape(x1)[0] + Z = np.concatenate([x1, x2], 1) + 1 + + output = self._run_scan_node(initial, x1, x2, [6, 2], [3, 2]) + output_z = np.concatenate( + [output["z1"], output["z2"], output["z3"], output["z4"]], 1) + + np.testing.assert_almost_equal(output["y"], Y) + np.testing.assert_almost_equal(output_z, Z) + + def test_scan_input_directions(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} not supported.".format( + defs.onnx_opset_version())) + + initial = self._get_rnd_int(0, 100, shape=[1]).astype(np.float32) + x1 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + x2 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + + Y = initial + np.shape(x1)[0] + Z = np.concatenate([x1[::-1], x2], 1) + 1 + + output = self._run_scan_node(initial, + x1, + x2, [6, 2], [3, 2], + scan_input_directions=[1, 0]) + output_z = np.concatenate( + [output["z1"], output["z2"], output["z3"], output["z4"]], 1) + + np.testing.assert_almost_equal(output["y"], Y) + np.testing.assert_almost_equal(output_z, Z) + + def test_scan_input_axes(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} not supported.".format( + defs.onnx_opset_version())) + + initial = self._get_rnd_int(0, 100, shape=[1]).astype(np.float32) + x1 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + x2 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + + Y = initial + np.shape(x1)[1] + x1_transpose = np.transpose(x1, (1, 0, 2)) + x2_transpose = np.transpose(x2, (1, 0, 2)) + Z = np.concatenate([x1_transpose, x2_transpose], 1) + 1 + + output = self._run_scan_node(initial, + x1, + x2, [3, 2], [10, 2], + scan_input_axes=[1, 1]) + output_z = np.concatenate( + [output["z1"], output["z2"], output["z3"], output["z4"]], 1) + + np.testing.assert_almost_equal(output["y"], Y) + np.testing.assert_almost_equal(output_z, Z) + + def test_scan_output_directions(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} not supported.".format( + defs.onnx_opset_version())) + + initial = self._get_rnd_int(0, 100, shape=[1]).astype(np.float32) + x1 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + x2 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + + Y = initial + np.shape(x1)[0] + Z = np.concatenate([x1, x2], 1) + 1 + + output = self._run_scan_node(initial, + x1, + x2, [6, 2], [3, 2], + scan_output_directions=[1, 0, 0, 1]) + output_z = np.concatenate( + [output["z1"][::-1], output["z2"], output["z3"], output["z4"][::-1]], 1) + + np.testing.assert_almost_equal(output["y"], Y) + np.testing.assert_almost_equal(output_z, Z) + + def test_scan_output_axes(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} not supported.".format( + defs.onnx_opset_version())) + + initial = self._get_rnd_int(0, 100, shape=[1]).astype(np.float32) + x1 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + x2 = self._get_rnd_float32(0, 1000, shape=[20, 6, 2]) + + Y = initial + np.shape(x1)[0] + Z = np.concatenate([x1, x2], 1) + 1 + Z = np.transpose(Z, (1, 0, 2)) + + output = self._run_scan_node(initial, + x1, + x2, [10, 2], [3, 2], + scan_output_axes=[1, 1, 1, 1]) + output_z = np.concatenate( + [output["z1"], output["z2"], output["z3"], output["z4"]], 0) + + np.testing.assert_almost_equal(output["y"], Y) + np.testing.assert_almost_equal(output_z, Z) + + def test_scatter_elements1(self): + data = np.array([[1.0, 2.0, 3.0, 4.0, 5.0]], dtype=np.float32) + indices = np.array([[1, 3]], dtype=np.int64) + updates = np.array([[1.1, 2.1]], dtype=np.float32) + axis = 1 + ref_output = np.array([[1.0, 1.1, 3.0, 2.1, 5.0]], dtype=np.float32) + + if legacy_opset_pre_ver(11): + node_def = helper.make_node("Scatter", ["data", "indices", "updates"], + ["outputs"], + axis=axis) + output = run_node(node_def, [data, indices, updates]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + else: + node_def = helper.make_node("ScatterElements", + ["data", "indices", "updates"], ["outputs"], + axis=axis) + output = run_node(node_def, [data, indices, updates]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + + def test_scatter_elements2(self): + data = np.array([ + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + [0.0, 0.0, 0.0], + ], + dtype=np.float32) + indices = np.array([ + [1, 0, 2], + [0, 2, 1], + ], dtype=np.int64) + updates = np.array([ + [1.0, 1.1, 1.2], + [2.0, 2.1, 2.2], + ], dtype=np.float32) + ref_output = np.array([ + [2.0, 1.1, 0.0], + [1.0, 0.0, 2.2], + [0.0, 2.1, 1.2], + ], + dtype=np.float32) + + if legacy_opset_pre_ver(11): + node_def = helper.make_node("Scatter", ["data", "indices", "updates"], + ["outputs"]) + output = run_node(node_def, [data, indices, updates]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + else: + node_def = helper.make_node("ScatterElements", + ["data", "indices", "updates"], ["outputs"]) + output = run_node(node_def, [data, indices, updates]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + + def test_scatter_elements3(self): + # indices out of bounds + data = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], dtype=np.float32) + indices = np.array([[0, 1, 2]], dtype=np.int64) + updates = np.array([[1.1, 2.1, 3.1]], dtype=np.float32) + + if legacy_opset_pre_ver(11): + node_def = helper.make_node("Scatter", ["data", "indices", "updates"], + ["outputs"]) + else: + node_def = helper.make_node("ScatterElements", + ["data", "indices", "updates"], ["outputs"]) + with np.testing.assert_raises(tf.errors.InvalidArgumentError): + output = run_node(node_def, [data, indices, updates]) + + def test_scatter_nd(self): + if legacy_opset_pre_ver(11): + raise unittest.SkipTest( + "ONNX version {} doesn't support ScatterND.".format( + defs.onnx_opset_version())) + + # valid positve and negative indices for elements + data = np.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=np.float32) + indices = np.array([[4], [3], [1], [7]], dtype=np.int64) + updates = np.array([9, 10, 11, 12], dtype=np.float32) + ref_output = np.array([1, 11, 3, 10, 9, 6, 7, 12], dtype=np.float32) + node_def = helper.make_node("ScatterND", ["data", "indices", "updates"], + ["outputs"]) + output = run_node(node_def, [data, indices, updates]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + + # valid positive and negative indices for slices + data = np.reshape(np.arange(1, 25, dtype=np.float32), [2, 3, 4]) + indices = np.array([[-2, -1], [1, 0]], dtype=np.int64) + updates = np.array([[39, 40, 41, 42], [43, 44, 45, 46]], dtype=np.float32) + ref_output = np.array( + [[[1, 2, 3, 4], [5, 6, 7, 8], [39, 40, 41, 42]], + [[43, 44, 45, 46], [17, 18, 19, 20], [21, 22, 23, 24]]], + dtype=np.float32) + output = run_node(node_def, [data, indices, updates]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + indices = np.array([[-1]], dtype=np.int64) + updates = np.array([[[43, 44, 45, 46], [47, 48, 49, 50], [51, 52, 53, 54]]], + dtype=np.float32) + ref_output = np.array( + [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], + [[43, 44, 45, 46], [47, 48, 49, 50], [51, 52, 53, 54]]], + dtype=np.float32) + output = run_node(node_def, [data, indices, updates]) + np.testing.assert_almost_equal(output["outputs"], ref_output) + + # indices out of bounds + indices = np.array([[0, 1, 2], [-1, -1, -3], [-2, -3, -4], [0, 2, -5]], + dtype=np.int64) + updates = np.array([37, 52, 30, 39], dtype=np.float32) + with np.testing.assert_raises(tf.errors.InvalidArgumentError): + output = run_node(node_def, [data, indices, updates]) + indices = np.array([[0, 1], [-1, -1], [-2, -4]], dtype=np.int64) + updates = np.array([[35, 36, 37, 38], [51, 52, 53, 54], [31, 32, 33, 34]], + dtype=np.float32) + with np.testing.assert_raises(tf.errors.InvalidArgumentError): + output = run_node(node_def, [data, indices, updates]) + + def test_shape(self): + node_def = helper.make_node("Shape", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[5, 10, 10, 3]) + output = run_node(node_def, [x]) + np.testing.assert_allclose(output["Y"], np.shape(x)) + + def test_shrink(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support Shrink.".format( + defs.onnx_opset_version())) + + node_def = helper.make_node("Shrink", ["X"], ["Y"], bias=1.5, lambd=1.5) + + X = np.arange(-2.0, 2.1, dtype=np.float32) + Y = np.array([-0.5, 0, 0, 0, 0.5], dtype=np.float32) + output = run_node(node_def, [X]) + np.testing.assert_almost_equal(output["Y"], Y) + + def test_sigmoid(self): + node_def = helper.make_node("Sigmoid", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[1000]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], 1 / (1 + np.exp(-x))) + + def test_sign(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support Sign.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Sign", ["X"], ["Y"]) + x = self._get_rnd_float32(-10, 10, [3, 5]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.sign(x)) + + def test_sinh(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support Sinh.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Sinh", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[3, 4, 5]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.sinh(x)) + + def test_size(self): + node_def = helper.make_node("Size", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[5, 10, 10, 3]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.size(x)) + + def test_slice(self): + # test case 1 with normal inputs + axes = [0, 1, 2] + starts = [0, 0, 0] + ends = [2, 2, 2] + steps = [1, 1, 1] + + if legacy_opset_pre_ver(10): + node_def = helper.make_node("Slice", ["X"], ["S"], + axes=axes, + starts=starts, + ends=ends) + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["S"], x[0:2, 0:2, 0:2]) + else: + node_def = helper.make_node("Slice", + ["X", "starts", "ends", "axes", "steps"], + ["S"]) + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = run_node(node_def, [x, starts, ends, axes, steps]) + np.testing.assert_almost_equal(output["S"], x[0:2, 0:2, 0:2]) + + # test case 2 with negative, out-of-bound and default inputs + axes = [0, 2] + starts = [0, -7] + ends = [-8, 20] + + if legacy_opset_pre_ver(10): + node_def = helper.make_node("Slice", ["X"], ["S"], + axes=axes, + starts=starts, + ends=ends) + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["S"], x[0:-8, :, -7:20]) + else: + node_def = helper.make_node("Slice", ["X", "starts", "ends", "axes"], + ["S"]) + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = run_node(node_def, [x, starts, ends, axes]) + np.testing.assert_almost_equal(output["S"], x[0:-8, :, -7:20]) + + # test case 3 with non-default steps + axes = [0, 1, 2] + starts = [0, 0, 0] + ends = [2, 2, 2] + steps = [2, -2, -1] + + if legacy_opset_pre_ver(10) == False: + node_def = helper.make_node("Slice", + ["X", "starts", "ends", "axes", "steps"], + ["S"]) + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = run_node(node_def, [x, starts, ends, axes, steps]) + np.testing.assert_almost_equal(output["S"], x[0:2:2, 0:2:-2, 0:2:-1]) + + def test_softplus(self): + node_def = helper.make_node("Softplus", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[3, 4, 5]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.log(np.exp(x) + 1), decimal=5) + + def test_softsign(self): + node_def = helper.make_node("Softsign", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[3, 4, 5]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], x / (1 + np.abs(x))) + + def test_space_to_depth(self): + node_def = helper.make_node("SpaceToDepth", ["X"], ["Y"], blocksize=2) + x_shape = [1, 3, 2, 2] + x = self._get_rnd_float32(shape=x_shape) + output = run_node(node_def, [x]) + x = np.transpose(x, (0, 2, 3, 1)) + y = np.reshape(np.swapaxes(x.reshape(1, 1, 1, 1, 1, 12), 2, 3), + (1, 1, 1, 12)) + y = np.transpose(y, (0, 3, 1, 2)) + np.testing.assert_allclose(output["Y"], y, rtol=1e-3) + + def test_split(self): + split = [3, 3, 4] + node_def = helper.make_node("Split", ["X"], + ["Z%i" % i for i in range(len(split))], + axis=0, + split=split) + x = self._get_rnd_float32(shape=[100]).reshape([10, 10]) + + output = run_node(node_def, [x]) + for a, b in zip(list(output), np.split(x, np.cumsum(split))[:-1]): + np.testing.assert_almost_equal(a, b) + + # test axis out of bound + node_def = helper.make_node("Split", ["X"], + ["Z%i" % i for i in range(len(split))], + axis=3, + split=split) + with np.testing.assert_raises(ValueError): + output = run_node(node_def, [x]) + + def test_sqrt(self): + node_def = helper.make_node("Sqrt", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[1000]) + 1.0 + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.sqrt(x), decimal=5) + + def test_squeeze(self): + node_def = helper.make_node("Squeeze", ["X"], ["Y"], axes=[2]) + x = np.array([[[0], [1], [2]]]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.squeeze(x, axis=2)) + + def test_sub(self): + node_def = helper.make_node("Sub", ["X", "Y"], ["Z"]) + x = self._get_rnd_float32(shape=[10, 10]) + y = self._get_rnd_float32(shape=[10, 10]) + output = run_node(node_def, [x, y]) + np.testing.assert_almost_equal(output["Z"], np.subtract(x, y)) + + def test_sum(self): + node_def = helper.make_node("Sum", ["X1", "X2", "X3", "X4"], ["Z"]) + x1 = self._get_rnd_float32(shape=[10, 10]) + x2 = self._get_rnd_float32(shape=[10, 10]) + x3 = self._get_rnd_float32(shape=[10, 10]) + x4 = self._get_rnd_float32(shape=[10, 10]) + output = run_node(node_def, [x1, x2, x3, x4]) + test_output = x1 + x2 + x3 + x4 + np.testing.assert_almost_equal(output["Z"], test_output) + + def test_tanh(self): + node_def = helper.make_node("Tanh", ["X"], ["Y"]) + x = self._get_rnd_float32(shape=[1000]) + 1.0 + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.tanh(x), decimal=5) + + def test_tfidf_vectorizer(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest( + "ONNX version {} doesn't support TfIdfVectorizer.".format( + defs.onnx_opset_version())) + + def run_test_ints(): + node_def = helper.make_node("TfIdfVectorizer", ["X"], ["Y"], + mode=mode, + min_gram_length=min_gram_len, + max_gram_length=max_gram_len, + max_skip_count=max_skip, + ngram_counts=ngram_counts, + ngram_indexes=ngram_indexes, + weights=weights, + pool_int64s=pool_int64s) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], y) + + def run_test_strings(): + node_def = helper.make_node("TfIdfVectorizer", ["X"], ["Y"], + mode=mode, + min_gram_length=min_gram_len, + max_gram_length=max_gram_len, + max_skip_count=max_skip, + ngram_counts=ngram_counts, + ngram_indexes=ngram_indexes, + weights=weights, + pool_strings=pool_strings) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], y) + + # test 2d inputs with 3 elements, output contains 1-grams and 2-grams + x = np.array([[1, 1, 3, 3, 3, 7], [8, 6, 7, 5, 6, 8], [8, 6, 7, 5, 6, + 8]]).astype(np.int32) + y = np.array([[0., 3., 0., 0., 0., 0., 0.], [0., 0., 1., 0., 1., 0., 1.], + [0., 0., 1., 0., 1., 0., 1.]]).astype(np.float32) + ngram_counts = np.array([0, 4]).astype(np.int64) + ngram_indexes = np.array([0, 1, 2, 3, 4, 5, 6]).astype(np.int64) + pool_int64s = np.array([2, 3, 5, 4, 5, 6, 7, 8, 6, 7]).astype(np.int64) + min_gram_len = 1 + max_gram_len = 2 + max_skip = 0 + mode = 'TF' + weights = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) + run_test_ints() + + # test 1d inputs with indexes in non-default order, max_skip=3, output 2-grams + x = np.array([1, 1, 3, 3, 3, 7, 8, 6, 7, 5, 6, 8]).astype(np.int32) + y = np.array([0., 1., 0., 1., 0., 0., 2.]).astype(np.float32) + ngram_counts = np.array([0, 4]).astype(np.int64) + ngram_indexes = np.array([5, 0, 2, 4, 1, 6, 3]).astype(np.int64) + pool_int64s = np.array([2, 3, 5, 4, 5, 6, 7, 8, 6, 7]).astype(np.int64) + min_gram_len = 2 + max_gram_len = 2 + max_skip = 3 + mode = 'TF' + weights = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) + run_test_ints() + + # test IDF mode with weights, max_skip=5, output contains 1-grams and 2-grams + x = np.array([[1, 1, 3, 3, 3, 7], [8, 6, 7, 5, 6, 8]]).astype(np.int32) + y = np.array([[0., 0.1, 0., 0., 0., 0., 0.], + [0., 0., 0.1, 0., 0.5, 0.5, 0.5]]).astype(np.float32) + ngram_counts = np.array([0, 4]).astype(np.int64) + ngram_indexes = np.array([0, 1, 2, 3, 4, 5, 6]).astype(np.int64) + pool_int64s = np.array([2, 3, 5, 4, 5, 6, 7, 8, 6, 7]).astype(np.int64) + min_gram_len = 1 + max_gram_len = 2 + max_skip = 5 + mode = 'IDF' + weights = np.array([0.1, 0.1, 0.1, 0.1, 0.5, 0.5, 0.5]) + run_test_ints() + + # test strings inputs, max_skip=5, output contains 1-grams and 2-grams + x = np.array(['a', 'a', 'b', 'b', 'b', 'c', 'd', 'e', 'c', 'f', 'e', 'd']) + y = np.array([0., 3., 1., 0., 1., 3., 1.]).astype(np.float32) + ngram_counts = np.array([0, 4]).astype(np.int64) + ngram_indexes = np.array([0, 1, 2, 3, 4, 5, 6]).astype(np.int64) + pool_strings = np.array(['x', 'b', 'f', 'y', 'f', 'e', 'c', 'd', 'e', 'c']) + min_gram_len = 1 + max_gram_len = 2 + max_skip = 5 + mode = 'TF' + run_test_strings() + + def test_thresholded_relu(self): + alpha = 2.0 + node_def = helper.make_node("ThresholdedRelu", ["X"], ["Y"], alpha=alpha) + x = self._get_rnd_float32(-3.0, 3.0, [10]) + y = np.clip(x, alpha, np.inf) + y[y == alpha] = 0 + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], y) + + def test_tile(self): + if legacy_onnx_pre_ver(1, 2): + raise unittest.SkipTest( + "The current version of ONNX does not record correctly the opset of Tile." + ) + node_def = helper.make_node("Tile", ["X1", "X2"], ["Z"]) + x = self._get_rnd_float32(shape=[3, 5, 5, 3]) + repeats = [1, 1, 2, 1] + output = run_node(node_def, [x, repeats]) + np.testing.assert_allclose(output["Z"], np.tile(x, repeats), rtol=1e-3) + + def test_transpose(self): + node_def = helper.make_node("Transpose", ["X"], ["Y"], perm=[0, 2, 1]) + x = self._get_rnd_float32(shape=[1000]).reshape([10, 10, 10]) + output = run_node(node_def, [x]) + np.testing.assert_almost_equal(output["Y"], np.transpose(x, (0, 2, 1))) + + def test_topk(self): + x = np.arange(15, dtype=np.float32).reshape(3, 5) + values = np.array([[4, 3], [9, 8], [14, 13]], dtype=np.float32) + indices = np.array([[4, 3], [4, 3], [4, 3]], dtype=np.int64) + if legacy_opset_pre_ver(10): # for opset = 1 + node_def = helper.make_node("TopK", ["x"], ["values", "indices"], k=2) + output = run_node(node_def, [x]) + elif legacy_opset_pre_ver(11): # for opset = 10 + k = np.array([2], dtype=np.int64) + node_def = helper.make_node("TopK", ["x", "k"], ["values", "indices"]) + output = run_node(node_def, [x, k]) + else: # for opset = 11 + x = np.array([[3, 2, 5, 10, 7], [12, 15, 10, 7, 20], [21, 16, 5, 3, 6]], + dtype=np.float32) + values = np.array([[3, 2], [10, 7], [5, 3]], dtype=np.float32) + indices = np.array([[0, 1], [2, 3], [2, 3]], dtype=np.int64) + k = np.array([2], dtype=np.int64) + node_def = helper.make_node("TopK", ["x", "k"], ["values", "indices"], + largest=0, + sorted=0) + output = run_node(node_def, [x, k]) + np.testing.assert_almost_equal(output["values"], values) + np.testing.assert_almost_equal(output["indices"], indices) + + def test_where(self): + if legacy_opset_pre_ver(9): + raise unittest.SkipTest("ONNX version {} doesn't support Where.".format( + defs.onnx_opset_version())) + node_def = helper.make_node("Where", ["C", "X", "Y"], ["Z"]) + c = np.array([[1, 0], [1, 1]], dtype=np.bool) + x = np.array([[1, 2], [3, 4]], dtype=np.float32) + y = np.array([[9, 8], [7, 6]], dtype=np.float32) + output = run_node(node_def, [c, x, y]) + np.testing.assert_almost_equal(output["Z"], np.where(c, x, y)) + + +if __name__ == '__main__': + unittest.main() diff --git a/pt2tf/onnx-tensorflow/test/backend/test_onnx_backend.py b/pt2tf/onnx-tensorflow/test/backend/test_onnx_backend.py new file mode 100644 index 0000000..2266427 --- /dev/null +++ b/pt2tf/onnx-tensorflow/test/backend/test_onnx_backend.py @@ -0,0 +1,119 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import os +import re +import unittest + +import onnx.backend.test + +from onnx import defs + +from onnx_tf import opset_version +from onnx_tf.backend import TensorflowBackend +from onnx_tf.common.legacy import legacy_onnx_pre_ver +from onnx_tf.common.legacy import legacy_opset_pre_ver + +def get_onnxtf_supported_ops(): + return opset_version.backend_opset_version + +def get_onnx_supported_ops(): + onnx_ops_dict = {} + for schema in defs.get_all_schemas(): + onnx_ops_dict[schema.name] = { + 'version': schema.since_version, + 'deprecated': schema.deprecated + } + return onnx_ops_dict + +# This is a pytest magic variable to load extra plugins +pytest_plugins = 'onnx.backend.test.report', + +backend_test = onnx.backend.test.BackendTest(TensorflowBackend, __name__) + +# The test cases excluded below should be considered permanent restrictions +# based on the TensorFlow implementation. Unimplemented operators will raise +# a BackendIsNotSupposedToImplementIt exception so that their test cases +# will pass and show a verbose message stating it was effectively skipped. + +# https://github.com/onnx/onnx/issues/349 +backend_test.exclude(r'[a-z,_]*GLU[a-z,_]*') + +# TF does not support dialation and strides at the same time: +# Will produce strides > 1 not supported in conjunction with dilation_rate > 1 +backend_test.exclude(r'[a-z,_]*dilated_strided[a-z,_]*') +backend_test.exclude(r'[a-z,_]*Conv2d_dilated[a-z,_]*') + +# TF does not have column major max_pool_with_argmax +backend_test.exclude( + r'[a-z,_]*maxpool_with_argmax_2d_precomputed_strides[a-z,_]*') + +# PRelu OnnxBackendPyTorchConvertedModelTest has wrong dim for broadcasting +backend_test.exclude(r'[a-z,_]*PReLU_[0-9]d_multiparam[a-z,_]*') + +# TF does not support int8, int16, uint8, uint16, uint32, uint64 for +# tf.floormod and tf.truncatemod +backend_test.exclude(r'test_mod_[a-z,_]*uint[0-9]+') +backend_test.exclude(r'test_mod_[a-z,_]*int(8|(16))+') + +# TF only support uint8, int32, int64 for indices and int32 for depth in +# tf.one_hot +backend_test.exclude(r'test_onehot_[a-z,_]*') + +# TF doesn't support most of the attributes in resize op +# test_node.py will cover the test +backend_test.exclude(r'test_resize_[a-z,_]*') + +# range is using loop in the model test but all the outputs datatype are +# missing in the body attribute of the loop +backend_test.exclude( + r'test_range_float_type_positive_delta_expanded[a-z,_]*') +backend_test.exclude( + r'test_range_int32_type_negative_delta_expanded[a-z,_]*') + +# skip all the cumsum testcases because all the axis in the testcases +# are created as a 1-D 1 element tensor, but the spec clearly state +# that axis should be a 0-D tensor(scalar) +backend_test.exclude(r'test_cumsum_[a-z,_]*') + +if legacy_opset_pre_ver(7): + backend_test.exclude(r'[a-z,_]*Upsample[a-z,_]*') + +if 'TRAVIS' in os.environ: + backend_test.exclude('test_vgg19') + backend_test.exclude('zfnet512') + +if legacy_onnx_pre_ver(1, 2): + # These following tests fails by a tiny margin with onnx<1.2: + backend_test.exclude('test_operator_add_broadcast_cpu') + backend_test.exclude('test_operator_add_size1_broadcast_cpu') + backend_test.exclude('test_operator_add_size1_right_broadcast_cpu') + backend_test.exclude('test_operator_add_size1_singleton_broadcast_cpu') + backend_test.exclude('test_averagepool_3d_default_cpu') + # Do not support consumed flag: + backend_test.exclude('test_batch_normalization') + # Do not support RNN testing on onnx<1.2 due to incorrect tests: + backend_test.exclude(r'test_operator_rnn_cpu') + backend_test.exclude(r'test_operator_lstm_cpu') + backend_test.exclude(r'test_operator_rnn_single_layer_cpu') + +# The onnx test for cast, float to string, does not work +if not legacy_opset_pre_ver(9): + backend_test.exclude(r'[a-z,_]*cast[a-z,_]*') + +if not legacy_opset_pre_ver(10): + # Do not support dilations != 1 for ConvTranspose, test is added in opset 10 + backend_test.exclude(r'[a-z,_]*convtranspose_dilations[a-z,_]*') + +# some NLL test cases do not use the `NegativeLogLikelihoodLoss` operator +# however they use the `where` operator which has some restrictions in TF 1.x +# (x,y tensors must have same shape, broadcastable shapes not supported) +backend_test.exclude(r'test_negative_log_likelihood_loss_[a-z,_]*') + +# import all test cases at global scope to make them visible to python.unittest +globals().update(backend_test.enable_report().test_cases) + +if __name__ == '__main__': + unittest.main() diff --git a/pt2tf/onnx-tensorflow/test/download_model.sh b/pt2tf/onnx-tensorflow/test/download_model.sh new file mode 100644 index 0000000..bf7c4ab --- /dev/null +++ b/pt2tf/onnx-tensorflow/test/download_model.sh @@ -0,0 +1,28 @@ +mkdir -p ../../onnx_models/ + +wget https://s3.amazonaws.com/download.onnx/models/bvlc_alexnet.tar.gz --directory-prefix=../../onnx_models/ +pushd ../../onnx_models/ && tar -xzf bvlc_alexnet.tar.gz && popd + +wget https://s3.amazonaws.com/download.onnx/models/densenet121.tar.gz --directory-prefix=../../onnx_models/ +pushd ../../onnx_models/ && tar -xzf densenet121.tar.gz && popd + +wget https://s3.amazonaws.com/download.onnx/models/inception_v1.tar.gz --directory-prefix=../../onnx_models/ +pushd ../../onnx_models/ && tar -xzf inception_v1.tar.gz && popd + +wget https://s3.amazonaws.com/download.onnx/models/inception_v2.tar.gz --directory-prefix=../../onnx_models/ +pushd ../../onnx_models/ && tar -xzf inception_v2.tar.gz && popd + +wget https://s3.amazonaws.com/download.onnx/models/resnet50.tar.gz --directory-prefix=../../onnx_models/ +pushd ../../onnx_models/ && tar -xzf resnet50.tar.gz && popd + +wget https://s3.amazonaws.com/download.onnx/models/shufflenet.tar.gz --directory-prefix=../../onnx_models/ +pushd ../../onnx_models/ && tar -xzf shufflenet.tar.gz && popd + +wget https://s3.amazonaws.com/download.onnx/models/squeezenet.tar.gz --directory-prefix=../../onnx_models/ +pushd ../../onnx_models/ && tar -xzf squeezenet.tar.gz && popd + +wget https://s3.amazonaws.com/download.onnx/models/vgg16.tar.gz --directory-prefix=../../onnx_models/ +pushd ../../onnx_models/ && tar -xzf vgg16.tar.gz && popd + +wget https://s3.amazonaws.com/download.onnx/models/vgg19.tar.gz --directory-prefix=../../onnx_models/ +pushd ../../onnx_models/ && tar -xzf vgg19.tar.gz && popd \ No newline at end of file diff --git a/pt2tf/onnx-tensorflow/test/test_cli.py b/pt2tf/onnx-tensorflow/test/test_cli.py new file mode 100644 index 0000000..8df16c4 --- /dev/null +++ b/pt2tf/onnx-tensorflow/test/test_cli.py @@ -0,0 +1,79 @@ +import inspect +import os +import subprocess +import unittest + +import onnx +from onnx.backend.test.runner import Runner +from onnx.backend.test.case.model import TestCase + +from onnx_tf.backend import TensorflowBackend +from onnx_tf.common import IS_PYTHON3 +from onnx_tf.common.legacy import legacy_onnx_pre_ver + +_ONNX_MODELS = [( + "mobilenetv2-1.0", + "https://s3.amazonaws.com/onnx-model-zoo/mobilenet/mobilenetv2-1.0/mobilenetv2-1.0.tar.gz" +)] + + +class TestCli(unittest.TestCase): + + @staticmethod + def prepare_model(model_name, url): + if legacy_onnx_pre_ver(1, 5, 0): + prepare_model_data = Runner._prepare_model_data + else: + prepare_model_data = Runner.prepare_model_data + if IS_PYTHON3: + params = list( + inspect.signature(prepare_model_data).parameters.keys()) + else: + params = inspect.getargspec(prepare_model_data).args + runner_class = Runner + if params[0] == "self": + runner_class = Runner(TensorflowBackend) + if legacy_onnx_pre_ver(1, 5, 0): + prepare_model_data = runner_class._prepare_model_data + else: + prepare_model_data = runner_class.prepare_model_data + if legacy_onnx_pre_ver(1, 4, 0): + tc = TestCase( + name="test_{}".format(model_name), + model_name=model_name, + url=url, + model_dir=None, + model=None, + data_sets=None, + kind='real') + else: + tc = TestCase( + name="test_{}".format(model_name), + model_name=model_name, + url=url, + model_dir=None, + model=None, + data_sets=None, + kind='real', + rtol=1e-3, + atol=1e-7) + return prepare_model_data(model_test=tc) + + def test_convert_to_tf(self): + if legacy_onnx_pre_ver(1, 2, 1): + raise unittest.SkipTest( + "The current version of ONNX uses dead model link.") + for model_name, url in _ONNX_MODELS: + model_dir = self.prepare_model(model_name, url) + subprocess.check_call([ + "onnx-tf", + "convert", + "-i", + os.path.join(model_dir, '{}.onnx'.format(model_name)), + "-o", + os.path.join(model_dir, '{}.pb'.format(model_name)), + ]) + + +if __name__ == '__main__': + unittest.main() diff --git a/pt2tf/onnx-tensorflow/third_party/__init__.py b/pt2tf/onnx-tensorflow/third_party/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pt2tf/onnx-tensorflow/third_party/get_info.py b/pt2tf/onnx-tensorflow/third_party/get_info.py new file mode 100644 index 0000000..4aa20bb --- /dev/null +++ b/pt2tf/onnx-tensorflow/third_party/get_info.py @@ -0,0 +1,110 @@ +# Copyright 2015: Mirantis Inc. +# 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. + +import re +import sys + +PARAM_OR_RETURNS_REGEX = re.compile(":(?:param|returns)") +RETURNS_REGEX = re.compile(":returns: (?P.*)", re.S) +PARAM_REGEX = re.compile(":param (?P[\*\w]+): (?P.*?)" + "(?:(?=:param)|(?=:return)|(?=:raises)|\Z)", re.S) + + +def trim(docstring): + """trim function from PEP-257""" + if not docstring: + return "" + # Convert tabs to spaces (following the normal Python rules) + # and split into a list of lines: + lines = docstring.expandtabs().splitlines() + # Determine minimum indentation (first line doesn't count): + indent = sys.maxsize + for line in lines[1:]: + stripped = line.lstrip() + if stripped: + indent = min(indent, len(line) - len(stripped)) + # Remove indentation (first line is special): + trimmed = [lines[0].strip()] + if indent < sys.maxsize: + for line in lines[1:]: + trimmed.append(line[indent:].rstrip()) + # Strip off trailing and leading blank lines: + while trimmed and not trimmed[-1]: + trimmed.pop() + while trimmed and not trimmed[0]: + trimmed.pop(0) + + # Current code/unittests expects a line return at + # end of multiline docstrings + # workaround expected behavior from unittests + if "\n" in docstring: + trimmed.append("") + + # Return a single string: + return "\n".join(trimmed) + + +def reindent(string): + return "\n".join(l.strip() for l in string.strip().split("\n")) + + +def parse_docstring(docstring): + """Parse the docstring into its components. + + :returns: a dictionary of form + { + "short_description": ..., + "long_description": ..., + "params": [{"name": ..., "doc": ...}, ...], + "returns": ... + } + """ + + short_description = long_description = returns = "" + params = [] + + if docstring: + docstring = trim(docstring) + + lines = docstring.split("\n", 1) + short_description = lines[0] + + if len(lines) > 1: + long_description = lines[1].strip() + + params_returns_desc = None + + match = PARAM_OR_RETURNS_REGEX.search(long_description) + if match: + long_desc_end = match.start() + params_returns_desc = long_description[long_desc_end:].strip() + long_description = long_description[:long_desc_end].rstrip() + + if params_returns_desc: + params = [ + {"name": name, "doc": trim(doc)} + for name, doc in PARAM_REGEX.findall(params_returns_desc) + ] + + match = RETURNS_REGEX.search(params_returns_desc) + if match: + returns = reindent(match.group("doc")) + + return { + "short_description": short_description, + "long_description": long_description, + "params": params, + "returns": returns + } diff --git a/pt2tf/onnx-tensorflow/util/get_version.py b/pt2tf/onnx-tensorflow/util/get_version.py new file mode 100644 index 0000000..26548af --- /dev/null +++ b/pt2tf/onnx-tensorflow/util/get_version.py @@ -0,0 +1,18 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import sys +import onnx +import tensorflow +import onnx_tf + +print("Python version:") +print(sys.version) +print("ONNX version:") +print(onnx.version.version) +print("ONNX-TF version:") +print(onnx_tf.__version__) +print("Tensorflow version:") +print(tensorflow.__version__) diff --git a/pt2tf/pt2onnx.py b/pt2tf/pt2onnx.py new file mode 100644 index 0000000..86ad5cb --- /dev/null +++ b/pt2tf/pt2onnx.py @@ -0,0 +1,19 @@ +import torch +from efficientnet_pytorch import EfficientNet + +# Specify which model to use +model_name = 'efficientnet-b3' +image_size = EfficientNet.get_image_size(model_name) +print('Image size: ', image_size) + +# Load model +model = EfficientNet.from_pretrained(model_name) +model.set_swish(memory_efficient=False) +model.eval() +print('Model image size: ', model._global_params.image_size) + +# Dummy input for ONNX +dummy_input = torch.randn(1, 3, 300, 300) + +# Export with ONNX +torch.onnx.export(model, dummy_input, f"{model_name}.onnx", verbose=True) diff --git a/pt2tf/requirements.txt b/pt2tf/requirements.txt new file mode 100644 index 0000000..4ef847f --- /dev/null +++ b/pt2tf/requirements.txt @@ -0,0 +1,30 @@ +absl-py==0.10.0 +astor==0.8.1 +efficientnet-pytorch==0.7.0 +future==0.18.2 +gast==0.2.2 +google-pasta==0.2.0 +grpcio==1.32.0 +h5py==2.10.0 +importlib-metadata==1.7.0 +Keras-Applications==1.0.8 +Keras-Preprocessing==1.1.2 +Markdown==3.2.2 +numpy==1.19.2 +onnx==1.7.0 +-e git+https://github.com/onnx/onnx-tensorflow.git@6b9e76d6fca74d5ddbf47049b9670120abaaf70f#egg=onnx_tf +opt-einsum==3.3.0 +Pillow==7.2.0 +protobuf==3.13.0 +PyYAML==5.3.1 +six==1.15.0 +tensorboard==1.15.0 +tensorflow==1.15.0 +tensorflow-estimator==1.15.1 +termcolor==1.1.0 +torch==1.6.0 +torchvision==0.7.0 +typing-extensions==3.7.4.3 +Werkzeug==1.0.1 +wrapt==1.12.1 +zipp==3.1.0