onnx2tf 1.29.18__py3-none-any.whl → 1.29.19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
onnx2tf/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from onnx2tf.onnx2tf import convert, main
2
2
 
3
- __version__ = '1.29.18'
3
+ __version__ = '1.29.19'
onnx2tf/ops/Col2Im.py CHANGED
@@ -1,9 +1,9 @@
1
+ import sys
1
2
  import random
2
3
  random.seed(0)
3
4
  import numpy as np
4
5
  np.random.seed(0)
5
6
  import tensorflow as tf
6
- import tf_keras
7
7
  import onnx_graphsurgeon as gs
8
8
  from onnx2tf.utils.common_functions import (
9
9
  get_constant_or_variable,
@@ -14,57 +14,32 @@ from onnx2tf.utils.common_functions import (
14
14
  pre_process_transpose,
15
15
  post_process_transpose,
16
16
  )
17
+ from onnx2tf.utils.logging import *
17
18
 
18
19
 
19
- class Col2ImLayer(tf_keras.layers.Layer):
20
- def __init__(self):
21
- super(Col2ImLayer, self).__init__()
20
+ def _build_col2im_kernel(
21
+ *,
22
+ k_h,
23
+ k_w,
24
+ dilation_h,
25
+ dilation_w,
26
+ dtype,
27
+ ):
28
+ k_h = tf.cast(k_h, tf.int32)
29
+ k_w = tf.cast(k_w, tf.int32)
30
+ eff_k_h = (k_h - 1) * dilation_h + 1
31
+ eff_k_w = (k_w - 1) * dilation_w + 1
22
32
 
23
- def call(
24
- self,
25
- input_tensor,
26
- input_block_shape,
27
- strides,
28
- input_image_shape,
29
- pads,
30
- dilations,
31
- output_shape = None,
32
- ):
33
- N, _, L = input_tensor.shape
34
- if output_shape is not None:
35
- C = tf.convert_to_tensor(output_shape[1])
36
- output_shape = tf.convert_to_tensor([output_shape[0]] + [s for s in output_shape[2:]] + [output_shape[1]])
37
- else:
38
- C = tf.convert_to_tensor(input_tensor.shape[1] // (input_block_shape[0] * input_block_shape[1]))
39
- output_shape = tf.convert_to_tensor([N] + input_image_shape + [C])
40
- im = tf.TensorArray(input_tensor.dtype, size=N, dynamic_size=True)
41
-
42
- def loop_over_l(n, im_n, l):
43
- row_idx = tf.convert_to_tensor((l // ((input_image_shape[1] - (input_block_shape[1] - 1) * dilations[1] - 1 + strides[1]) // strides[1])) * strides[0])
44
- col_idx = tf.convert_to_tensor((l % ((input_image_shape[1] - (input_block_shape[1] - 1) * dilations[1] - 1 + strides[1]) // strides[1])) * strides[1])
45
-
46
- def loop_over_c(c, im_n):
47
- patch_idx = tf.convert_to_tensor(c * input_block_shape[0] * input_block_shape[1])
48
- patch = tf.reshape(input_tensor[n, patch_idx:patch_idx + input_block_shape[0] * input_block_shape[1], l], input_block_shape)
49
- if dilations[0] > 1 or dilations[1] > 1:
50
- dilated_patch = tf.zeros([(input_block_shape[0] - 1) * dilations[0] + 1, (input_block_shape[1] - 1) * dilations[1] + 1], dtype=patch.dtype)
51
- for i in tf.range(input_block_shape[0]):
52
- for j in tf.range(input_block_shape[1]):
53
- dilated_patch = tf.tensor_scatter_nd_update(dilated_patch, [[i * dilations[0], j * dilations[1]]], [patch[i, j]])
54
- patch = dilated_patch
55
- patch_shape = tf.shape(patch)
56
- indices = tf.reshape(tf.stack(tf.meshgrid(row_idx + tf.range(patch_shape[0]), col_idx + tf.range(patch_shape[1]), c, indexing='ij'), axis=-1), [-1, 3])
57
- updates = tf.reshape(patch, [-1])
58
- return tf.tensor_scatter_nd_add(im_n, indices, updates)
59
- return tf.reduce_sum(tf.map_fn(lambda c: loop_over_c(c, im_n), tf.range(C), dtype=im_n.dtype), axis=0)
60
-
61
- def loop_over_n(n):
62
- im_n = tf.zeros(output_shape[1:], dtype=input_tensor.dtype)
63
- return tf.reduce_sum(tf.map_fn(lambda l: loop_over_l(n, im_n, l), tf.range(L), dtype=im_n.dtype), axis=0)
64
-
65
- im = tf.map_fn(loop_over_n, tf.range(N), dtype=input_tensor.dtype)
66
-
67
- return im[:, pads[0]:input_image_shape[0]-pads[2], pads[1]:input_image_shape[1]-pads[3], :]
33
+ ky = tf.reshape(tf.repeat(tf.range(k_h), k_w), tf.stack([k_h, k_w]))
34
+ kx = tf.reshape(tf.tile(tf.range(k_w), [k_h]), tf.stack([k_h, k_w]))
35
+
36
+ positions = ky * dilation_h * eff_k_w + kx * dilation_w
37
+ positions = tf.reshape(positions, [-1])
38
+ one_hot = tf.one_hot(positions, depth=eff_k_h * eff_k_w, dtype=dtype)
39
+ kernel = tf.reshape(one_hot, tf.stack([k_h * k_w, eff_k_h, eff_k_w]))
40
+ kernel = tf.transpose(kernel, [1, 2, 0])
41
+ kernel = tf.expand_dims(kernel, axis=2)
42
+ return kernel, eff_k_h, eff_k_w
68
43
 
69
44
 
70
45
  @print_node_info
@@ -114,10 +89,9 @@ def make_node(
114
89
  input_block_shape = tf_layers_dict[graph_node_input_3.name]['tf_node'] \
115
90
  if isinstance(graph_node_input_3, gs.Variable) else graph_node_input_3
116
91
 
117
- spatial_size = len(input_image_shape)
118
- dilations = graph_node.attrs.get('dilations', [1] * spatial_size)
119
- pads = graph_node.attrs.get('pads', [0, 0] * spatial_size)
120
- strides = graph_node.attrs.get('strides', [1] * spatial_size)
92
+ dilations = graph_node.attrs.get('dilations', [1, 1])
93
+ pads = graph_node.attrs.get('pads', [0, 0, 0, 0])
94
+ strides = graph_node.attrs.get('strides', [1, 1])
121
95
 
122
96
  # Preserving Graph Structure (Dict)
123
97
  tf_layers_dict[graph_node_output.name] = {
@@ -142,17 +116,87 @@ def make_node(
142
116
  tf_layers_dict[graph_node_output.name].pop('nhwc')
143
117
 
144
118
  # Generation of TF OP
145
- col2im = Col2ImLayer()
146
- tf_layers_dict[graph_node_output.name]['tf_node'] = \
147
- col2im(
148
- input_tensor=input_tensor,
149
- input_block_shape=input_block_shape,
150
- strides=strides,
151
- input_image_shape=input_image_shape,
152
- pads=pads,
153
- dilations=dilations,
154
- output_shape=shape,
155
- )
119
+ original_dtype = input_tensor.dtype
120
+ compute_dtype = original_dtype
121
+ if original_dtype not in (tf.float16, tf.float32, tf.float64, tf.bfloat16):
122
+ if original_dtype in (tf.complex64, tf.complex128):
123
+ error('Col2Im does not support complex types in non-Flex implementation.')
124
+ sys.exit(1)
125
+ compute_dtype = tf.float32
126
+ input_tensor = tf.cast(input_tensor, compute_dtype)
127
+
128
+ input_image_shape = tf.cast(input_image_shape, tf.int32)
129
+ input_block_shape = tf.cast(input_block_shape, tf.int32)
130
+
131
+ if input_image_shape.shape is not None \
132
+ and input_image_shape.shape.rank is not None \
133
+ and input_image_shape.shape.rank != 1:
134
+ error('Col2Im supports only 2D image_shape input.')
135
+ sys.exit(1)
136
+
137
+ if input_block_shape.shape is not None \
138
+ and input_block_shape.shape.rank is not None \
139
+ and input_block_shape.shape.rank != 1:
140
+ error('Col2Im supports only 2D block_shape input.')
141
+ sys.exit(1)
142
+
143
+ k_h = input_block_shape[0]
144
+ k_w = input_block_shape[1]
145
+ h_img = input_image_shape[0]
146
+ w_img = input_image_shape[1]
147
+
148
+ stride_h, stride_w = strides
149
+ dilation_h, dilation_w = dilations
150
+ pad_top, pad_left, pad_bottom, pad_right = pads
151
+
152
+ kernel, eff_k_h, eff_k_w = _build_col2im_kernel(
153
+ k_h=k_h,
154
+ k_w=k_w,
155
+ dilation_h=dilation_h,
156
+ dilation_w=dilation_w,
157
+ dtype=compute_dtype,
158
+ )
159
+
160
+ h_pad = h_img + pad_top + pad_bottom
161
+ w_pad = w_img + pad_left + pad_right
162
+
163
+ out_h = tf.math.floordiv(h_pad - eff_k_h, stride_h) + 1
164
+ out_w = tf.math.floordiv(w_pad - eff_k_w, stride_w) + 1
165
+
166
+ input_shape = tf.shape(input_tensor)
167
+ n = input_shape[0]
168
+ ck = input_shape[1]
169
+ c = tf.math.floordiv(ck, k_h * k_w)
170
+
171
+ cols = tf.reshape(
172
+ input_tensor,
173
+ tf.stack([n, c, k_h * k_w, out_h, out_w]),
174
+ )
175
+ cols = tf.transpose(cols, [0, 1, 3, 4, 2])
176
+ cols = tf.reshape(cols, tf.stack([n * c, out_h, out_w, k_h * k_w]))
177
+
178
+ output_shape = tf.stack([n * c, h_pad, w_pad, 1])
179
+ output = tf.nn.conv2d_transpose(
180
+ cols,
181
+ kernel,
182
+ output_shape=output_shape,
183
+ strides=[1, stride_h, stride_w, 1],
184
+ padding='VALID',
185
+ )
186
+
187
+ output = tf.reshape(output, tf.stack([n, c, h_pad, w_pad]))
188
+ output = tf.transpose(output, [0, 2, 3, 1])
189
+
190
+ output = tf.slice(
191
+ output,
192
+ tf.stack([0, pad_top, pad_left, 0]),
193
+ tf.stack([-1, h_img, w_img, -1]),
194
+ )
195
+
196
+ if output.dtype != original_dtype:
197
+ output = tf.cast(output, original_dtype)
198
+
199
+ tf_layers_dict[graph_node_output.name]['tf_node'] = output
156
200
 
157
201
  # Post-process transpose
158
202
  before_trans_shape = tf_layers_dict[graph_node_output.name]['tf_node'].shape
onnx2tf/ops/DFT.py ADDED
@@ -0,0 +1,245 @@
1
+ import sys
2
+ import random
3
+ random.seed(0)
4
+ import numpy as np
5
+ np.random.seed(0)
6
+ import tensorflow as tf
7
+ import onnx_graphsurgeon as gs
8
+ from onnx2tf.utils.common_functions import (
9
+ get_constant_or_variable,
10
+ print_node_info,
11
+ inverted_operation_enable_disable,
12
+ make_tf_node_info,
13
+ get_replacement_parameter,
14
+ pre_process_transpose,
15
+ post_process_transpose,
16
+ )
17
+ from onnx2tf.utils.logging import *
18
+
19
+
20
+ def _normalize_axis(axis, rank):
21
+ axis = tf.cast(axis, tf.int32)
22
+ rank = tf.cast(rank, tf.int32)
23
+ return tf.where(axis < 0, axis + rank, axis)
24
+
25
+
26
+ def _move_axis_to_last(x, axis):
27
+ rank = tf.rank(x)
28
+ axis = _normalize_axis(axis, rank)
29
+ range0 = tf.range(axis)
30
+ range1 = tf.range(axis + 1, rank)
31
+ perm = tf.concat([range0, range1, [axis]], axis=0)
32
+ x_t = tf.transpose(x, perm)
33
+ inv_perm = tf.argsort(perm)
34
+ return x_t, inv_perm
35
+
36
+
37
+ def _pad_or_slice_last(x, length):
38
+ length = tf.cast(length, tf.int32)
39
+ current = tf.shape(x)[-1]
40
+
41
+ def _pad():
42
+ pad_amount = length - current
43
+ pad = tf.concat(
44
+ [
45
+ tf.zeros([tf.rank(x) - 1, 2], dtype=tf.int32),
46
+ tf.stack([[0, pad_amount]]),
47
+ ],
48
+ axis=0,
49
+ )
50
+ return tf.pad(x, pad)
51
+
52
+ def _slice():
53
+ return x[..., :length]
54
+
55
+ x = tf.cond(current < length, _pad, lambda: x)
56
+ x = tf.cond(current > length, _slice, lambda: x)
57
+ return x
58
+
59
+
60
+ @print_node_info
61
+ @inverted_operation_enable_disable
62
+ @get_replacement_parameter
63
+ def make_node(
64
+ *,
65
+ graph_node: gs.Node,
66
+ tf_layers_dict: dict,
67
+ **kwargs: dict,
68
+ ):
69
+ """DFT
70
+
71
+ Parameters
72
+ ----------
73
+ graph_node: gs.Node
74
+ graph_surgeon Node
75
+
76
+ tf_layers_dict: dict
77
+ optype, shape, dtype, tensorflow graph
78
+ """
79
+ before_op_output_shape_trans_1 = \
80
+ tf_layers_dict.get(graph_node.inputs[0].name, {}).get('before_op_output_shape_trans', True)
81
+
82
+ graph_node_input_1 = get_constant_or_variable(
83
+ graph_node.inputs[0],
84
+ before_op_output_shape_trans_1,
85
+ )
86
+ graph_node_input_2 = get_constant_or_variable(
87
+ graph_node.inputs[1],
88
+ before_op_output_shape_trans=False,
89
+ ) if len(graph_node.inputs) >= 2 else None
90
+ graph_node_input_3 = get_constant_or_variable(
91
+ graph_node.inputs[2],
92
+ before_op_output_shape_trans=False,
93
+ ) if len(graph_node.inputs) >= 3 else None
94
+
95
+ graph_node_output: gs.Variable = graph_node.outputs[0]
96
+ shape = graph_node_output.shape
97
+ dtype = graph_node_output.dtype
98
+
99
+ input_tensor = tf_layers_dict[graph_node_input_1.name]['tf_node'] \
100
+ if isinstance(graph_node_input_1, gs.Variable) else graph_node_input_1
101
+ dft_length = tf_layers_dict[graph_node_input_2.name]['tf_node'] \
102
+ if isinstance(graph_node_input_2, gs.Variable) else graph_node_input_2
103
+ axis = tf_layers_dict[graph_node_input_3.name]['tf_node'] \
104
+ if isinstance(graph_node_input_3, gs.Variable) else graph_node_input_3
105
+
106
+ onesided = bool(graph_node.attrs.get('onesided', 0))
107
+ inverse = bool(graph_node.attrs.get('inverse', 0))
108
+
109
+ # Preserving Graph Structure (Dict)
110
+ tf_layers_dict[graph_node_output.name] = {
111
+ 'optype': graph_node.op,
112
+ 'shape': shape,
113
+ 'dtype': dtype,
114
+ 'nhwc': tf_layers_dict[graph_node_input_1.name]['nhwc'] \
115
+ if isinstance(graph_node_input_1, gs.Variable) \
116
+ and 'nhwc' in tf_layers_dict[graph_node_input_1.name].keys() else False,
117
+ }
118
+
119
+ # Pre-process transpose
120
+ input_tensor = pre_process_transpose(
121
+ value_before_transpose=input_tensor,
122
+ param_target='inputs',
123
+ param_name=graph_node.inputs[0].name,
124
+ **kwargs,
125
+ )
126
+
127
+ input_rank = tf.rank(input_tensor)
128
+ axis_attr = graph_node.attrs.get('axis', None)
129
+ if axis is None:
130
+ if axis_attr is not None:
131
+ axis = tf.constant(axis_attr, dtype=tf.int32)
132
+ else:
133
+ axis = tf.cast(input_rank - 2, tf.int32)
134
+ else:
135
+ axis = tf.cast(tf.reshape(axis, []), tf.int32)
136
+ axis = _normalize_axis(axis, input_rank)
137
+
138
+ dft_length_value = None
139
+ if dft_length is not None:
140
+ dft_length_value = tf.cast(tf.reshape(dft_length, []), tf.int32)
141
+
142
+ input_dtype = input_tensor.dtype
143
+ if input_dtype in (tf.float64,):
144
+ float_dtype = tf.float64
145
+ complex_dtype = tf.complex128
146
+ elif input_dtype in (tf.float32,):
147
+ float_dtype = tf.float32
148
+ complex_dtype = tf.complex64
149
+ elif input_dtype in (tf.float16, tf.bfloat16):
150
+ float_dtype = tf.float32
151
+ complex_dtype = tf.complex64
152
+ else:
153
+ error('DFT supports float/bfloat16 types only.')
154
+ sys.exit(1)
155
+
156
+ # Convert to complex tensor (drop last dim)
157
+ last_dim_static = input_tensor.shape[-1]
158
+ if last_dim_static is not None:
159
+ if last_dim_static == 1:
160
+ real = tf.squeeze(input_tensor, axis=-1)
161
+ imag = tf.zeros_like(real)
162
+ elif last_dim_static == 2:
163
+ real, imag = tf.unstack(input_tensor, axis=-1)
164
+ else:
165
+ error('DFT input last dimension must be 1 or 2.')
166
+ sys.exit(1)
167
+ else:
168
+ last_dim = tf.shape(input_tensor)[-1]
169
+ def _real_case():
170
+ real = tf.squeeze(input_tensor, axis=-1)
171
+ imag = tf.zeros_like(real)
172
+ return real, imag
173
+ def _complex_case():
174
+ real, imag = tf.unstack(input_tensor, axis=-1)
175
+ return real, imag
176
+ real, imag = tf.cond(
177
+ tf.equal(last_dim, 1),
178
+ _real_case,
179
+ _complex_case,
180
+ )
181
+
182
+ real = tf.cast(real, float_dtype)
183
+ imag = tf.cast(imag, float_dtype)
184
+ signal = tf.complex(real, imag)
185
+
186
+ signal_t, inv_perm = _move_axis_to_last(signal, axis)
187
+ signal_len = tf.shape(signal_t)[-1]
188
+
189
+ if onesided and inverse:
190
+ if last_dim_static == 1:
191
+ error('DFT onesided inverse supports only complex input.')
192
+ sys.exit(1)
193
+ if dft_length_value is None:
194
+ dft_length_value = tf.cast(signal_len * 2 - 2, tf.int32)
195
+ out_real = tf.signal.irfft(signal_t, fft_length=[dft_length_value])
196
+ out_real = tf.transpose(out_real, inv_perm)
197
+ output = tf.expand_dims(out_real, axis=-1)
198
+ elif onesided and not inverse:
199
+ if last_dim_static == 2:
200
+ error('DFT onesided forward supports only real input.')
201
+ sys.exit(1)
202
+ if dft_length_value is None:
203
+ dft_length_value = tf.cast(signal_len, tf.int32)
204
+ real_signal = tf.math.real(signal_t)
205
+ out_complex = tf.signal.rfft(real_signal, fft_length=[dft_length_value])
206
+ out_complex = tf.transpose(out_complex, inv_perm)
207
+ output = tf.stack([tf.math.real(out_complex), tf.math.imag(out_complex)], axis=-1)
208
+ else:
209
+ if dft_length_value is not None:
210
+ signal_t = _pad_or_slice_last(signal_t, dft_length_value)
211
+ if inverse:
212
+ out_complex = tf.signal.ifft(signal_t)
213
+ else:
214
+ out_complex = tf.signal.fft(signal_t)
215
+ out_complex = tf.transpose(out_complex, inv_perm)
216
+ output = tf.stack([tf.math.real(out_complex), tf.math.imag(out_complex)], axis=-1)
217
+
218
+ if output.dtype != input_dtype:
219
+ output = tf.cast(output, input_dtype)
220
+
221
+ # Post-process transpose
222
+ tf_layers_dict[graph_node_output.name]['tf_node'] = post_process_transpose(
223
+ value_before_transpose=output,
224
+ param_target='outputs',
225
+ param_name=graph_node.outputs[0].name,
226
+ **kwargs,
227
+ )
228
+
229
+ # Generation of Debug Info
230
+ tf_layers_dict[graph_node_output.name]['tf_node_info'] = \
231
+ make_tf_node_info(
232
+ node_info={
233
+ 'tf_op_type': 'DFT',
234
+ 'tf_inputs': {
235
+ 'input': input_tensor,
236
+ 'axis': axis,
237
+ 'dft_length': dft_length_value,
238
+ 'onesided': onesided,
239
+ 'inverse': inverse,
240
+ },
241
+ 'tf_outputs': {
242
+ 'output': tf_layers_dict[graph_node_output.name]['tf_node'],
243
+ },
244
+ }
245
+ )
@@ -0,0 +1,399 @@
1
+ import sys
2
+ import random
3
+ random.seed(0)
4
+ import numpy as np
5
+ np.random.seed(0)
6
+ import tensorflow as tf
7
+ import onnx_graphsurgeon as gs
8
+ from onnx2tf.utils.common_functions import (
9
+ get_constant_or_variable,
10
+ get_weights_constant_or_variable,
11
+ print_node_info,
12
+ inverted_operation_enable_disable,
13
+ make_tf_node_info,
14
+ get_replacement_parameter,
15
+ pre_process_transpose,
16
+ post_process_transpose,
17
+ transpose_with_flexing_deterrence,
18
+ )
19
+ from onnx2tf.utils.logging import *
20
+
21
+ INF_INDEX_VALUE: int = 4294967296
22
+
23
+
24
+ def _to_int_tensor(value, name=None):
25
+ if isinstance(value, tf.Tensor):
26
+ return tf.cast(value, tf.int32)
27
+ return tf.constant(value, dtype=tf.int32, name=name)
28
+
29
+
30
+ def _bilinear_sample_2d(
31
+ image,
32
+ coords,
33
+ ):
34
+ """
35
+ image: [N, H, W, C]
36
+ coords: [N, oH, oW, kH, kW, 2] in absolute coords (y, x)
37
+ """
38
+ coord_dtype = coords.dtype
39
+ h = tf.shape(image)[1]
40
+ w = tf.shape(image)[2]
41
+ h_f = tf.cast(h, coord_dtype)
42
+ w_f = tf.cast(w, coord_dtype)
43
+ max_y = h_f - 1.0
44
+ max_x = w_f - 1.0
45
+
46
+ y, x = tf.split(coords, num_or_size_splits=2, axis=-1)
47
+
48
+ y0 = tf.floor(y)
49
+ x0 = tf.floor(x)
50
+ y1 = y0 + 1.0
51
+ x1 = x0 + 1.0
52
+
53
+ dy = y - y0
54
+ dx = x - x0
55
+
56
+ w00 = (1.0 - dy) * (1.0 - dx)
57
+ w10 = dy * (1.0 - dx)
58
+ w11 = dy * dx
59
+ w01 = (1.0 - dy) * dx
60
+
61
+ def _in_bounds(y_idx, x_idx):
62
+ return tf.logical_and(
63
+ tf.logical_and(y_idx >= 0.0, y_idx <= max_y),
64
+ tf.logical_and(x_idx >= 0.0, x_idx <= max_x),
65
+ )
66
+
67
+ m00 = _in_bounds(y0, x0)
68
+ m10 = _in_bounds(y1, x0)
69
+ m11 = _in_bounds(y1, x1)
70
+ m01 = _in_bounds(y0, x1)
71
+
72
+ y0c = tf.clip_by_value(y0, 0.0, max_y)
73
+ x0c = tf.clip_by_value(x0, 0.0, max_x)
74
+ y1c = tf.clip_by_value(y1, 0.0, max_y)
75
+ x1c = tf.clip_by_value(x1, 0.0, max_x)
76
+
77
+ y0i = tf.cast(y0c, tf.int32)
78
+ x0i = tf.cast(x0c, tf.int32)
79
+ y1i = tf.cast(y1c, tf.int32)
80
+ x1i = tf.cast(x1c, tf.int32)
81
+
82
+ input_flat = tf.reshape(image, tf.stack([tf.shape(image)[0], h * w, tf.shape(image)[3]]))
83
+
84
+ def _gather(y_idx, x_idx):
85
+ linear = y_idx * w + x_idx
86
+ linear = tf.squeeze(linear, axis=-1)
87
+ return tf.gather(input_flat, linear, batch_dims=1)
88
+
89
+ v00 = _gather(y0i, x0i)
90
+ v10 = _gather(y1i, x0i)
91
+ v11 = _gather(y1i, x1i)
92
+ v01 = _gather(y0i, x1i)
93
+
94
+ m00 = tf.cast(m00, image.dtype)
95
+ m10 = tf.cast(m10, image.dtype)
96
+ m11 = tf.cast(m11, image.dtype)
97
+ m01 = tf.cast(m01, image.dtype)
98
+
99
+ output = w00 * m00 * v00 + w10 * m10 * v10 + w11 * m11 * v11 + w01 * m01 * v01
100
+ return output
101
+
102
+
103
+ @print_node_info
104
+ @inverted_operation_enable_disable
105
+ @get_replacement_parameter
106
+ def make_node(
107
+ *,
108
+ graph_node: gs.Node,
109
+ tf_layers_dict: dict,
110
+ **kwargs: dict,
111
+ ):
112
+ """DeformConv
113
+
114
+ Parameters
115
+ ----------
116
+ graph_node: gs.Node
117
+ graph_surgeon Node
118
+
119
+ tf_layers_dict: dict
120
+ optype, shape, dtype, tensorflow graph
121
+ """
122
+ before_op_output_shape_trans_1 = \
123
+ tf_layers_dict.get(graph_node.inputs[0].name, {}).get('before_op_output_shape_trans', True)
124
+ before_op_output_shape_trans_3 = \
125
+ tf_layers_dict.get(graph_node.inputs[2].name, {}).get('before_op_output_shape_trans', True)
126
+ before_op_output_shape_trans_4 = \
127
+ tf_layers_dict.get(graph_node.inputs[3].name, {}).get('before_op_output_shape_trans', True) \
128
+ if len(graph_node.inputs) >= 4 else True
129
+ before_op_output_shape_trans_5 = \
130
+ tf_layers_dict.get(graph_node.inputs[4].name, {}).get('before_op_output_shape_trans', True) \
131
+ if len(graph_node.inputs) >= 5 else True
132
+
133
+ graph_node_input_1 = get_constant_or_variable(
134
+ graph_node.inputs[0],
135
+ before_op_output_shape_trans_1,
136
+ )
137
+
138
+ kernel_shape = graph_node.attrs.get('kernel_shape', [])
139
+ if kernel_shape == [] and graph_node.inputs[1].shape is not None:
140
+ kernel_shape = graph_node.inputs[1].shape[2:]
141
+ kernel_size = len(kernel_shape) if kernel_shape != [] else 2
142
+
143
+ graph_node_input_2 = get_weights_constant_or_variable(
144
+ const_or_var=graph_node.inputs[1],
145
+ kernel_size=kernel_size,
146
+ )
147
+ graph_node_input_3 = get_constant_or_variable(
148
+ graph_node.inputs[2],
149
+ before_op_output_shape_trans_3,
150
+ )
151
+ graph_node_input_4 = get_constant_or_variable(
152
+ graph_node.inputs[3],
153
+ before_op_output_shape_trans_4,
154
+ ) if len(graph_node.inputs) >= 4 else None
155
+ graph_node_input_5 = get_constant_or_variable(
156
+ graph_node.inputs[4],
157
+ before_op_output_shape_trans_5,
158
+ ) if len(graph_node.inputs) >= 5 else None
159
+
160
+ graph_node_output: gs.Variable = graph_node.outputs[0]
161
+ output_tensor_shape = graph_node_output.shape
162
+ dtype = graph_node_output.dtype
163
+
164
+ input_tensor = tf_layers_dict[graph_node_input_1.name]['tf_node'] \
165
+ if isinstance(graph_node_input_1, gs.Variable) else graph_node_input_1
166
+ weights = tf_layers_dict[graph_node_input_2.name]['tf_node'] \
167
+ if isinstance(graph_node_input_2, gs.Variable) else graph_node_input_2
168
+ offset = tf_layers_dict[graph_node_input_3.name]['tf_node'] \
169
+ if isinstance(graph_node_input_3, gs.Variable) else graph_node_input_3
170
+ bias = tf_layers_dict[graph_node_input_4.name]['tf_node'] \
171
+ if isinstance(graph_node_input_4, gs.Variable) else graph_node_input_4
172
+ mask = tf_layers_dict[graph_node_input_5.name]['tf_node'] \
173
+ if isinstance(graph_node_input_5, gs.Variable) else graph_node_input_5
174
+
175
+ input_tensor_shape = input_tensor.shape
176
+
177
+ if input_tensor_shape is not None and len(input_tensor_shape) != 4:
178
+ error('DeformConv currently supports only 2D inputs (N, C, H, W).')
179
+ sys.exit(1)
180
+
181
+ # Preserving Graph Structure (Dict)
182
+ tf_layers_dict[graph_node_output.name] = {
183
+ 'optype': graph_node.op,
184
+ 'shape': output_tensor_shape,
185
+ 'dtype': dtype,
186
+ 'nhwc': True,
187
+ }
188
+
189
+ # Pre-process transpose
190
+ input_tensor = pre_process_transpose(
191
+ value_before_transpose=input_tensor,
192
+ param_target='inputs',
193
+ param_name=graph_node.inputs[0].name,
194
+ **kwargs,
195
+ )
196
+ offset = pre_process_transpose(
197
+ value_before_transpose=offset,
198
+ param_target='inputs',
199
+ param_name=graph_node.inputs[2].name,
200
+ **kwargs,
201
+ )
202
+ if mask is not None:
203
+ mask = pre_process_transpose(
204
+ value_before_transpose=mask,
205
+ param_target='inputs',
206
+ param_name=graph_node.inputs[4].name,
207
+ **kwargs,
208
+ )
209
+
210
+ input_dtype = input_tensor.dtype
211
+ if weights is not None and weights.dtype != input_dtype:
212
+ weights = tf.cast(weights, input_dtype)
213
+ if offset is not None and offset.dtype != input_dtype:
214
+ offset = tf.cast(offset, input_dtype)
215
+ if bias is not None and bias.dtype != input_dtype:
216
+ bias = tf.cast(bias, input_dtype)
217
+ if mask is not None and mask.dtype != input_dtype:
218
+ mask = tf.cast(mask, input_dtype)
219
+
220
+ # Workaround to avoid as many conversion failures as possible
221
+ onnx_input_shape = [
222
+ dim if isinstance(dim, int) else None for dim in graph_node.inputs[0].shape
223
+ ] if graph_node.inputs[0].shape is not None else None
224
+ tf_input_shape = [
225
+ dim if isinstance(dim, int) else None for dim in input_tensor.shape
226
+ ]
227
+ if onnx_input_shape is not None \
228
+ and len(onnx_input_shape) > 1 and len(tf_input_shape) > 1 \
229
+ and onnx_input_shape == tf_input_shape:
230
+
231
+ shape_for_judging_skip = [
232
+ dim if dim is not None else INF_INDEX_VALUE for dim in onnx_input_shape[1:]
233
+ ]
234
+ if shape_for_judging_skip.count(shape_for_judging_skip[0]) != len(shape_for_judging_skip):
235
+ input_tensor = transpose_with_flexing_deterrence(
236
+ input_tensor=input_tensor,
237
+ perm=[0,2,3,1],
238
+ **kwargs,
239
+ )
240
+ offset = transpose_with_flexing_deterrence(
241
+ input_tensor=offset,
242
+ perm=[0,2,3,1],
243
+ **kwargs,
244
+ )
245
+ if mask is not None:
246
+ mask = transpose_with_flexing_deterrence(
247
+ input_tensor=mask,
248
+ perm=[0,2,3,1],
249
+ **kwargs,
250
+ )
251
+
252
+ # Attributes
253
+ dilations = graph_node.attrs.get('dilations', [1, 1])
254
+ group = graph_node.attrs.get('group', 1)
255
+ offset_group = graph_node.attrs.get('offset_group', 1)
256
+ pads = graph_node.attrs.get('pads', [0, 0, 0, 0])
257
+ strides = graph_node.attrs.get('strides', [1, 1])
258
+
259
+ dilation_h, dilation_w = dilations
260
+ stride_h, stride_w = strides
261
+ pad_top, pad_left, pad_bottom, pad_right = pads
262
+
263
+ # Input prep
264
+ if pad_top != 0 or pad_bottom != 0 or pad_left != 0 or pad_right != 0:
265
+ input_tensor = tf.pad(
266
+ input_tensor,
267
+ paddings=[[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]],
268
+ )
269
+
270
+ batch = tf.shape(input_tensor)[0]
271
+ in_h = tf.shape(input_tensor)[1]
272
+ in_w = tf.shape(input_tensor)[2]
273
+ in_c = tf.shape(input_tensor)[3]
274
+
275
+ offset_shape = tf.shape(offset)
276
+ out_h = offset_shape[1]
277
+ out_w = offset_shape[2]
278
+
279
+ # Kernel shape
280
+ if kernel_shape != []:
281
+ kh = _to_int_tensor(kernel_shape[0])
282
+ kw = _to_int_tensor(kernel_shape[1])
283
+ else:
284
+ kh = _to_int_tensor(tf.shape(weights)[0])
285
+ kw = _to_int_tensor(tf.shape(weights)[1])
286
+
287
+ # Base grid: [oH, oW, kH, kW, 2]
288
+ oy = tf.range(out_h, dtype=input_dtype) * tf.cast(stride_h, input_dtype)
289
+ ox = tf.range(out_w, dtype=input_dtype) * tf.cast(stride_w, input_dtype)
290
+ ky = tf.range(kh, dtype=input_dtype) * tf.cast(dilation_h, input_dtype)
291
+ kx = tf.range(kw, dtype=input_dtype) * tf.cast(dilation_w, input_dtype)
292
+
293
+ oy = tf.reshape(oy, tf.stack([out_h, 1, 1, 1]))
294
+ ox = tf.reshape(ox, tf.stack([1, out_w, 1, 1]))
295
+ ky = tf.reshape(ky, tf.stack([1, 1, kh, 1]))
296
+ kx = tf.reshape(kx, tf.stack([1, 1, 1, kw]))
297
+
298
+ y = oy + ky
299
+ x = ox + kx
300
+ target_shape = tf.stack([out_h, out_w, kh, kw])
301
+ y = tf.broadcast_to(y, target_shape)
302
+ x = tf.broadcast_to(x, target_shape)
303
+ base_grid = tf.stack([y, x], axis=-1)
304
+
305
+ # Offset reshape: [N, oH, oW, Goff, kH, kW, 2]
306
+ offset = tf.reshape(
307
+ offset,
308
+ tf.stack([batch, out_h, out_w, offset_group, kh, kw, 2]),
309
+ )
310
+
311
+ coords = base_grid[None, :, :, None, :, :, :] + offset
312
+ coords = tf.transpose(coords, [0, 3, 1, 2, 4, 5, 6])
313
+ coords = tf.reshape(coords, tf.stack([batch * offset_group, out_h, out_w, kh, kw, 2]))
314
+
315
+ # Input grouping for offset_group
316
+ c_per_offset = tf.math.floordiv(in_c, offset_group)
317
+ input_tensor = tf.reshape(
318
+ input_tensor,
319
+ tf.stack([batch, in_h, in_w, offset_group, c_per_offset]),
320
+ )
321
+ input_tensor = tf.transpose(input_tensor, [0, 3, 1, 2, 4])
322
+ input_tensor = tf.reshape(
323
+ input_tensor,
324
+ tf.stack([batch * offset_group, in_h, in_w, c_per_offset]),
325
+ )
326
+
327
+ sampled = _bilinear_sample_2d(input_tensor, coords)
328
+ sampled = tf.reshape(
329
+ sampled,
330
+ tf.stack([batch, offset_group, out_h, out_w, kh, kw, c_per_offset]),
331
+ )
332
+ sampled = tf.transpose(sampled, [0, 2, 3, 1, 4, 5, 6])
333
+
334
+ if mask is not None:
335
+ mask = tf.reshape(
336
+ mask,
337
+ tf.stack([batch, out_h, out_w, offset_group, kh, kw, 1]),
338
+ )
339
+ sampled = sampled * tf.cast(mask, sampled.dtype)
340
+
341
+ # Merge offset_group back to channel dim: [N, oH, oW, kH, kW, C]
342
+ sampled = tf.reshape(
343
+ sampled,
344
+ tf.stack([batch, out_h, out_w, kh, kw, in_c]),
345
+ )
346
+
347
+ # Grouped convolution via batched matmul
348
+ out_c = tf.shape(weights)[3]
349
+ c_per_group = tf.math.floordiv(in_c, group)
350
+ out_c_per_group = tf.math.floordiv(out_c, group)
351
+
352
+ cols = tf.reshape(sampled, tf.stack([batch * out_h * out_w, kh * kw * in_c]))
353
+ cols = tf.reshape(cols, tf.stack([batch * out_h * out_w, group, kh * kw * c_per_group]))
354
+ cols = tf.transpose(cols, [1, 0, 2])
355
+
356
+ weights = tf.reshape(weights, tf.stack([kh, kw, c_per_group, group, out_c_per_group]))
357
+ weights = tf.transpose(weights, [3, 0, 1, 2, 4])
358
+ weights = tf.reshape(weights, tf.stack([group, kh * kw * c_per_group, out_c_per_group]))
359
+
360
+ output = tf.matmul(cols, weights)
361
+ output = tf.transpose(output, [1, 0, 2])
362
+ output = tf.reshape(output, tf.stack([batch, out_h, out_w, out_c]))
363
+
364
+ if bias is not None:
365
+ output += tf.reshape(bias, tf.stack([1, 1, 1, out_c]))
366
+
367
+ if output.dtype != input_dtype:
368
+ output = tf.cast(output, input_dtype)
369
+
370
+ # Post-process transpose
371
+ tf_layers_dict[graph_node_output.name]['tf_node'] = post_process_transpose(
372
+ value_before_transpose=output,
373
+ param_target='outputs',
374
+ param_name=graph_node.outputs[0].name,
375
+ **kwargs,
376
+ )
377
+
378
+ # Generation of Debug Info
379
+ tf_layers_dict[graph_node_output.name]['tf_node_info'] = \
380
+ make_tf_node_info(
381
+ node_info={
382
+ 'tf_op_type': 'DeformConv',
383
+ 'tf_inputs': {
384
+ 'input_tensor': input_tensor,
385
+ 'weights': weights,
386
+ 'offset': offset,
387
+ 'bias': bias,
388
+ 'mask': mask,
389
+ 'strides': strides,
390
+ 'dilations': dilations,
391
+ 'pads': pads,
392
+ 'group': group,
393
+ 'offset_group': offset_group,
394
+ },
395
+ 'tf_outputs': {
396
+ 'output': tf_layers_dict[graph_node_output.name]['tf_node'],
397
+ },
398
+ }
399
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onnx2tf
3
- Version: 1.29.18
3
+ Version: 1.29.19
4
4
  Summary: Self-Created Tools to convert ONNX files (NCHW) to TensorFlow/TFLite/Keras format (NHWC). The purpose of this tool is to solve the massive Transpose extrapolation problem in onnx-tensorflow (onnx-tf).
5
5
  Keywords: onnx,tensorflow,tflite,keras,deep-learning,machine-learning
6
6
  Author: Katsuya Hyodo
@@ -137,11 +137,11 @@ https://github.com/PINTO0309/onnx2tf/wiki/model_status
137
137
  |Cos|:heavy_check_mark:|
138
138
  |CumProd|:heavy_check_mark:|
139
139
  |CumSum|:heavy_check_mark:|
140
- |DeformConv|**Help wanted**|
140
+ |DeformConv|:white_check_mark:|
141
141
  |DepthToSpace|:heavy_check_mark:|
142
142
  |Det|:heavy_check_mark:|
143
143
  |DequantizeLinear|:heavy_check_mark:|
144
- |DFT|**Help wanted**|
144
+ |DFT|:white_check_mark:|
145
145
  |Div|:heavy_check_mark:|
146
146
  |Dropout|:heavy_check_mark:|
147
147
  |DynamicQuantizeLinear|:heavy_check_mark:|
@@ -365,7 +365,7 @@ Video speed is adjusted approximately 50 times slower than actual speed.
365
365
  docker run --rm -it \
366
366
  -v `pwd`:/workdir \
367
367
  -w /workdir \
368
- ghcr.io/pinto0309/onnx2tf:1.29.18
368
+ ghcr.io/pinto0309/onnx2tf:1.29.19
369
369
 
370
370
  or
371
371
 
@@ -373,7 +373,7 @@ Video speed is adjusted approximately 50 times slower than actual speed.
373
373
  docker run --rm -it \
374
374
  -v `pwd`:/workdir \
375
375
  -w /workdir \
376
- docker.io/pinto0309/onnx2tf:1.29.18
376
+ docker.io/pinto0309/onnx2tf:1.29.19
377
377
 
378
378
  or
379
379
 
@@ -1,4 +1,4 @@
1
- onnx2tf/__init__.py,sha256=GJI-T9Q6ftbR-PwGyLk5t5_Iv3hvUC3prwy56yvn7vA,67
1
+ onnx2tf/__init__.py,sha256=j0g0sP9V7WMAY5PXs_oOHLBgUSJ1dcjLILPUq39xOnU,67
2
2
  onnx2tf/__main__.py,sha256=2RSCQ7d4lc6CwD-rlGn9UicPFg-P5du7ZD_yh-kuBEU,57
3
3
  onnx2tf/onnx2tf.py,sha256=y8FewjpNYAFnUs0cjq6JzdYkiXQSm1o_sZ3PXLJzK64,161921
4
4
  onnx2tf/ops/Abs.py,sha256=V7btmCG_ZvK_qJovUsguq0ZMJ349mhNQ4FHSgzP_Yuo,4029
@@ -27,7 +27,7 @@ onnx2tf/ops/Cast.py,sha256=M0LRClHPgZ_8NubwME6ipKrAqcY9aKC5ihQXCkTkNkM,4601
27
27
  onnx2tf/ops/Ceil.py,sha256=0-jaueltpQSwpOIDUmy9DdTy98qN-XimYu5cHVPnUIs,3586
28
28
  onnx2tf/ops/Celu.py,sha256=9g7WNKo4G_jMtUXcoOfpNdLYqEsuyXLPkkyQZxDuL4U,3853
29
29
  onnx2tf/ops/Clip.py,sha256=K3Pgt9BXl5_rzg6s-kPFmwElL5COsvolRY1BUTo7UWw,8753
30
- onnx2tf/ops/Col2Im.py,sha256=MDqck00gURrbsroJAgUDkxmdsGyE9v2ez4NKdvdq5IY,7514
30
+ onnx2tf/ops/Col2Im.py,sha256=8n66z3O59VJvJRlcrj93a5TLJ_qh-aSdR_-8SAQIlRo,7658
31
31
  onnx2tf/ops/Compress.py,sha256=NvDGr9gCNl-8YG41xDBfe3UvhRP03K-ktdtY_MoytBc,3667
32
32
  onnx2tf/ops/Concat.py,sha256=kDk7LN01nHuQyYnEPUEikSQ-M17jguAc-qFtCb9tg9I,38537
33
33
  onnx2tf/ops/ConcatFromSequence.py,sha256=z8pNmGQRGq9cxWORW330NZS_0zsmhFudLswMyPn8AXU,3086
@@ -40,6 +40,8 @@ onnx2tf/ops/Cos.py,sha256=0v5ZJZRzrswVEObyxf4f0RvnWMWZA4uCEdoeq_VE31s,3608
40
40
  onnx2tf/ops/Cosh.py,sha256=-L3QkQtiVBJIv1sSxbXtetVIwgI_2T4WC1O4t2aJ8Gc,3585
41
41
  onnx2tf/ops/CumProd.py,sha256=k4hTEQrkwS7vk7pEy2Btvy2y0o70NlWj1MgsNomfOPg,3957
42
42
  onnx2tf/ops/CumSum.py,sha256=SYKmD5r9Cm9gsCkJPNFoHigvvBO1PmRYRrVmn1HE78o,3954
43
+ onnx2tf/ops/DFT.py,sha256=rL_w1z16N9Kkf0TyMbywOawld0qZ_g1QOD9npGYD_zY,8086
44
+ onnx2tf/ops/DeformConv.py,sha256=tlhZDzNYAT093PkBDP4s6-EO-vnSdW_0KZTxtddjajM,13541
43
45
  onnx2tf/ops/DepthToSpace.py,sha256=BiyBZ88dmXQAkZ5Jc-Ddo-5Kn8dRYCnoik_XnOFzqXc,14449
44
46
  onnx2tf/ops/DequantizeLinear.py,sha256=1v43E1hUqO3g7N-PL1fy_cGj4oUgbphh7vXIGhUAyGc,6463
45
47
  onnx2tf/ops/Det.py,sha256=kxuHkpv_KNHkof0uBv2RLtr3G1uA76MFHyCiCYCBXkw,3590
@@ -209,7 +211,7 @@ onnx2tf/utils/enums.py,sha256=7c5TqetqB07VjyHoxJHfLgtqBqk9ZRyUF33fPOJR1IM,1649
209
211
  onnx2tf/utils/iterative_json_optimizer.py,sha256=qqeIxWGxrhcCYk8-ebWnblnOkzDCwi-nseipHzHR_bk,10436
210
212
  onnx2tf/utils/json_auto_generator.py,sha256=OC-SfKtUg7zUxaXTAg6kT0ShzIc3ByjDa3FNp173DtA,60302
211
213
  onnx2tf/utils/logging.py,sha256=yUCmPuJ_XiUItM3sZMcaMO24JErkQy7zZwVTYWAuiKg,1982
212
- onnx2tf-1.29.18.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
213
- onnx2tf-1.29.18.dist-info/entry_points.txt,sha256=GuhvLu7ZlYECumbmoiFlKX0mFPtFi_Ti9L-E5yuQqKs,42
214
- onnx2tf-1.29.18.dist-info/METADATA,sha256=9JTkd8SawqhrnG2GYMLaI8rvpkmiUJMRUdGvEhbGSBE,154306
215
- onnx2tf-1.29.18.dist-info/RECORD,,
214
+ onnx2tf-1.29.19.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
215
+ onnx2tf-1.29.19.dist-info/entry_points.txt,sha256=GuhvLu7ZlYECumbmoiFlKX0mFPtFi_Ti9L-E5yuQqKs,42
216
+ onnx2tf-1.29.19.dist-info/METADATA,sha256=rSyPbOdWaW3QovkZCVvFg5zn_INzTCm8KN_rjZBah0Q,154312
217
+ onnx2tf-1.29.19.dist-info/RECORD,,