onnx2tf 1.29.1__py3-none-any.whl → 1.29.3__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 +1 -1
- onnx2tf/onnx2tf.py +7 -2
- onnx2tf/ops/AveragePool.py +91 -31
- onnx2tf/ops/Conv.py +27 -0
- onnx2tf/utils/json_auto_generator.py +190 -190
- {onnx2tf-1.29.1.dist-info → onnx2tf-1.29.3.dist-info}/METADATA +8 -8
- {onnx2tf-1.29.1.dist-info → onnx2tf-1.29.3.dist-info}/RECORD +11 -11
- {onnx2tf-1.29.1.dist-info → onnx2tf-1.29.3.dist-info}/WHEEL +0 -0
- {onnx2tf-1.29.1.dist-info → onnx2tf-1.29.3.dist-info}/licenses/LICENSE +0 -0
- {onnx2tf-1.29.1.dist-info → onnx2tf-1.29.3.dist-info}/licenses/LICENSE_onnx-tensorflow +0 -0
- {onnx2tf-1.29.1.dist-info → onnx2tf-1.29.3.dist-info}/top_level.txt +0 -0
onnx2tf/__init__.py
CHANGED
onnx2tf/onnx2tf.py
CHANGED
|
@@ -1246,8 +1246,8 @@ def convert(
|
|
|
1246
1246
|
# Attach it to the exception for later use
|
|
1247
1247
|
ex.onnx_op_name = error_onnx_op_name
|
|
1248
1248
|
|
|
1249
|
-
# If no replacement file was provided, try to generate one automatically
|
|
1250
|
-
if not param_replacement_file and input_onnx_file_path:
|
|
1249
|
+
# If no replacement file was provided, optionally try to generate one automatically
|
|
1250
|
+
if not param_replacement_file and input_onnx_file_path and auto_generate_json_on_error:
|
|
1251
1251
|
info('')
|
|
1252
1252
|
info(Color.REVERSE(f'Attempting automatic JSON generation due to conversion error'), '=' * 30)
|
|
1253
1253
|
if error_onnx_op_name:
|
|
@@ -1313,6 +1313,11 @@ def convert(
|
|
|
1313
1313
|
warn(
|
|
1314
1314
|
f'Conversion failed and automatic JSON generation could not find a solution after {attempt} attempts.'
|
|
1315
1315
|
)
|
|
1316
|
+
elif not param_replacement_file and input_onnx_file_path and not auto_generate_json_on_error:
|
|
1317
|
+
warn(
|
|
1318
|
+
'Conversion failed. Automatic JSON generation on error is disabled by default.\n' +
|
|
1319
|
+
'Re-run with --auto_generate_json_on_error or provide a parameter replacement JSON file.'
|
|
1320
|
+
)
|
|
1316
1321
|
# Re-raise the original error
|
|
1317
1322
|
raise ex
|
|
1318
1323
|
|
onnx2tf/ops/AveragePool.py
CHANGED
|
@@ -168,6 +168,46 @@ def make_node(
|
|
|
168
168
|
)
|
|
169
169
|
|
|
170
170
|
if not is_known_shape:
|
|
171
|
+
def build_tf_pads_from_begin_end(pads_begin, pads_end):
|
|
172
|
+
pads_begin = tf.cast(pads_begin, tf.int32)
|
|
173
|
+
pads_end = tf.cast(pads_end, tf.int32)
|
|
174
|
+
spatial_pads = tf.stack([pads_begin, pads_end], axis=1)
|
|
175
|
+
return tf.concat(
|
|
176
|
+
[
|
|
177
|
+
tf.zeros((1, 2), dtype=tf.int32),
|
|
178
|
+
spatial_pads,
|
|
179
|
+
tf.zeros((1, 2), dtype=tf.int32),
|
|
180
|
+
],
|
|
181
|
+
axis=0,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def calc_extra_padding_with_ceil_dynamic(input_tensor, pads, kernel_shape, dilations, strides):
|
|
185
|
+
input_shape = tf.shape(input_tensor)
|
|
186
|
+
input_spatial = input_shape[1:-1]
|
|
187
|
+
pads_begin = tf.constant(pads[:len(pads) // 2], dtype=tf.int32)
|
|
188
|
+
pads_end = tf.constant(pads[len(pads) // 2:], dtype=tf.int32)
|
|
189
|
+
pads_along_axis = pads_begin + pads_end
|
|
190
|
+
k = tf.constant(kernel_shape, dtype=tf.int32)
|
|
191
|
+
d = tf.constant(dilations, dtype=tf.int32)
|
|
192
|
+
s = tf.constant(strides, dtype=tf.int32)
|
|
193
|
+
|
|
194
|
+
numerator = input_spatial + pads_along_axis - d * (k - 1) - 1
|
|
195
|
+
output_spatial = tf.cast(
|
|
196
|
+
tf.math.ceil(
|
|
197
|
+
tf.cast(numerator, tf.float32) / tf.cast(s, tf.float32) + 1.0
|
|
198
|
+
),
|
|
199
|
+
tf.int32,
|
|
200
|
+
)
|
|
201
|
+
last_stride_starts = (output_spatial - 1) * s
|
|
202
|
+
last_stride_validity = last_stride_starts < (input_spatial + pads_begin)
|
|
203
|
+
|
|
204
|
+
extra_pads = tf.where(
|
|
205
|
+
last_stride_validity,
|
|
206
|
+
last_stride_starts + (k - 1) * d + 1 - (input_spatial + pads_along_axis),
|
|
207
|
+
tf.zeros_like(input_spatial),
|
|
208
|
+
)
|
|
209
|
+
return extra_pads
|
|
210
|
+
|
|
171
211
|
def compute_output_spatial_shape_from_tensor(input_tensor, pads, kernel_shape, dilations, strides, ceil_mode=False):
|
|
172
212
|
input_shape = tf.shape(input_tensor) # Get dynamic shape
|
|
173
213
|
input_spatial = input_shape[1:-1] # Extract spatial dimensions only (NHWC format)
|
|
@@ -223,18 +263,32 @@ def make_node(
|
|
|
223
263
|
|
|
224
264
|
# extra padding to end side (right, bottom) may be needed when ceil_mode is True
|
|
225
265
|
# this extra padding should not be counted as padding when count_include_pad is True
|
|
226
|
-
if
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
266
|
+
if not is_known_shape:
|
|
267
|
+
pads_begin = tf.constant(pads[:len(pads) // 2], dtype=tf.int32)
|
|
268
|
+
pads_end = tf.constant(pads[len(pads) // 2:], dtype=tf.int32)
|
|
269
|
+
if ceil_mode:
|
|
270
|
+
extra_pads = calc_extra_padding_with_ceil_dynamic(
|
|
271
|
+
input_tensor=input_tensor,
|
|
231
272
|
pads=pads,
|
|
273
|
+
kernel_shape=kernel_shape,
|
|
232
274
|
dilations=dilations,
|
|
233
275
|
strides=strides,
|
|
234
276
|
)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
277
|
+
pads_end = pads_end + extra_pads
|
|
278
|
+
tf_pads = build_tf_pads_from_begin_end(pads_begin, pads_end)
|
|
279
|
+
else:
|
|
280
|
+
if ceil_mode:
|
|
281
|
+
extra_pads = \
|
|
282
|
+
calc_extra_padding_with_ceil(
|
|
283
|
+
input_shape=input_tensor_shape[1:-1],
|
|
284
|
+
kernel=kernel_shape,
|
|
285
|
+
pads=pads,
|
|
286
|
+
dilations=dilations,
|
|
287
|
+
strides=strides,
|
|
288
|
+
)
|
|
289
|
+
pads = pads[:len(pads) // 2] + [p + e for p, e in zip(pads[len(pads) // 2:], extra_pads)]
|
|
290
|
+
|
|
291
|
+
tf_pads = pads
|
|
238
292
|
|
|
239
293
|
elif auto_pad == 'SAME_UPPER':
|
|
240
294
|
tf_pad_mode = 'SAME'
|
|
@@ -305,36 +359,42 @@ def make_node(
|
|
|
305
359
|
# 1. when extra padding layer is added and count_include_pad is False
|
|
306
360
|
# 2. when extra padding layer is not added and count_include_pad is True
|
|
307
361
|
# 3. when last stride has extra padding due to ceil_mode and count_include_pad is True
|
|
308
|
-
if is_explicit_padding
|
|
362
|
+
if is_explicit_padding:
|
|
309
363
|
warn(
|
|
310
364
|
f'Tensorflow incompatible padding detected. ' \
|
|
311
365
|
f'Extra pad layer is inserted automatically. '
|
|
312
366
|
)
|
|
313
|
-
|
|
314
|
-
if auto_pad == 'SAME_LOWER':
|
|
315
|
-
# switch the order of pads
|
|
316
|
-
tf_pads = [i for tup in zip(tf_pads[len(tf_pads) // 2:], tf_pads[:len(tf_pads) // 2]) for i in tup]
|
|
317
|
-
|
|
318
|
-
if not count_include_pad and need_multiplier:
|
|
319
|
-
average_multiplier = []
|
|
320
|
-
for k, non_zero_count in zip(kernel_shape, non_zero_counts):
|
|
321
|
-
multiplier = [k / n if n != 0 else 1 for n in non_zero_count]
|
|
322
|
-
average_multiplier.append(multiplier)
|
|
323
|
-
|
|
324
|
-
# convert to tensorflow padding format
|
|
325
|
-
tf_pads = \
|
|
326
|
-
[[0, 0]] + \
|
|
327
|
-
[list(i) for i in zip(tf_pads[:len(tf_pads) // 2], tf_pads[len(tf_pads) // 2:])] + \
|
|
328
|
-
[[0, 0]]
|
|
329
|
-
|
|
330
|
-
if spatial_size == 1 and kernel_shape[0] > input_tensor_shape[1]:
|
|
331
|
-
padded_tensor = input_tensor
|
|
332
|
-
else:
|
|
367
|
+
if not is_known_shape:
|
|
333
368
|
padded_tensor = tf.pad(
|
|
334
369
|
tensor=input_tensor,
|
|
335
370
|
paddings=tf_pads,
|
|
336
371
|
mode='CONSTANT',
|
|
337
372
|
)
|
|
373
|
+
else:
|
|
374
|
+
if auto_pad == 'SAME_LOWER':
|
|
375
|
+
# switch the order of pads
|
|
376
|
+
tf_pads = [i for tup in zip(tf_pads[len(tf_pads) // 2:], tf_pads[:len(tf_pads) // 2]) for i in tup]
|
|
377
|
+
|
|
378
|
+
if not count_include_pad and need_multiplier:
|
|
379
|
+
average_multiplier = []
|
|
380
|
+
for k, non_zero_count in zip(kernel_shape, non_zero_counts):
|
|
381
|
+
multiplier = [k / n if n != 0 else 1 for n in non_zero_count]
|
|
382
|
+
average_multiplier.append(multiplier)
|
|
383
|
+
|
|
384
|
+
# convert to tensorflow padding format
|
|
385
|
+
tf_pads = \
|
|
386
|
+
[[0, 0]] + \
|
|
387
|
+
[list(i) for i in zip(tf_pads[:len(tf_pads) // 2], tf_pads[len(tf_pads) // 2:])] + \
|
|
388
|
+
[[0, 0]]
|
|
389
|
+
|
|
390
|
+
if spatial_size == 1 and kernel_shape[0] > input_tensor_shape[1]:
|
|
391
|
+
padded_tensor = input_tensor
|
|
392
|
+
else:
|
|
393
|
+
padded_tensor = tf.pad(
|
|
394
|
+
tensor=input_tensor,
|
|
395
|
+
paddings=tf_pads,
|
|
396
|
+
mode='CONSTANT',
|
|
397
|
+
)
|
|
338
398
|
|
|
339
399
|
else:
|
|
340
400
|
padded_tensor = input_tensor
|
|
@@ -345,7 +405,7 @@ def make_node(
|
|
|
345
405
|
multiplier = [n / k for n in non_zero_count]
|
|
346
406
|
average_multiplier.append(multiplier)
|
|
347
407
|
|
|
348
|
-
if count_include_pad and extra_pads != [0] * spatial_size:
|
|
408
|
+
if count_include_pad and is_known_shape and extra_pads != [0] * spatial_size:
|
|
349
409
|
# extra padding in last stride should not be included in averaging
|
|
350
410
|
if average_multiplier is None:
|
|
351
411
|
average_multiplier = []
|
|
@@ -370,7 +430,7 @@ def make_node(
|
|
|
370
430
|
# Generation of TF OP
|
|
371
431
|
tf_op_type = None
|
|
372
432
|
if len(kernel_shape) == 1:
|
|
373
|
-
if kernel_shape[0] > padded_tensor.shape[1]:
|
|
433
|
+
if padded_tensor.shape[1] is not None and kernel_shape[0] > padded_tensor.shape[1]:
|
|
374
434
|
pooled_tensor = AveragePooling1D(
|
|
375
435
|
pool_size=[padded_tensor.shape[1]],
|
|
376
436
|
strides=[padded_tensor.shape[1]],
|
onnx2tf/ops/Conv.py
CHANGED
|
@@ -370,6 +370,20 @@ def make_node(
|
|
|
370
370
|
)
|
|
371
371
|
|
|
372
372
|
def depth_conv_bias(input_tensor, input_weights, pad_mode, strides, dilations, input_bias):
|
|
373
|
+
# tf.nn.depthwise_conv2d uses a different output shape when dilation>1 and stride>1.
|
|
374
|
+
# Emulate stride>1 by running stride=1 then subsampling to match ONNX.
|
|
375
|
+
if pad_mode == 'VALID' \
|
|
376
|
+
and max(dilations) > 1 \
|
|
377
|
+
and any(s > 1 for s in strides[1:-1]):
|
|
378
|
+
conv = tf.nn.depthwise_conv2d(
|
|
379
|
+
input=input_tensor,
|
|
380
|
+
filter=input_weights,
|
|
381
|
+
padding=pad_mode,
|
|
382
|
+
strides=[1, 1, 1, 1],
|
|
383
|
+
dilations=dilations,
|
|
384
|
+
)
|
|
385
|
+
conv = conv[:, ::strides[1], ::strides[2], :]
|
|
386
|
+
return tf.add(conv, input_bias)
|
|
373
387
|
return \
|
|
374
388
|
tf.add(
|
|
375
389
|
tf.nn.depthwise_conv2d(
|
|
@@ -438,6 +452,19 @@ def make_node(
|
|
|
438
452
|
)
|
|
439
453
|
|
|
440
454
|
def depth_conv_nobias(input_tensor, input_weights, pad_mode, strides, dilations):
|
|
455
|
+
# tf.nn.depthwise_conv2d uses a different output shape when dilation>1 and stride>1.
|
|
456
|
+
# Emulate stride>1 by running stride=1 then subsampling to match ONNX.
|
|
457
|
+
if pad_mode == 'VALID' \
|
|
458
|
+
and max(dilations) > 1 \
|
|
459
|
+
and any(s > 1 for s in strides[1:-1]):
|
|
460
|
+
conv = tf.nn.depthwise_conv2d(
|
|
461
|
+
input=input_tensor,
|
|
462
|
+
filter=input_weights,
|
|
463
|
+
padding=pad_mode,
|
|
464
|
+
strides=[1, 1, 1, 1],
|
|
465
|
+
dilations=dilations,
|
|
466
|
+
)
|
|
467
|
+
return conv[:, ::strides[1], ::strides[2], :]
|
|
441
468
|
return \
|
|
442
469
|
tf.nn.depthwise_conv2d(
|
|
443
470
|
input=input_tensor,
|