diff options
Diffstat (limited to 'verif/generator/tosa_arg_gen.py')
-rw-r--r-- | verif/generator/tosa_arg_gen.py | 338 |
1 files changed, 210 insertions, 128 deletions
diff --git a/verif/generator/tosa_arg_gen.py b/verif/generator/tosa_arg_gen.py index 8e00fab..2181735 100644 --- a/verif/generator/tosa_arg_gen.py +++ b/verif/generator/tosa_arg_gen.py @@ -6,6 +6,7 @@ import math import numpy as np from generator.tosa_error_if import ErrorIf from generator.tosa_error_if import TosaErrorIfArgGen +from generator.tosa_utils import MAX_RESIZE_DIMENSION from serializer.tosa_serializer import DTypeNames from tosa.DType import DType from tosa.Op import Op @@ -1609,10 +1610,107 @@ class TosaArgGen: @staticmethod def agResize(testGen, opName, shapeList, dtype, error_name=None): arg_list = [] - ifm_shape = shapeList[0] - for mode in [ResizeMode.NEAREST, ResizeMode.BILINEAR]: + def get_aspect_ratio_resize_params(): + common_aspect_ratios = ((3, 2), (16, 9), (4, 3)) + aspect_ratio = testGen.rng.choice(common_aspect_ratios) + invert = testGen.rng.choice((False, True)) + letterbox = testGen.rng.choice((False, True)) + + scale_y_n = aspect_ratio[0] if invert else aspect_ratio[1] + scale_x_n = aspect_ratio[1] if invert else aspect_ratio[0] + scale_y_d = scale_x_d = 1 + offset_x = offset_y = 0 + + if letterbox: + max_border = scale_y_n + border_y = testGen.randInt(low=0, high=max_border) + border_x = 0 + else: + # Pillarboxing + border_y = 0 + max_border = scale_x_n + border_x = testGen.randInt(low=0, high=max_border) + + scale = (scale_y_n, scale_y_d, scale_x_n, scale_x_d) + offset = (offset_y, offset_x) + border = (border_y, border_x) + + return scale, offset, border + + def get_upscale_downscale_params(): + valid_params = False + while not valid_params: + upscale = testGen.rng.choice((False, True)) + + # True if sampling begins from (0,0). Otherwise (-0.5,-0.5) + origin_sampling = testGen.rng.choice((False, True)) + + if upscale: + shift = testGen.randInt(low=1, high=4) + scale_x_d = scale_y_d = 1 + scale_x_n = scale_y_n = ( + 1 << shift if origin_sampling else 2 << shift + ) + border_x = border_y = 0 if origin_sampling else (1 << shift) - 1 + offset_x = offset_y = 0 if origin_sampling else -(1 << shift) + 1 + else: + scale_x_n = 1 + scale_y_n = 1 + + # Return list of valid scale_*_d values (max value 4) given input dim shape + def get_valid_denom(ifm_dim): + return [x for x in range(1, 5) if ifm_dim % x == 1] + + # Generate list of valid downscale values and choose one randomly + valid_scale_y_ds = get_valid_denom(ifm_shape[1]) + valid_scale_x_ds = get_valid_denom(ifm_shape[2]) + + if not valid_scale_y_ds and not valid_scale_x_ds: + # Bad parameters, skip + continue + + if not valid_scale_y_ds: + scale_y_d = 1 + else: + scale_y_d = testGen.rng.choice(valid_scale_y_ds) + + if not valid_scale_x_ds: + scale_x_d = 1 + else: + scale_x_d = testGen.rng.choice(valid_scale_x_ds) + + border_x = border_y = 0 + offset_y = testGen.randInt(0, 16 * scale_y_n) + offset_x = testGen.randInt(0, 16 * scale_x_n) + valid_params = True + + scale = (scale_y_n, scale_y_d, scale_x_n, scale_x_d) + offset = (offset_y, offset_x) + border = (border_y, border_x) + return scale, offset, border + + def get_rand_params(): + # Scale + scale_y_n = testGen.randInt(low=1, high=(1 << 11)) + scale_x_n = testGen.randInt(low=1, high=(1 << 11)) + + scale_y_d = testGen.randInt(low=1, high=(16 * scale_y_n)) + scale_x_d = testGen.randInt(low=1, high=(16 * scale_x_n)) + + # Offsets and border within the scale + offset_y = testGen.randInt(low=-scale_y_n, high=(16 * scale_y_n)) + offset_x = testGen.randInt(low=-scale_x_n, high=(16 * scale_x_n)) + border_y = testGen.randInt(low=(-16 * scale_y_n), high=scale_y_n) + border_x = testGen.randInt(low=(-16 * scale_x_n), high=scale_x_n) + + scale = (scale_y_n, scale_y_d, scale_x_n, scale_x_d) + offset = (offset_y, offset_x) + border = (border_y, border_x) + return scale, offset, border + + for mode in [ResizeMode.NEAREST, ResizeMode.BILINEAR]: # Exclude illegal {mode, type} configurations. Pick legal output types if mode == ResizeMode.NEAREST and dtype == DType.INT8: outputDTypeList = [DType.INT8] @@ -1631,114 +1729,98 @@ class TosaArgGen: else: continue + arg_str = "mode{}_out{}_sc{}x{}x{}x{}_off{}x{}_bor{}x{}" + for outputDType in outputDTypeList: - for perm in range(testGen.args.num_rand_permutations): - # Randomly generate legal output dimensions and shift - # and then compute the stride and offset based on them - # A output_dim of 1 will cause offset to exceed allowed range - # so minimum value 2 produced below - output_dims = [testGen.randInt(1) + 1, testGen.randInt(1) + 1] - while (float(ifm_shape[1]) / float(output_dims[0])) >= 16: - output_dims[0] += 1 - while (float(ifm_shape[2]) / float(output_dims[1])) >= 16: - output_dims[1] += 1 - - in_center_h = (ifm_shape[1] - 1) / 2.0 - in_center_w = (ifm_shape[2] - 1) / 2.0 - out_center_h = (output_dims[0] - 1) / 2.0 - out_center_w = (output_dims[1] - 1) / 2.0 - - fp_stride_y = float(ifm_shape[1]) / float(output_dims[0]) - fp_stride_x = float(ifm_shape[2]) / float(output_dims[1]) - fp_offset_y = in_center_h - fp_stride_y * out_center_h - fp_offset_x = in_center_w - fp_stride_x * out_center_w - - if outputDType == DType.FLOAT: - float_op = True - arg_str = ( - "mode{}_shift{}_odim{}x{}_out{}" - "_st{:.2f}x{:.2f}_off{:.2f}x{:.2f}" + perm = 0 + while perm < testGen.args.num_rand_permutations: + # Random choice of type of params we are testing + _rnd_param_fn = testGen.rng.choice( + ( + get_rand_params, + get_upscale_downscale_params, + get_aspect_ratio_resize_params, ) - shift = 0 - stride = [0, 0] - offset = [0, 0] - stride_fp = [fp_stride_y, fp_stride_x] - offset_fp = [fp_offset_y, fp_offset_x] + ) + scale, offset, border = _rnd_param_fn() - else: - float_op = False - arg_str = "mode{}_shift{}_odim{}x{}_out{}_st{}x{}_off{}x{}" - shift = testGen.randInt(1, 12) - # Now search for a shift value (1 to 11) that will produce - # a valid and predictable resize operation - count = 0 - while count < 12: - unit = float(1 << shift) - stride_y = int(round(fp_stride_y * unit)) - stride_x = int(round(fp_stride_x * unit)) - offset_y = int(round(fp_offset_y * unit)) - offset_x = int(round(fp_offset_x * unit)) - - if ( - stride_y <= 0 - or stride_x <= 0 - or stride_y >= (16 << shift) - or stride_x >= (16 << shift) - or offset_y >= (16 << shift) - or offset_x >= (16 << shift) - or offset_y <= (-16 << shift) - or offset_x <= (-16 << shift) - ): - # Change the shift value and check again - count += 1 - shift = (shift % 11) + 1 - continue - - def RESIZE_REQUIRE_CALC( - length_in, length_out, stride, offset, shift - ): - # Perform the pseudo loop to look for out of bounds - for pos in range(0, length_out): - a = pos * stride + offset - ia = a >> shift - ia0 = max(ia, 0) - ia1 = min(ia + 1, length_in - 1) - if ia0 > ia1: - # Found a problem value - break - return ia0, ia1 - - iy0, iy1 = RESIZE_REQUIRE_CALC( - ifm_shape[1], output_dims[0], stride_y, offset_y, shift - ) - ix0, ix1 = RESIZE_REQUIRE_CALC( - ifm_shape[2], output_dims[1], stride_x, offset_x, shift - ) - if ix0 > ix1 or iy0 > iy1: - # Change the shift value and check again - count += 1 - shift = (shift % 11) + 1 - continue - break - - if count >= 12: - # Couldn't find a good set of values for this test, skip it + # Expand params for bounds-checking + (scale_y_n, scale_y_d, scale_x_n, scale_x_d) = scale + (offset_y, offset_x) = offset + (border_y, border_x) = border + + # Make sure output dimensions OH and OW are integers + partial_output_y = ( + (ifm_shape[1] - 1) * scale_y_n - offset_y + border_y + ) + partial_output_x = ( + (ifm_shape[2] - 1) * scale_x_n - offset_x + border_x + ) + if error_name == ErrorIf.ResizeOutputShapeNonInteger: + if ( + partial_output_y % scale_y_d == 0 + and partial_output_x % scale_x_d == 0 + ): + # Skip this test as it doesn't produce NonInteger output + perm += 1 continue + else: + while partial_output_y % scale_y_d != 0: + scale_y_d -= 1 + while partial_output_x % scale_x_d != 0: + scale_x_d -= 1 + + output_y = partial_output_y // scale_y_d + 1 + output_x = partial_output_x // scale_x_d + 1 - stride = [stride_y, stride_x] - offset = [offset_y, offset_x] + if ( + output_y >= testGen.args.max_resize_output_dim + or output_x >= testGen.args.max_resize_output_dim + ) and error_name is None: + # Skip positive test if output dim will be too high + # Avoid high test latency and OOM issues + perm += 1 + continue - stride_fp = [0.0, 0.0] - offset_fp = [0.0, 0.0] + if ( + output_y <= 0 + or output_y >= MAX_RESIZE_DIMENSION + or output_x <= 0 + or output_x >= MAX_RESIZE_DIMENSION + ): + # Output dimensions out of scope + if error_name is not None and perm > 0: + # As long as we have one ERROR_IF test, don't worry + # about creating all the other permutations + perm += 1 + continue + + if error_name == ErrorIf.ResizeOutputShapeMismatch and ( + ( + output_y + scale_y_d >= MAX_RESIZE_DIMENSION + and output_y - scale_y_d < 1 + ) + or ( + output_x + scale_x_d >= MAX_RESIZE_DIMENSION + and output_x - scale_x_d < 1 + ) + ): + # Can't create a negative test with these params as it + # will create invalid output size + if perm > 0: + perm += 1 + continue + + scale = [scale_y_n, scale_y_d, scale_x_n, scale_x_d] + offset = [offset_y, offset_x] + border = [border_y, border_x] # Common for all data types if error_name is not None: ( - shift, - stride, - stride_fp, + scale, offset, - offset_fp, + border, outputDTypeNew, ) = TosaErrorIfArgGen.eiResizeErrorIf( testGen, @@ -1747,42 +1829,42 @@ class TosaArgGen: dtype, shapeList, outputDType, - shift, - stride, - stride_fp, + scale, offset, - offset_fp, + border, ) else: outputDTypeNew = outputDType - arg_list.append( - ( - arg_str.format( - "N" if mode == ResizeMode.NEAREST else "B", - shift, - output_dims[0], - output_dims[1], - testGen.typeStr(outputDTypeNew), - stride_fp[0] if float_op else stride[0], - stride_fp[1] if float_op else stride[1], - offset_fp[0] if float_op else offset[0], - offset_fp[1] if float_op else offset[1], - ), - [ - mode, - stride, - offset, - shift, - stride_fp, - offset_fp, - output_dims, - dtype, - outputDTypeNew, - ], - ) + arg_to_append = ( + arg_str.format( + "N" if mode == ResizeMode.NEAREST else "B", + testGen.typeStr(outputDTypeNew), + scale[0], + scale[1], + scale[2], + scale[3], + offset[0], + offset[1], + border[0], + border[1], + ), + [ + mode, + scale, + offset, + border, + dtype, + outputDTypeNew, + ], ) + if arg_to_append in arg_list: + # Skip already generated test params + continue + # Valid permutation + perm += 1 + arg_list.append(arg_to_append) return arg_list @staticmethod |