diff options
-rw-r--r-- | verif/conformance/tosa_main_profile_ops_info.json | 6 | ||||
-rw-r--r-- | verif/conformance/tosa_verif_conformance_generator.py | 7 | ||||
-rw-r--r-- | verif/generator/tosa_arg_gen.py | 580 | ||||
-rw-r--r-- | verif/generator/tosa_error_if.py | 78 | ||||
-rw-r--r-- | verif/generator/tosa_random_gen.py | 174 | ||||
-rw-r--r-- | verif/generator/tosa_test_gen.py | 703 | ||||
-rw-r--r-- | verif/generator/tosa_verif_build_tests.py | 9 |
7 files changed, 901 insertions, 656 deletions
diff --git a/verif/conformance/tosa_main_profile_ops_info.json b/verif/conformance/tosa_main_profile_ops_info.json index 63a2a9c..fbf5a82 100644 --- a/verif/conformance/tosa_main_profile_ops_info.json +++ b/verif/conformance/tosa_main_profile_ops_info.json @@ -723,7 +723,7 @@ "profile": [ "tosa-mi" ], - "support_for": [ "lazy_data_gen", "generator_select" ], + "support_for": [ "lazy_data_gen", "generator_select", "stable_random_gen" ], "gen_filter": "^conv2d", "generation": { "standard": { @@ -754,7 +754,7 @@ "--target-shape", "1,65537,1,3", "--target-shape", - "1,2,65531,2", + "1,2,65530,2", "--tensor-dim-range", "1,16", "--max-conv-dilation", @@ -1881,7 +1881,7 @@ "profile": [ "tosa-mi" ], - "support_for": [ "lazy_data_gen", "generator_select" ], + "support_for": [ "lazy_data_gen", "generator_select", "stable_random_gen" ], "generation": { "standard": { "generator_args": [ diff --git a/verif/conformance/tosa_verif_conformance_generator.py b/verif/conformance/tosa_verif_conformance_generator.py index 7c82f31..5402c21 100644 --- a/verif/conformance/tosa_verif_conformance_generator.py +++ b/verif/conformance/tosa_verif_conformance_generator.py @@ -138,6 +138,8 @@ def build_op_tests( if "lazy_data_gen" in supports and args.lazy_data_generation: build_cmd_base.append("--lazy-data-generation") + if "stable_random_gen" in supports and not args.global_random_generation: + build_cmd_base.append("--stable-random-generation") if "generator_select" in supports: if selector_info is None: @@ -545,6 +547,11 @@ def parse_args(argv=None): help="Type of tests produced (default is both)", ) parser.add_argument( + "--global-random-generation", + action="store_true", + help="Disable stable random generation of tests that support this mode", + ) + parser.add_argument( "--lazy-data-generation", action="store_true", help="Enable lazy data generation (only for tosa-mi)", diff --git a/verif/generator/tosa_arg_gen.py b/verif/generator/tosa_arg_gen.py index a2ef5bf..83487a1 100644 --- a/verif/generator/tosa_arg_gen.py +++ b/verif/generator/tosa_arg_gen.py @@ -30,48 +30,48 @@ class TosaQuantGen: pass @staticmethod - def getZeroPoint(testGen, dtype, error_name=None): + def getZeroPoint(rng, zeropoint, dtype, error_name=None): if dtype == DType.INT8: - if testGen.args.zeropoint is not None: - return min(127, max(-128, testGen.args.zeropoint)) - return testGen.randInt(-128, 128) + if zeropoint is not None: + return min(127, max(-128, zeropoint)) + return rng.randInt(-128, 128) elif dtype == DType.UINT8: - if testGen.args.zeropoint is not None: - return min(255, max(0, testGen.args.zeropoint)) - return testGen.randInt(0, 256) + if zeropoint is not None: + return min(255, max(0, zeropoint)) + return rng.randInt(0, 256) elif error_name in [ ErrorIf.InputZeroPointNotZero, ErrorIf.WeightZeroPointNotZero, ErrorIf.OutputZeroPointNotZero, ]: - zero_point = testGen.randInt(-128, 128) + zero_point = rng.randInt(-128, 128) if zero_point == 0: zero_point = 1 return zero_point return 0 @staticmethod - def qgUnary(testGen, op, dtype, error_name=None): + def qgUnary(rng, zeropoint, op, dtype, error_name=None): if error_name == ErrorIf.InputZeroPointNotZero: qinfo = [ - TosaQuantGen.getZeroPoint(testGen, dtype, error_name), - TosaQuantGen.getZeroPoint(testGen, dtype), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype, error_name), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype), ] elif error_name == ErrorIf.OutputZeroPointNotZero: qinfo = [ - TosaQuantGen.getZeroPoint(testGen, dtype), - TosaQuantGen.getZeroPoint(testGen, dtype, error_name), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype, error_name), ] else: qinfo = [ - TosaQuantGen.getZeroPoint(testGen, dtype), - TosaQuantGen.getZeroPoint(testGen, dtype), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype), ] return qinfo @staticmethod - def qgConv(testGen, op, dtype_or_dtypeList, error_name=None): + def qgConv(rng, zeropoint, op, dtype_or_dtypeList, error_name=None): if isinstance(dtype_or_dtypeList, list): # a list of [input, weights, accumulator] dtypes dtypeList = dtype_or_dtypeList @@ -81,32 +81,32 @@ class TosaQuantGen: if error_name == ErrorIf.InputZeroPointNotZero: qinfo = [ - TosaQuantGen.getZeroPoint(testGen, dtypeList[0], error_name), - TosaQuantGen.getZeroPoint(testGen, dtypeList[1]), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtypeList[0], error_name), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtypeList[1]), ] elif error_name == ErrorIf.WeightZeroPointNotZero: qinfo = [ - TosaQuantGen.getZeroPoint(testGen, dtypeList[0]), - TosaQuantGen.getZeroPoint(testGen, dtypeList[1], error_name), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtypeList[0]), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtypeList[1], error_name), ] else: qinfo = [ - TosaQuantGen.getZeroPoint(testGen, dtypeList[0]), - TosaQuantGen.getZeroPoint(testGen, dtypeList[1]), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtypeList[0]), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtypeList[1]), ] return qinfo @staticmethod - def qgMatmul(testGen, op, dtype, error_name=None): + def qgMatmul(rng, zeropoint, op, dtype, error_name=None): if error_name == ErrorIf.InputZeroPointNotZero: qinfo = [ - TosaQuantGen.getZeroPoint(testGen, dtype, error_name), - TosaQuantGen.getZeroPoint(testGen, dtype, error_name), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype, error_name), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype, error_name), ] else: qinfo = [ - TosaQuantGen.getZeroPoint(testGen, dtype), - TosaQuantGen.getZeroPoint(testGen, dtype), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype), + TosaQuantGen.getZeroPoint(rng, zeropoint, dtype), ] return qinfo @@ -166,9 +166,9 @@ class TosaTensorGen: pass @staticmethod - def tgBasic(testGen, opName, rank, error_name=None): - pl, const = opName["operands"] - shape = testGen.makeShape(rank) + def tgBasic(testGen, rng, op, rank, error_name=None): + pl, const = op["operands"] + shape = testGen.makeShape(rng, rank) # Constrict the overall size of the shape when creating ERROR_IF tests if error_name: @@ -181,20 +181,20 @@ class TosaTensorGen: # Generates an input rank mismatch for operators with more than one input if error_name == ErrorIf.RankMismatch: if rank == 1 and i != 1: - shape = testGen.makeShape(rank + testGen.rng.choice([1, 2, 3])) + shape = testGen.makeShape(rng, rank + rng.choice([1, 2, 3])) elif i != 1: - shape = testGen.makeShape(rank + testGen.rng.choice([-1, 1])) + shape = testGen.makeShape(rng, rank + rng.choice([-1, 1])) return shape_list @staticmethod - def tgNHWC(testGen, opName, rank, error_name=None): - pl, const = opName["operands"] + def tgNHWC(testGen, rng, op, rank, error_name=None): + pl, const = op["operands"] if error_name != ErrorIf.WrongRank: assert rank == 4 - shape = testGen.makeShape(rank) + shape = testGen.makeShape(rng, rank) shape = testGen.constrictBatchSize(shape) # Constrict the overall size of the shape when creating ERROR_IF tests @@ -208,7 +208,7 @@ class TosaTensorGen: return shape_list @staticmethod - def tgGather(testGen, opName, rank, error_name=None): + def tgGather(testGen, rng, opName, rank, error_name=None): pl, const = opName["operands"] assert pl == 2 @@ -216,18 +216,18 @@ class TosaTensorGen: if error_name != ErrorIf.WrongRank: assert rank == 3 - values_shape = testGen.makeShape(rank) + values_shape = testGen.makeShape(rng, rank) values_shape = testGen.constrictBatchSize(values_shape) N = values_shape[0] - W = testGen.makeDimension() + W = testGen.makeDimension(rng) indices_shape = [N, W] shape_list = [values_shape, indices_shape] return shape_list @staticmethod - def tgScatter(testGen, opName, rank, error_name=None): + def tgScatter(testGen, rng, opName, rank, error_name=None): pl, const = opName["operands"] assert pl == 3 @@ -235,7 +235,7 @@ class TosaTensorGen: if error_name != ErrorIf.WrongRank: assert rank == 3 - values_in_shape = testGen.makeShape(rank) + values_in_shape = testGen.makeShape(rng, rank) values_in_shape = testGen.constrictBatchSize(values_in_shape) N = values_in_shape[0] @@ -246,7 +246,7 @@ class TosaTensorGen: # once (having a W greater than K means that you have to repeat a K index) W_min = min(testGen.args.tensor_shape_range[0], K) W_max = min(testGen.args.tensor_shape_range[1], K) - W = testGen.randInt(W_min, W_max) if W_min < W_max else W_min + W = rng.randInt(W_min, W_max) if W_min < W_max else W_min input_shape = [N, W, C] @@ -258,14 +258,14 @@ class TosaTensorGen: return shape_list @staticmethod - def _get_broadcast_shapes(testGen, num_shapes, rank, error_name=None): - shape = testGen.makeShape(rank) + def _get_broadcast_shapes(testGen, rng, num_shapes, rank, error_name=None): + shape = testGen.makeShape(rng, rank) shape_list = [] # Choose one of the inputs to broadcast # Note: Simplifies OutputShaper code if we don't change first shape for errors - bcast_idx = testGen.randInt(0 if error_name is None else 1, num_shapes) - fuzz_idx = testGen.randInt(0, rank) + bcast_idx = rng.randInt(0 if error_name is None else 1, num_shapes) + fuzz_idx = rng.randInt(0, rank) for i in range(num_shapes): shape_bcast = shape.copy() @@ -278,13 +278,13 @@ class TosaTensorGen: if i == bcast_idx: if error_name == ErrorIf.RankMismatch: # Add one rank to the shape (or more for rank of 1) - extra_ranks = testGen.rng.choice([1, 2, 3]) if rank == 1 else 1 + extra_ranks = rng.choice([1, 2, 3]) if rank == 1 else 1 shape_bcast = np.concatenate( - (shape_bcast, testGen.makeShape(extra_ranks)) + (shape_bcast, testGen.makeShape(rng, extra_ranks)) ) if rank != 1: # Either keep the extra rank, or remove it - new_len = testGen.rng.choice([-2, len(shape_bcast)]) + new_len = rng.choice([-2, len(shape_bcast)]) shape_bcast = shape_bcast[:new_len] elif error_name == ErrorIf.BroadcastShapesMismatch: shape_bcast[fuzz_idx] += 2 @@ -296,30 +296,32 @@ class TosaTensorGen: return shape_list @staticmethod - def tgBroadcastFuzz(testGen, op, rank, error_name=None): + def tgBroadcastFuzz(testGen, rng, op, rank, error_name=None): pl, const = op["operands"] num_shapes = pl + const return TosaTensorGen._get_broadcast_shapes( - testGen, num_shapes, rank, error_name + testGen, rng, num_shapes, rank, error_name ) @staticmethod - def tgMul(testGen, op, rank, error_name=None): + def tgMul(testGen, rng, op, rank, error_name=None): # Get broadcast shapes for the first 2 inputs as the 3rd is shift - shape_list = TosaTensorGen._get_broadcast_shapes(testGen, 2, rank, error_name) + shape_list = TosaTensorGen._get_broadcast_shapes( + testGen, rng, 2, rank, error_name + ) # Add a single dimension tensor for shift shape_list.append([1]) return shape_list @staticmethod - def tgConv2D(testGen, op, rank, error_name=None): + def tgConv2D(testGen, rng, op, rank, error_name=None): pl, const = op["operands"] if error_name != ErrorIf.WrongRank: assert rank == 4 # IFM dimensions are NHWC - ifm_shape = testGen.makeShape(rank) + ifm_shape = testGen.makeShape(rng, rank) ifm_shape = testGen.constrictBatchSize(ifm_shape) # Constrict the overall size of the shape when creating ERROR_IF tests @@ -332,7 +334,7 @@ class TosaTensorGen: filter_hw = op["filter"] # Generate a random OFM depth - ofm_depth = testGen.makeDimension() + ofm_depth = testGen.makeDimension(rng) # The filter dimensions are OHWI filter_shape = np.asarray([ofm_depth, filter_hw[0], filter_hw[1], ifm_shape[3]]) @@ -343,14 +345,14 @@ class TosaTensorGen: return [ifm_shape, filter_shape, bias_shape] @staticmethod - def tgConv3D(testGen, op, rank, error_name=None): + def tgConv3D(testGen, rng, op, rank, error_name=None): pl, const = op["operands"] if error_name != ErrorIf.WrongRank: assert rank == 5 # IFM dimensions are NDHWC - ifm_shape = testGen.makeShape(rank) + ifm_shape = testGen.makeShape(rng, rank) ifm_shape = testGen.constrictBatchSize(ifm_shape) # Constrict the overall size of the shape when creating ERROR_IF tests @@ -363,7 +365,7 @@ class TosaTensorGen: filter_dhw = op["filter"] # Generate a random OFM channel - ofm_channel = testGen.makeDimension() + ofm_channel = testGen.makeDimension(rng) # The filter dimensions are ODHWI filter_shape = np.asarray( @@ -376,14 +378,14 @@ class TosaTensorGen: return [ifm_shape, filter_shape, bias_shape] @staticmethod - def tgTransposeConv2D(testGen, op, rank, error_name=None): + def tgTransposeConv2D(testGen, rng, op, rank, error_name=None): pl, const = op["operands"] if error_name != ErrorIf.WrongRank: assert rank == 4 # IFM dimensions are NHWC - ifm_shape = testGen.makeShape(rank) + ifm_shape = testGen.makeShape(rng, rank) ifm_shape = testGen.constrictBatchSize(ifm_shape) # Constrict the overall size of the shape when creating ERROR_IF tests @@ -396,7 +398,7 @@ class TosaTensorGen: filter_hw = op["filter"] # Generate a random OFM depth - ofm_depth = testGen.makeDimension() + ofm_depth = testGen.makeDimension(rng) # The filter dimensions are OHWI filter_shape = np.asarray([ofm_depth, filter_hw[0], filter_hw[1], ifm_shape[3]]) @@ -407,7 +409,7 @@ class TosaTensorGen: return [ifm_shape, filter_shape, bias_shape] @staticmethod - def tgDepthwiseConv2D(testGen, op, rank, error_name=None): + def tgDepthwiseConv2D(testGen, rng, op, rank, error_name=None): pl, const = op["operands"] if error_name != ErrorIf.WrongRank: @@ -415,7 +417,7 @@ class TosaTensorGen: assert pl == 1 and const == 2 # IFM dimensions are NHWC - ifm_shape = testGen.makeShape(rank) + ifm_shape = testGen.makeShape(rng, rank) ifm_shape = testGen.constrictBatchSize(ifm_shape) # Constrict the overall size of the shape when creating ERROR_IF tests @@ -431,7 +433,7 @@ class TosaTensorGen: # Generate a random OFM depth, but don't let it get too big because # the output depth is M * C filter_m = ( - testGen.makeDimension() % (testGen.args.tensor_shape_range[1] // 4) + testGen.makeDimension(rng) % (testGen.args.tensor_shape_range[1] // 4) ) + 1 # The filter dimensions are HWCM @@ -443,7 +445,7 @@ class TosaTensorGen: return [ifm_shape, filter_shape, bias_shape] @staticmethod - def tgFFT2d(testGen, op, rank, error_name=None): + def tgFFT2d(testGen, rng, op, rank, error_name=None): pl, const = op["operands"] if error_name != ErrorIf.WrongRank: @@ -451,7 +453,7 @@ class TosaTensorGen: assert pl == 2 and const == 0 # IFM dimensions are NHW - ifm_shape = testGen.makeShape(rank) + ifm_shape = testGen.makeShape(rng, rank) # Select nearest lower power of two from input height and width ifm_shape[1] = 2 ** int(math.log(ifm_shape[1], 2)) @@ -466,7 +468,7 @@ class TosaTensorGen: inc_h = 2 if ifm_shape[1] == 1 else 1 inc_w = 2 if ifm_shape[2] == 1 else 1 inc_choices = [(inc_h, 0), (0, inc_w), (inc_h, inc_w)] - selected_inc = testGen.rng.choice(inc_choices) + selected_inc = rng.choice(inc_choices) ifm_shape[1] += selected_inc[0] ifm_shape[2] += selected_inc[1] @@ -474,15 +476,15 @@ class TosaTensorGen: ifm_shapes = [ifm_shape.copy(), ifm_shape.copy()] if error_name == ErrorIf.FFTInputShapeMismatch: - modify_shape = testGen.rng.choice([0, 1]) + modify_shape = rng.choice([0, 1]) # Only modify kernel (H, W) - modify_dim = testGen.rng.choice([1, 2]) + modify_dim = rng.choice([1, 2]) ifm_shapes[modify_shape][modify_dim] *= 2 return [ifm_shapes[0], ifm_shapes[1]] @staticmethod - def tgRFFT2d(testGen, op, rank, error_name=None): + def tgRFFT2d(testGen, rng, op, rank, error_name=None): pl, const = op["operands"] if error_name != ErrorIf.WrongRank: @@ -490,7 +492,7 @@ class TosaTensorGen: assert pl == 1 and const == 0 # IFM dimensions are NHW - ifm_shape = testGen.makeShape(rank) + ifm_shape = testGen.makeShape(rng, rank) # Select nearest lower power of two from input height and width ifm_shape[1] = 2 ** int(math.log(ifm_shape[1], 2)) @@ -506,7 +508,7 @@ class TosaTensorGen: inc_h = 2 if ifm_shape[1] == 1 else 1 inc_w = 2 if ifm_shape[2] == 1 else 1 inc_choices = [(inc_h, 0), (0, inc_w), (inc_h, inc_w)] - selected_inc = testGen.rng.choice(inc_choices) + selected_inc = rng.choice(inc_choices) ifm_shape[1] += selected_inc[0] ifm_shape[2] += selected_inc[1] @@ -515,19 +517,19 @@ class TosaTensorGen: return [ifm_shape] @staticmethod - def tgFullyConnected(testGen, op, rank, error_name=None): + def tgFullyConnected(testGen, rng, op, rank, error_name=None): pl, const = op["operands"] if error_name != ErrorIf.WrongRank: assert rank == 2 - input_shape = testGen.makeShape(rank) + input_shape = testGen.makeShape(rng, rank) # Constrict the overall size of the shape when creating ERROR_IF tests if error_name: input_shape = TosaErrorIfArgGen.eiRestrictDimensions(input_shape) - filter_oc = testGen.rng.integers( + filter_oc = rng.integers( low=testGen.args.tensor_shape_range[0], high=testGen.args.tensor_shape_range[1], size=1, @@ -539,14 +541,14 @@ class TosaTensorGen: return [input_shape, filter_shape, bias_shape] @staticmethod - def tgMatmul(testGen, op, rank, error_name=None): + def tgMatmul(testGen, rng, op, rank, error_name=None): pl, const = op["operands"] if error_name != ErrorIf.WrongRank: assert rank == 3 assert pl == 2 and const == 0 - a_shape = testGen.makeShape(rank) + a_shape = testGen.makeShape(rng, rank) # Constrict the overall size of the shape when creating ERROR_IF tests if error_name: @@ -554,7 +556,7 @@ class TosaTensorGen: # Get a random number for b_oc even if target shape is defined b_oc = np.int32( - testGen.rng.integers( + rng.integers( low=testGen.args.tensor_shape_range[0], high=testGen.args.tensor_shape_range[1], size=1, @@ -568,24 +570,24 @@ class TosaTensorGen: return [a_shape, b_shape] @staticmethod - def tgConcat(testGen, opName, rank, error_name=None): - pl, const = opName["operands"] - shape = testGen.makeShape(rank) + def tgConcat(testGen, rng, op, rank, error_name=None): + pl, const = op["operands"] + shape = testGen.makeShape(rng, rank) # Create extra tensors to concat. # Take into account value of pl when getting maximum number of concats - num_tensors = testGen.randInt(0, 4) + num_tensors = rng.randInt(0, 4) shape_list = [] for i in range(pl + const + num_tensors): if error_name == ErrorIf.ConcatInputRankMismatch and i != 0: - remove = testGen.rng.choice([True, False]) + remove = rng.choice([True, False]) wrongShape = shape.copy() if remove and len(shape) > 1: wrongShape = wrongShape[1:] else: wrongShape = list(wrongShape) - wrongShape.append(testGen.rng.integers(1, 10)) + wrongShape.append(rng.integers(1, 10)) shape_list.append(wrongShape) else: @@ -594,7 +596,7 @@ class TosaTensorGen: return shape_list @staticmethod - def tgConcatConstInput(testGen, shapeList, axis, error_name=None): + def tgConcatConstInput(rng, shapeList, axis, error_name=None): if error_name in [ ErrorIf.AxisSmallerZero, ErrorIf.AxisLargerRank, @@ -610,7 +612,7 @@ class TosaTensorGen: for shape in shapeList[1:]: # Negative test shapeLists are created individually for each test, # so no need to copy the shape before altering it. - shape[(axis + 1) % len(shape)] += testGen.rng.integers(5, 10) + shape[(axis + 1) % len(shape)] += rng.integers(5, 10) return shapeList # Create copy of shape we are going to split (so we don't alter shapeList) @@ -630,7 +632,7 @@ class TosaTensorGen: # invalidate dimensions if error_name == ErrorIf.ConcatInputDimMismatch: - shape[(axis + 1) % len(shape)] += testGen.rng.integers(5, 10) + shape[(axis + 1) % len(shape)] += rng.integers(5, 10) else: shape[axis] = remaining_length @@ -672,12 +674,12 @@ class TosaTensorValuesGen: } @staticmethod - def _get_data_range(testGen, dtype, highValueLookup, lowValueLookup=None): + def _get_data_range(rng, dtype, highValueLookup, lowValueLookup=None): # Return a tuple of (low,high) data range values for the given data # type using a combination of per operator table limits, data limits # and user supplied ranges for FP numbers if dtype in highValueLookup: - type_range = testGen.getDTypeRange(dtype, high_inclusive=True) + type_range = rng.dTypeRange(dtype, high_inclusive=True) high_val = highValueLookup[dtype] if lowValueLookup is not None and dtype in lowValueLookup: low_val = lowValueLookup[dtype] @@ -703,7 +705,7 @@ class TosaTensorValuesGen: @staticmethod def tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name=None + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None ): # Variable inputs versus constants pCount, cCount = testGen.TOSA_OP_LIST[opName]["operands"] @@ -742,8 +744,8 @@ class TosaTensorValuesGen: ): # Change from inclusive to exclusive range data_range = (data_range[0], data_range[1] + 1) - # Ignore lazy data gen option and create data array using any range limits + # Ignore lazy data gen option and create data array using any range limits if "fixed_data" in argsDict and argsDict["fixed_data"][idx] is not None: if dtype == DType.SHAPE: arr = np.int64(argsDict["fixed_data"][idx]) @@ -756,7 +758,7 @@ class TosaTensorValuesGen: else: assert False, "Unsupported fixed_data type" else: - arr = testGen.getRandTensor(shape, dtype, data_range) + arr = rng.randTensor(shape, dtype, data_range) if roundMode: arr = np.round(arr) if idx < pCount: @@ -802,8 +804,7 @@ class TosaTensorValuesGen: info["data"] = [int(i) for i in argsDict["fixed_data"][idx]] tens_meta["fixed_data_info"] = info else: - # TODO - generate seed for this generator based on test - info["rng_seed"] = 42 + info["rng_seed"] = rng.seed data_range = None if "data_range_list" in argsDict: @@ -814,9 +815,7 @@ class TosaTensorValuesGen: data_range = argsDict["data_range"] if data_range is None: - data_range = testGen.getDTypeRange( - dtypeList[idx], high_inclusive=True - ) + data_range = rng.dTypeRange(dtypeList[idx], high_inclusive=True) info["range"] = [str(v) for v in data_range] tens_meta["pseudo_random_info"] = info elif dg_type == gtu.DataGenType.DOT_PRODUCT: @@ -836,7 +835,7 @@ class TosaTensorValuesGen: elif dg_type == gtu.DataGenType.FULL_RANGE: info = {} info["start_val"] = int( - testGen.randInt(0, gtu.DTYPE_ATTRIBUTES[dtypeList[idx]]["fullset"]) + rng.randInt(0, gtu.DTYPE_ATTRIBUTES[dtypeList[idx]]["fullset"]) ) tens_meta["full_range_info"] = info else: @@ -883,7 +882,9 @@ class TosaTensorValuesGen: return TosaTensorValuesGen.TVGInfo(tens_ser_list, tens_data) @staticmethod - def tvgNegate(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgNegate( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): if dtypeList[0] == DType.INT32 and error_name is None: # Integer test op = testGen.TOSA_OP_LIST[opName] @@ -896,7 +897,7 @@ class TosaTensorValuesGen: max_val = (1 << 31) - 1 min_val = -max_val arr = np.int32( - testGen.rng.integers(low=min_val, high=(max_val + 1), size=shapeList[0]) + rng.integers(low=min_val, high=(max_val + 1), size=shapeList[0]) ) tens_ser_list = [] tens_ser_list.append( @@ -906,7 +907,7 @@ class TosaTensorValuesGen: else: # ERROR_IF or floating point test return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) # Set the ADD/SUB data range to half the largest value to avoid infinities @@ -917,7 +918,9 @@ class TosaTensorValuesGen: } @staticmethod - def tvgAddSub(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgAddSub( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): if dtypeList[0] in (DType.INT32, DType.SHAPE) and error_name is None: # Make sure the integer operation does not cause value saturation - where # the number wraps due to limited number of bits to store the answer @@ -929,8 +932,8 @@ class TosaTensorValuesGen: tens_ser_list = [] add = op["op"] in (Op.ADD, Op.ADD_SHAPE) data_range = testGen.args.tensor_shape_range - a_arr = testGen.getRandTensor(shapeList[0], dtypeList[0], data_range) - b_arr = testGen.getRandTensor(shapeList[1], dtypeList[1], data_range) + a_arr = rng.randTensor(shapeList[0], dtypeList[0], data_range) + b_arr = rng.randTensor(shapeList[1], dtypeList[1], data_range) if add: res_arr = np.add(a_arr, b_arr, dtype=np.int64) else: @@ -985,18 +988,18 @@ class TosaTensorValuesGen: else: # ERROR_IF or floating point test data_range = TosaTensorValuesGen._get_data_range( - testGen, dtypeList[0], TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_ADDSUB + rng, dtypeList[0], TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_ADDSUB ) if data_range: argsDict["data_range"] = data_range return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod def tvgCondIfWhileLoop( - testGen, opName, dtypeList, shapeList, argsDict, error_name=None + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None ): if dtypeList[0] in ( DType.INT32, @@ -1012,11 +1015,9 @@ class TosaTensorValuesGen: tens_ser_list = [] for idx, shape in enumerate(shapeList[:]): if dtypeList[0] == DType.INT32: - arr = testGen.getRandTensor(shapeList[idx], DType.INT16) + arr = rng.randTensor(shapeList[idx], DType.INT16) else: - arr = np.int32( - testGen.rng.integers(low=0, high=32, size=shapeList[idx]) - ) + arr = np.int32(rng.integers(low=0, high=32, size=shapeList[idx])) if pRemain > 0: tens_ser_list.append( testGen.ser.addPlaceholder(shape, dtypeList[idx], arr) @@ -1030,12 +1031,12 @@ class TosaTensorValuesGen: return TosaTensorValuesGen.TVGInfo(tens_ser_list, None) else: return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod def tvgArithmeticRightShift( - testGen, opName, dtypeList, shapeList, argsDict, error_name=None + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None ): op = testGen.TOSA_OP_LIST[opName] pCount, cCount = op["operands"] @@ -1048,34 +1049,38 @@ class TosaTensorValuesGen: for idx, shape in enumerate(shapeList[:]): if idx == 1: if dtypeList[idx] == DType.INT8: - arr = np.int32(testGen.rng.integers(low=0, high=8, size=shape)) + arr = np.int32(rng.integers(low=0, high=8, size=shape)) elif dtypeList[idx] == DType.INT16: - arr = np.int32(testGen.rng.integers(low=0, high=16, size=shape)) + arr = np.int32(rng.integers(low=0, high=16, size=shape)) elif dtypeList[idx] == DType.INT32: - arr = np.int32(testGen.rng.integers(low=0, high=32, size=shape)) + arr = np.int32(rng.integers(low=0, high=32, size=shape)) elif error_name == ErrorIf.WrongInputType: - arr = np.int32(testGen.rng.integers(low=0, high=8, size=shape)) + arr = np.int32(rng.integers(low=0, high=8, size=shape)) else: raise Exception("OpArithmeticRightShift: invalid input dtype") else: - arr = testGen.getRandTensor(shape, dtypeList[idx]) + arr = rng.randTensor(shape, dtypeList[idx]) tens_ser_list.append(testGen.ser.addPlaceholder(shape, dtypeList[idx], arr)) return TosaTensorValuesGen.TVGInfo(tens_ser_list, None) @staticmethod - def tvgReshape(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgReshape( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): dtypeList[1] = DType.SHAPE shapeList[1] = [len(argsDict["new_shape"])] # Create a new list for the pre-generated data in argsDict["fixed_data"] argsDict["fixed_data"] = [None, argsDict["new_shape"]] return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgRescale(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgRescale( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): scale32 = argsDict["scale"] multiplier_arr = argsDict["multiplier"] shift_arr = argsDict["shift"] @@ -1091,11 +1096,11 @@ class TosaTensorValuesGen: argsDict["fixed_data"] = [None, multiplier_arr, shift_arr] return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgPad(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgPad(testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None): # argsDict["pad"] is 2D array, need to flatten it to get list of values pad_values = argsDict["pad"].flatten() dtypeList[1] = DType.SHAPE @@ -1104,11 +1109,11 @@ class TosaTensorValuesGen: argsDict["fixed_data"] = [None, pad_values] return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgSlice(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgSlice(testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None): dtypeList[1] = DType.SHAPE shapeList[1] = [len(argsDict["start"])] dtypeList[2] = DType.SHAPE @@ -1117,30 +1122,34 @@ class TosaTensorValuesGen: argsDict["fixed_data"] = [None, argsDict["start"], argsDict["size"]] return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgTile(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgTile(testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None): dtypeList[1] = DType.SHAPE shapeList[1] = [len(argsDict["multiples"])] argsDict["fixed_data"] = [None, argsDict["multiples"]] return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgSelect(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgSelect( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): # Set datatype of condition tensor to boolean dtypeList[0] = DType.BOOL return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgIntDiv(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgIntDiv( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): if error_name is None: op = testGen.TOSA_OP_LIST[opName] pCount, cCount = op["operands"] @@ -1154,8 +1163,8 @@ class TosaTensorValuesGen: # 1. divisor == 0 # 2. dividend == -(1<<31) and divisor == -1 while True: - dividend_arr = testGen.getRandTensor(shapeList[0], dtypeList[0]) - divisor_arr = testGen.getRandTensor(shapeList[1], dtypeList[1]) + dividend_arr = rng.randTensor(shapeList[0], dtypeList[0]) + divisor_arr = rng.randTensor(shapeList[1], dtypeList[1]) if (divisor_arr == 0).any(): continue @@ -1175,7 +1184,7 @@ class TosaTensorValuesGen: return TosaTensorValuesGen.TVGInfo(tens_ser_list, None) else: return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) # Set the MUL data range to the square root of the largest value @@ -1187,7 +1196,7 @@ class TosaTensorValuesGen: } @staticmethod - def tvgMul(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgMul(testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None): if error_name is not None or dtypeList[0] in ( DType.FP16, DType.BF16, @@ -1195,7 +1204,7 @@ class TosaTensorValuesGen: ): # ERROR_IF or floating point test data_range = TosaTensorValuesGen._get_data_range( - testGen, dtypeList[0], TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_MUL + rng, dtypeList[0], TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_MUL ) if data_range: argsDict["data_range"] = data_range @@ -1208,10 +1217,9 @@ class TosaTensorValuesGen: argsDict["fixed_data"] = [None, None, [argsDict["shift"]]] return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) else: - # Integer test op = testGen.TOSA_OP_LIST[opName] pCount, cCount = op["operands"] @@ -1231,7 +1239,9 @@ class TosaTensorValuesGen: elif error_name == ErrorIf.WrongInputType: num_bits = 8 else: - raise Exception("OpMul: invalid input dtype") + raise Exception( + f"OpMul: invalid input dtype {gtu.DTYPE_ATTRIBUTES[dtypeList[0]]['str']}" + ) for idx, shape in enumerate(shapeList[:]): if dtypeList[idx] == DType.SHAPE: @@ -1241,12 +1251,8 @@ class TosaTensorValuesGen: low = -(2 ** (num_bits - 1)) high = (2 ** (num_bits - 1)) - 1 - a_arr = np.int32( - testGen.rng.integers(low=low, high=high, size=shapeList[0]) - ) - b_arr = np.int32( - testGen.rng.integers(low=low, high=high, size=shapeList[1]) - ) + a_arr = np.int32(rng.integers(low=low, high=high, size=shapeList[0])) + b_arr = np.int32(rng.integers(low=low, high=high, size=shapeList[1])) i = 0 while True: @@ -1292,7 +1298,9 @@ class TosaTensorValuesGen: return TosaTensorValuesGen.TVGInfo(tens_ser_list, None) @staticmethod - def tvgConcat(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgConcat( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): count = len(shapeList) - testGen.args.num_const_inputs_concat if count < 1: count = 1 @@ -1302,12 +1310,10 @@ class TosaTensorValuesGen: op = testGen.TOSA_OP_LIST[opName] if op["op"] == Op.CONCAT_SHAPE: # Set the axis to 0 - shapeList = TosaTensorGen.tgConcatConstInput( - testGen, shapeList, 0, error_name - ) + shapeList = TosaTensorGen.tgConcatConstInput(rng, shapeList, 0, error_name) else: shapeList = TosaTensorGen.tgConcatConstInput( - testGen, shapeList, argsDict["axis"], error_name + rng, shapeList, argsDict["axis"], error_name ) # Override default pCount/cCount for operator @@ -1315,20 +1321,20 @@ class TosaTensorValuesGen: argsDict["c_count"] = len(shapeList) - count return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod def tvgLogicalShift( - testGen, opName, dtypeList, shapeList, argsDict, error_name=None + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None ): op = testGen.TOSA_OP_LIST[opName] pCount, cCount = op["operands"] assert ( pCount == 2 and cCount == 0 ), "Op.LOGICAL_LEFT_SHIFT or Op.LOGICAL_RIGHT_SHIFT must have 2 placeholders, 0 consts" - values_arr = testGen.getRandTensor(shapeList[0], dtypeList[0]) - shift_arr = np.int32(testGen.rng.integers(low=0, high=32, size=shapeList[1])) + values_arr = rng.randTensor(shapeList[0], dtypeList[0]) + shift_arr = np.int32(rng.integers(low=0, high=32, size=shapeList[1])) tens_ser_list = [] tens_ser_list.append( testGen.ser.addPlaceholder(shapeList[0], dtypeList[0], values_arr) @@ -1340,7 +1346,7 @@ class TosaTensorValuesGen: return TosaTensorValuesGen.TVGInfo(tens_ser_list, None) @staticmethod - def tvgEqual(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgEqual(testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None): if error_name is None and not gtu.dtypeIsSupportedByCompliance(dtypeList[0]): # Integer op = testGen.TOSA_OP_LIST[opName] @@ -1349,8 +1355,8 @@ class TosaTensorValuesGen: pCount == 2 and cCount == 0 ), "Op.EQUAL must have 2 placeholders, 0 consts" - a_arr = testGen.getRandTensor(shapeList[0], dtypeList[0]) - b_arr = testGen.getRandTensor(shapeList[1], dtypeList[1]) + a_arr = rng.randTensor(shapeList[0], dtypeList[0]) + b_arr = rng.randTensor(shapeList[1], dtypeList[1]) # Using random numbers means that it will be very unlikely that # there are any matching (equal) values, therefore force that @@ -1362,9 +1368,7 @@ class TosaTensorValuesGen: for axis in range(0, len(shapeList[0])): # Index can be up to the largest dimension in both shapes index = np.int32( - testGen.rng.integers( - 0, max(shapeList[0][axis], shapeList[1][axis]) - ) + rng.integers(0, max(shapeList[0][axis], shapeList[1][axis])) ) # Reduce the index down to a shape's dim for broadcasting a_index.append(min(shapeList[0][axis] - 1, index)) @@ -1383,11 +1387,13 @@ class TosaTensorValuesGen: else: # ERROR_IF or floating point test return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgReduceSum(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgReduceSum( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): dtype = dtypeList[0] if dtype == DType.INT32: op = testGen.TOSA_OP_LIST[opName] @@ -1399,7 +1405,7 @@ class TosaTensorValuesGen: # summation of any axis range_val = int((1 << 31) / max(shapeList[0])) values_arr = np.int32( - testGen.rng.integers(low=-range_val, high=range_val, size=shapeList[0]) + rng.integers(low=-range_val, high=range_val, size=shapeList[0]) ) tens_ser_list = [] tens_ser_list.append( @@ -1419,18 +1425,18 @@ class TosaTensorValuesGen: / max(shapeList[0]) } data_range = TosaTensorValuesGen._get_data_range( - testGen, dtype, highval_lookup + rng, dtype, highval_lookup ) assert data_range is not None argsDict["data_range"] = data_range return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod def tvgReduceProduct( - testGen, opName, dtypeList, shapeList, argsDict, error_name=None + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None ): dtype = dtypeList[0] if error_name is None: @@ -1442,20 +1448,20 @@ class TosaTensorValuesGen: 1 / max(shapeList[0]), ) } - data_range = TosaTensorValuesGen._get_data_range( - testGen, dtype, highval_lookup - ) + data_range = TosaTensorValuesGen._get_data_range(rng, dtype, highval_lookup) assert data_range is not None argsDict["data_range"] = data_range return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgResize(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgResize( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): data_range = TosaTensorValuesGen._get_data_range( - testGen, + rng, dtypeList[0], TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE, ) @@ -1476,7 +1482,7 @@ class TosaTensorValuesGen: argsDict["fixed_data"] = [None, scale_values, offset_values, border_values] return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) # Set the POW exponent high data range @@ -1537,10 +1543,10 @@ class TosaTensorValuesGen: } @staticmethod - def tvgPow(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgPow(testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None): if error_name is not None: return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) dtype = dtypeList[0] # Different ranges for POW @@ -1548,25 +1554,25 @@ class TosaTensorValuesGen: if test_set == 0: # Positive base with fractional exponent base_range = TosaTensorValuesGen._get_data_range( - testGen, + rng, dtype, TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_POW_BASE, TosaTensorValuesGen.TVG_FLOAT_LOW_VALUE_POW_BASE, ) exp_range = TosaTensorValuesGen._get_data_range( - testGen, dtype, TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_POW_EXP + rng, dtype, TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_POW_EXP ) exp_round = False else: # Integer exponent exp_range = TosaTensorValuesGen._get_data_range( - testGen, dtype, TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_POW_EXP + rng, dtype, TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_POW_EXP ) exp_round = True if test_set == 1: # Positive base base_range = TosaTensorValuesGen._get_data_range( - testGen, + rng, dtype, TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_POW_BASE, TosaTensorValuesGen.TVG_FLOAT_LOW_VALUE_POW_BASE, @@ -1576,7 +1582,7 @@ class TosaTensorValuesGen: # Negative base # Supply new look up tables with negative values base_range = TosaTensorValuesGen._get_data_range( - testGen, + rng, dtype, {dtype: -TosaTensorValuesGen.TVG_FLOAT_LOW_VALUE_POW_BASE[dtype]}, {dtype: -TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_POW_BASE[dtype]}, @@ -1593,15 +1599,17 @@ class TosaTensorValuesGen: ) argsDict["data_range_list"] = data_range_list return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgLogRsqrt(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgLogRsqrt( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): # LOG & RSQRT data range from lowest expressible positive number to # largest to avoid NaNs data_range = TosaTensorValuesGen._get_data_range( - testGen, + rng, dtypeList[0], TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE, TosaTensorValuesGen.TVG_FLOAT_LOW_VALUE, @@ -1610,7 +1618,7 @@ class TosaTensorValuesGen: argsDict["data_range"] = data_range return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) # Set the EXP data range to the log of the largest to smallest values @@ -1627,9 +1635,9 @@ class TosaTensorValuesGen: } @staticmethod - def tvgExp(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgExp(testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None): data_range = TosaTensorValuesGen._get_data_range( - testGen, + rng, dtypeList[0], TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE_EXP, TosaTensorValuesGen.TVG_FLOAT_LOW_VALUE_EXP, @@ -1638,12 +1646,12 @@ class TosaTensorValuesGen: argsDict["data_range"] = data_range return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod def tvgFullyConnected( - testGen, opName, dtypeList, shapeList, argsDict, error_name=None + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None ): dtype = dtypeList[0] if ( @@ -1658,26 +1666,24 @@ class TosaTensorValuesGen: highval_lookup = { dtype: math.pow(TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE[dtype], 1 / IC) } - data_range = TosaTensorValuesGen._get_data_range( - testGen, dtype, highval_lookup - ) + data_range = TosaTensorValuesGen._get_data_range(rng, dtype, highval_lookup) assert data_range is not None argsDict["data_range"] = data_range return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgCast(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgCast(testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None): in_dtype = dtypeList[0] out_dtype = argsDict["out_type"] # Create look up to limit input tensor to output type maximums to avoid # FP infinities and saturation of integers - out_range = testGen.getDTypeRange(out_dtype, high_inclusive=True) + out_range = rng.dTypeRange(out_dtype, high_inclusive=True) highval_lookup = {in_dtype: out_range[1]} data_range = TosaTensorValuesGen._get_data_range( - testGen, + rng, in_dtype, highval_lookup, ) @@ -1686,11 +1692,13 @@ class TosaTensorValuesGen: argsDict["data_range"] = data_range return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgGather(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgGather( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): K = shapeList[0][1] # Fix the type of the indices tensor @@ -1709,11 +1717,11 @@ class TosaTensorValuesGen: for idx, shape in enumerate(shapeList): dtype = dtypeList[idx] if idx != 1: - arr = testGen.getRandTensor(shape, dtype) + arr = rng.randTensor(shape, dtype) tens_ser_list.append(testGen.ser.addPlaceholder(shape, dtype, arr)) else: # Limit data range of indices tensor upto K (exclusive) - arr = testGen.getRandTensor(shape, dtype, (0, K)) + arr = rng.randTensor(shape, dtype, (0, K)) # To match old functionality - create indices as CONST tens_ser_list.append(testGen.ser.addConst(shape, dtype, arr)) @@ -1729,11 +1737,13 @@ class TosaTensorValuesGen: argsDict["data_range_list"] = data_range_list return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @staticmethod - def tvgScatter(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + def tvgScatter( + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name=None + ): K = shapeList[0][1] W = shapeList[2][1] @@ -1760,7 +1770,7 @@ class TosaTensorValuesGen: for idx, shape in enumerate(shapeList): dtype = dtypeList[idx] if idx != 1: - arr = testGen.getRandTensor(shape, dtype) + arr = rng.randTensor(shape, dtype) tens_ser_list.append(testGen.ser.addPlaceholder(shape, dtype, arr)) else: # Create the indices array @@ -1769,7 +1779,7 @@ class TosaTensorValuesGen: for n in range(shape[0]): # Get a shuffled list of output indices (0 to K-1) and # limit length to W - arr.append(testGen.rng.permutation(K)[:W]) + arr.append(rng.permutation(K)[:W]) indices_arr = np.array(arr, dtype=np.int32) # (N, W) # To match old functionality - create indices as CONST tens_ser_list.append( @@ -1789,7 +1799,7 @@ class TosaTensorValuesGen: argsDict["data_range_list"] = data_range_list return TosaTensorValuesGen.tvgLazyGenDefault( - testGen, opName, dtypeList, shapeList, argsDict, error_name + testGen, rng, opName, dtypeList, shapeList, argsDict, error_name ) @@ -1881,7 +1891,7 @@ class TosaArgGen: return new_arg_list @staticmethod - def agNone(testGen, opName, shapeList, dtype, error_name=None): + def agNone(testGen, rng, opName, shapeList, dtype, error_name=None): """A trivial argument generator for operators that don't take any non-tensor arguments""" arg_list = TosaArgGen._add_data_generators( @@ -1896,7 +1906,7 @@ class TosaArgGen: return arg_list @staticmethod - def agPow(testGen, opName, shapeList, dtype, error_name=None): + def agPow(testGen, rng, opName, shapeList, dtype, error_name=None): """Pow operator needs different test sets to cover random numbers without creating NaNs or Infs""" arg_list = TosaArgGen._add_data_generators( @@ -1911,17 +1921,17 @@ class TosaArgGen: return arg_list @staticmethod - def agAxis(testGen, opName, shapeList, dtype, error_name=None): + def agAxis(testGen, rng, opName, shapeList, dtype, error_name=None): """Build the axis argument for operators that take a single axis""" arg_list = [] shape = shapeList[0] if error_name == ErrorIf.AxisSmallerZero: # Set too small axis - axes = [testGen.rng.integers(-5, 0)] + axes = [rng.integers(-5, 0)] elif error_name == ErrorIf.AxisLargerRank: # Set too large axis - axes = [testGen.rng.integers(len(shape) + 1, len(shape) + 10)] + axes = [rng.integers(len(shape) + 1, len(shape) + 10)] else: # Create tests for each dimension axes = range(0, len(shape)) @@ -1967,7 +1977,7 @@ class TosaArgGen: return sparsity @staticmethod - def agConv(testGen, opName, shapeList, dtypes, error_name=None): + def agConv(testGen, rng, opName, shapeList, dtypes, error_name=None): # Used by CONV2D, CONV3D and DEPTHWISE_CONV2D arg_list = [] @@ -2005,13 +2015,13 @@ class TosaArgGen: # Generate comprehensive argument lists # - except for named errors, which use specific invalid value(s) if error_name == ErrorIf.PadSmallerZero: - p_vals = [testGen.rng.choice(range(-5, 0))] + p_vals = [rng.choice(range(-5, 0))] else: p_vals = [x for x in range(0, testGen.args.max_conv_padding + 1)] paddings = {x for x in itertools.product(*([p_vals] * k_rank * 2))} if error_name == ErrorIf.StrideSmallerOne: # Can't use stride=0, as it is used to derive output shape, as a divisor - s_vals = [testGen.rng.choice(range(-5, 0))] + s_vals = [rng.choice(range(-5, 0))] else: # Stride must be greater than 1 to force non-integer error startStride = ( @@ -2022,7 +2032,7 @@ class TosaArgGen: ] strides = {x for x in itertools.product(*([s_vals] * k_rank))} if error_name == ErrorIf.DilationSmallerOne: - d_vals = [testGen.rng.choice(range(-5, 1))] + d_vals = [rng.choice(range(-5, 1))] else: d_vals = [x for x in range(1, testGen.args.max_conv_dilation + 1)] dilations = {x for x in itertools.product(*([d_vals] * k_rank))} @@ -2195,13 +2205,13 @@ class TosaArgGen: return arg_list @staticmethod - def agFullyConnected(testGen, opName, shapeList, dtypes, error_name=None): + def agFullyConnected(testGen, rng, opName, shapeList, dtypes, error_name=None): assert isinstance(dtypes, (list, tuple)), f"{dtypes} unexpected" input_dtype = dtypes[0] if error_name == ErrorIf.WrongOutputType: - accum_dtype = gtu.get_wrong_output_type(opName, testGen.rng, input_dtype) + accum_dtype = gtu.get_wrong_output_type(opName, rng, input_dtype) elif error_name == ErrorIf.WrongInputType: # Pick some potentially correct output dtype if input type is incorrect accum_dtype = DType.INT32 @@ -2230,7 +2240,7 @@ class TosaArgGen: return arg_list @staticmethod - def agMatMul(testGen, opName, shapeList, dtype, error_name=None): + def agMatMul(testGen, rng, opName, shapeList, dtype, error_name=None): # Get valid accumulate type(s) if dtype == DType.INT8: accum_dtypes = [DType.INT32] @@ -2249,7 +2259,7 @@ class TosaArgGen: if error_name == ErrorIf.WrongOutputType: # Get incorrect output dtype for ErrorIf case - accum_dtypes = [gtu.get_wrong_output_type(opName, testGen.rng, dtype)] + accum_dtypes = [gtu.get_wrong_output_type(opName, rng, dtype)] elif error_name == ErrorIf.WrongInputType: # Pick some potentially correct output dtype if input type is incorrect accum_dtypes = [DType.INT32] @@ -2283,7 +2293,7 @@ class TosaArgGen: return arg_list @staticmethod - def agTransposeConv2D(testGen, opName, shapeList, dtypes, error_name=None): + def agTransposeConv2D(testGen, rng, opName, shapeList, dtypes, error_name=None): arg_list = [] if testGen.args.level8k and error_name is not None: @@ -2310,9 +2320,7 @@ class TosaArgGen: smallest_padding_size = -min(k_shape[0], k_shape[1]) + 1 if error_name == ErrorIf.PadLargerEqualKernel: max_filter_size = -max(k_shape[0], k_shape[1]) - p_vals = [ - testGen.rng.choice(range(max_filter_size - 10, max_filter_size)) - ] + p_vals = [rng.choice(range(max_filter_size - 10, max_filter_size))] else: p_vals = [ x @@ -2323,7 +2331,7 @@ class TosaArgGen: paddings = {x for x in itertools.product(*([p_vals] * 4))} if error_name == ErrorIf.StrideSmallerOne: # Can't use stride=0, as it is used to derive output shape, as a divisor - s_vals = [testGen.rng.choice(range(-5, 0))] + s_vals = [rng.choice(range(-5, 0))] else: s_vals = [x for x in range(1, testGen.args.max_conv_stride + 1)] strides = {x for x in itertools.product(*([s_vals] * 2))} @@ -2440,7 +2448,7 @@ class TosaArgGen: return arg_list @staticmethod - def agPad(testGen, opName, shapeList, dtype, error_name=None): + def agPad(testGen, rng, opName, shapeList, dtype, error_name=None): rank = len(shapeList[0]) # Exhaustively test combinations of padding on each side of each dimension @@ -2454,11 +2462,11 @@ class TosaArgGen: shape_pad_values = itertools.product(*([axis_pad_values] * rank)) if dtype in [DType.BOOL, DType.INT8, DType.INT16, DType.INT32]: - pad_const_int = testGen.getRandNumberDType(dtype) + pad_const_int = rng.randNumberDType(dtype) pad_const_fp = 0 elif gtu.dtypeIsFloat(dtype): pad_const_int = 0 - pad_const_fp = testGen.getRandNumberDType(dtype) + pad_const_fp = rng.randNumberDType(dtype) else: return [] @@ -2516,7 +2524,7 @@ class TosaArgGen: return arg_list @staticmethod - def agPooling(testGen, opName, shapeList, dtype, error_name=None): + def agPooling(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] shape = shapeList[0] @@ -2658,7 +2666,7 @@ class TosaArgGen: ErrorIf.PadLargerEqualKernel, ]: sNew, pNew, kNew = TosaErrorIfArgGen.eiPoolingErrorIf( - testGen, error_name, s, p, k + rng, error_name, s, p, k ) if None not in [sNew, pNew, kNew] and n % sparsity == 0: arg_list.append( @@ -2722,12 +2730,12 @@ class TosaArgGen: return arg_list @staticmethod - def agCast(testGen, opName, shapeList, inDtype, error_name=None): + def agCast(testGen, rng, opName, shapeList, inDtype, error_name=None): arg_list = [] # Enumerate the output types here if error_name == ErrorIf.WrongOutputType: - dtypeList = TosaErrorIfArgGen.eiCastErrorIf(testGen, inDtype) + dtypeList = TosaErrorIfArgGen.eiCastErrorIf(inDtype) elif inDtype == DType.INT8: dtypeList = [ DType.BOOL, @@ -2811,7 +2819,7 @@ class TosaArgGen: return arg_list @staticmethod - def agRescale(testGen, opName, shapeList, inDtype, error_name=None): + def agRescale(testGen, rng, opName, shapeList, inDtype, error_name=None): arg_list = [] # Enumerate the output types here @@ -2906,7 +2914,7 @@ class TosaArgGen: # Calculate scale based on: # scale = a *(2^output_width)/(2^input_width)) - a = np.float32(testGen.rng.random(size=[nc])) + a = np.float32(rng.random(size=[nc])) scale_arr = a * np.float32( (1 << out_type_width) / (1 << in_type_width) ) @@ -2965,13 +2973,13 @@ class TosaArgGen: return arg_list @staticmethod - def agMul(testGen, opName, shapeList, dtype, error_name=None): + def agMul(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] if dtype is DType.INT32: for p in range(testGen.args.num_rand_permutations): - shift = testGen.randInt(0, 32) + shift = rng.randInt(0, 32) arg_list.append(("perm{}_shift{}".format(p, shift), {"shift": shift})) else: arg_list.append(("perm0_shift0", {"shift": 0})) @@ -2988,7 +2996,7 @@ class TosaArgGen: return arg_list @staticmethod - def agArithmeticRightShift(testGen, opName, shapeList, dtype, error_name=None): + def agArithmeticRightShift(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] for round in (True, False): @@ -3009,7 +3017,7 @@ class TosaArgGen: return arg_list @staticmethod - def agFFT2d(testGen, opName, shapeList, dtype, error_name=None): + def agFFT2d(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] shape = shapeList[0] @@ -3037,7 +3045,7 @@ class TosaArgGen: return arg_list @staticmethod - def agRFFT2d(testGen, opName, shapeList, dtype, error_name=None): + def agRFFT2d(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] shape = shapeList[0] @@ -3074,7 +3082,7 @@ class TosaArgGen: return factors @staticmethod - def agReshape(testGen, opName, shapeList, dtype, error_name=None): + def agReshape(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] origShape = shapeList[0] @@ -3085,7 +3093,7 @@ class TosaArgGen: # This code is NOT fast. Fortunately, the numbers are fairly small. for p in range(testGen.args.num_rand_permutations): # Rank from 1 to TOSA_TENSOR_MAX_RANK - newRank = testGen.randInt(1, (testGen.TOSA_TENSOR_MAX_RANK + 1)) + newRank = rng.randInt(1, (testGen.TOSA_TENSOR_MAX_RANK + 1)) if len(factors) < newRank: continue @@ -3095,12 +3103,12 @@ class TosaArgGen: # Generate the new shape of the chosen new rank newShape = [] remainingElements = totalElements - shuffledFactors = testGen.rng.permutation(factors) + shuffledFactors = rng.permutation(factors) for i in range(1, newRank): # pick rank-1 factors newShape.append(shuffledFactors[0]) remainingElements = remainingElements // shuffledFactors[0] - shuffledFactors = testGen.rng.permutation( + shuffledFactors = rng.permutation( TosaArgGen.getFactors(remainingElements) ) newShape.append(remainingElements) @@ -3136,7 +3144,7 @@ class TosaArgGen: return arg_list @staticmethod - def agTranspose(testGen, opName, shapeList, dtype, error_name=None): + def agTranspose(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] ifm_shape = shapeList[0] @@ -3151,7 +3159,7 @@ class TosaArgGen: elif error_name == ErrorIf.IndexUsedTwice: # Create list with a duplicated index perm_range = list(range(len(ifm_shape))) - index_choice = testGen.rng.choice(range(len(perm_range))) + index_choice = rng.choice(range(len(perm_range))) perm_range[(index_choice + 1) % len(perm_range)] = perm_range[index_choice] permutations = [p for p in itertools.permutations(perm_range)] @@ -3163,7 +3171,7 @@ class TosaArgGen: limit = min(len(permutations), testGen.args.num_rand_permutations) # Get random permutation generator that uses all permutations - random_permutations = testGen.rng.permutation(permutations) + random_permutations = rng.permutation(permutations) # Create list of required amount of permutations arg_list = [ @@ -3183,7 +3191,7 @@ class TosaArgGen: return arg_list @staticmethod - def agSlice(testGen, opName, shapeList, dtype, error_name=None): + def agSlice(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] ifm_shape = shapeList[0] @@ -3197,8 +3205,8 @@ class TosaArgGen: for i in range(rank): if ifm_shape[i] > 1: - start.append(testGen.randInt(0, ifm_shape[i])) - size.append(testGen.randInt(0, ifm_shape[i] - start[i])) + start.append(rng.randInt(0, ifm_shape[i])) + size.append(rng.randInt(0, ifm_shape[i] - start[i])) # Invalid slice size? if size[i] == 0: @@ -3210,7 +3218,7 @@ class TosaArgGen: if valid: # If ERROR_IF test required then incorrect start, size will be returned start, size = TosaErrorIfArgGen.eiSliceErrorIf( - testGen, error_name, ifm_shape, start, size + rng, error_name, ifm_shape, start, size ) arg_list.append(("perm{}".format(p), {"start": start, "size": size})) # Now add data generator types @@ -3226,7 +3234,7 @@ class TosaArgGen: return arg_list @staticmethod - def agTile(testGen, opName, shapeList, dtype, error_name=None): + def agTile(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] ifm_shape = shapeList[0] @@ -3246,7 +3254,7 @@ class TosaArgGen: elif max(ifm_shape) > 1000: multiples.append(2) else: - multiples.append(testGen.randInt(1, 4)) + multiples.append(rng.randInt(1, 4)) arg_list.append(("perm{}".format(p), {"multiples": multiples})) # Now add data generator types @@ -3262,15 +3270,15 @@ class TosaArgGen: return arg_list @staticmethod - def agResize(testGen, opName, shapeList, dtype, error_name=None): + def agResize(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] ifm_shape = shapeList[0] 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)) + aspect_ratio = rng.choice(common_aspect_ratios) + invert = rng.choice((False, True)) + letterbox = 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] @@ -3279,13 +3287,13 @@ class TosaArgGen: if letterbox: max_border = scale_y_n - border_y = testGen.randInt(low=0, high=max_border) + border_y = rng.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) + border_x = rng.randInt(low=0, high=max_border) scale = (scale_y_n, scale_y_d, scale_x_n, scale_x_d) offset = (offset_y, offset_x) @@ -3296,13 +3304,13 @@ class TosaArgGen: def get_upscale_downscale_params(): valid_params = False while not valid_params: - upscale = testGen.rng.choice((False, True)) + upscale = rng.choice((False, True)) # True if sampling begins from (0,0). Otherwise (-0.5,-0.5) - origin_sampling = testGen.rng.choice((False, True)) + origin_sampling = rng.choice((False, True)) if upscale: - shift = testGen.randInt(low=1, high=4) + shift = rng.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 @@ -3328,16 +3336,16 @@ class TosaArgGen: if not valid_scale_y_ds: scale_y_d = 1 else: - scale_y_d = testGen.rng.choice(valid_scale_y_ds) + scale_y_d = 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) + scale_x_d = 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) + offset_y = rng.randInt(0, 16 * scale_y_n) + offset_x = rng.randInt(0, 16 * scale_x_n) valid_params = True scale = (scale_y_n, scale_y_d, scale_x_n, scale_x_d) @@ -3356,11 +3364,11 @@ class TosaArgGen: return scale_d # Scale - scale_y_n = testGen.randInt(low=1, high=(1 << 11)) - scale_x_n = testGen.randInt(low=1, high=(1 << 11)) + scale_y_n = rng.randInt(low=1, high=(1 << 11)) + scale_x_n = rng.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)) + scale_y_d = rng.randInt(low=1, high=(16 * scale_y_n)) + scale_x_d = rng.randInt(low=1, high=(16 * scale_x_n)) scale_y_d = fix_scale_to_max_scale( scale_y_n, scale_y_d, testGen.TOSA_8K_LEVEL_MAX_SCALE @@ -3370,10 +3378,10 @@ class TosaArgGen: ) # 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) + offset_y = rng.randInt(low=-scale_y_n, high=(16 * scale_y_n)) + offset_x = rng.randInt(low=-scale_x_n, high=(16 * scale_x_n)) + border_y = rng.randInt(low=(-16 * scale_y_n), high=scale_y_n) + border_x = rng.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) @@ -3382,24 +3390,24 @@ class TosaArgGen: def get_level_8k_params(): # Create 64x scale - 64/1 to 2048/32 - scale_d = testGen.randInt( + scale_d = rng.randInt( low=1, high=(1 << 11) / testGen.TOSA_8K_LEVEL_MAX_SCALE ) scale_n = scale_d * testGen.TOSA_8K_LEVEL_MAX_SCALE # Create half to fifth scaling - scale_d_alt = testGen.randInt(low=2, high=6) + scale_d_alt = rng.randInt(low=2, high=6) scale_n_alt = 1 - switch = testGen.rng.choice((False, True)) + switch = rng.choice((False, True)) if switch: scale = (scale_n_alt, scale_d_alt, scale_n, scale_d) else: scale = (scale_n, scale_d, scale_n_alt, scale_d_alt) - offset_y = testGen.rng.choice((-scale[0], 0, (16 * scale[0]) - 1)) - offset_x = testGen.rng.choice((-scale[2], 0, (16 * scale[2]) - 1)) + offset_y = rng.choice((-scale[0], 0, (16 * scale[0]) - 1)) + offset_x = rng.choice((-scale[2], 0, (16 * scale[2]) - 1)) offset = (offset_y, offset_x) - border_y = testGen.rng.choice((-16 * scale[0], 0, scale[0] - 1)) - border_x = testGen.rng.choice((-16 * scale[2], 0, scale[2] - 1)) + border_y = rng.choice((-16 * scale[0], 0, scale[0] - 1)) + border_x = rng.choice((-16 * scale[2], 0, scale[2] - 1)) border = (border_y, border_x) return scale, offset, border @@ -3437,7 +3445,7 @@ class TosaArgGen: while perm < testGen.args.num_rand_permutations: # Random choice of type of params we are testing if not testGen.args.level8k: - _rnd_param_fn = testGen.rng.choice( + _rnd_param_fn = rng.choice( ( get_rand_params, get_upscale_downscale_params, @@ -3541,7 +3549,7 @@ class TosaArgGen: border, outputDTypeNew, ) = TosaErrorIfArgGen.eiResizeErrorIf( - testGen, + rng, error_name, mode, dtype, @@ -3596,17 +3604,13 @@ class TosaArgGen: return arg_list @staticmethod - def agTable(testGen, opName, shapeList, dtype, error_name=None): + def agTable(testGen, rng, opName, shapeList, dtype, error_name=None): arg_list = [] if dtype == DType.INT8: - table = np.int32( - testGen.rng.integers(low=-128, high=128, size=[256]) - ).tolist() + table = np.int32(rng.integers(low=-128, high=128, size=[256])).tolist() else: # INT16 - table = np.int32( - testGen.rng.integers(low=-32768, high=32768, size=[513]) - ).tolist() + table = np.int32(rng.integers(low=-32768, high=32768, size=[513])).tolist() # Make sure all slopes are within REQUIRE min/max 16-bit int for idx in range(len(table) - 1): slope = table[idx + 1] - table[idx] @@ -3635,7 +3639,7 @@ class TosaArgGen: # Return list of tuples: (arg_str, args_dict) return arg_list - def agCondIf(testGen, opName, shapeList, dtype, error_name=None): + def agCondIf(testGen, rng, opName, shapeList, dtype, error_name=None): # CondIf generates the condition values here. # Convert to tensors in the build function, along with the # then and else blocks @@ -3656,7 +3660,7 @@ class TosaArgGen: # Return list of tuples: (arg_str, args_dict) return arg_list - def agWhileLoop(testGen, opName, shapeList, dtype, error_name=None): + def agWhileLoop(testGen, rng, opName, shapeList, dtype, error_name=None): # While loop: 0 iterations, 1, more than 1 arg_list = [] diff --git a/verif/generator/tosa_error_if.py b/verif/generator/tosa_error_if.py index 3972edd..e557f06 100644 --- a/verif/generator/tosa_error_if.py +++ b/verif/generator/tosa_error_if.py @@ -94,7 +94,7 @@ class ErrorIf(object): class TosaErrorIfArgGen: @staticmethod def eiResizeErrorIf( - testGen, + rng, error_name, mode, dtype, @@ -105,28 +105,28 @@ class TosaErrorIfArgGen: border, ): if error_name == ErrorIf.ScaleSmallerEqualZero: - index = testGen.randInt(low=0, high=4) - scale[index] = testGen.rng.choice([-2, -1, 0]) + index = rng.randInt(low=0, high=4) + scale[index] = rng.choice([-2, -1, 0]) elif error_name == ErrorIf.ScaleNLargerMax: - index = testGen.rng.choice([0, 2]) - scale[index] = (1 << 11) + testGen.rng.choice([1, 2, 3]) + index = rng.choice([0, 2]) + scale[index] = (1 << 11) + rng.choice([1, 2, 3]) elif error_name == ErrorIf.ScaleDLargerMax: - index = testGen.rng.choice([1, 3]) - scale[index] = 16 * scale[index - 1] + testGen.rng.choice([0, 1, 2]) + index = rng.choice([1, 3]) + scale[index] = 16 * scale[index - 1] + rng.choice([0, 1, 2]) if error_name == ErrorIf.OffsetLargerEqualMax: - index = testGen.rng.choice([0, 1]) - offset[index] = 16 * scale[index * 2] + testGen.rng.choice([0, 1, 2]) + index = rng.choice([0, 1]) + offset[index] = 16 * scale[index * 2] + rng.choice([0, 1, 2]) elif error_name == ErrorIf.OffsetSmallerMin: - index = testGen.rng.choice([0, 1]) - offset[index] = -scale[index * 2] - testGen.rng.choice([1, 2, 3]) + index = rng.choice([0, 1]) + offset[index] = -scale[index * 2] - rng.choice([1, 2, 3]) if error_name == ErrorIf.BorderLargerEqualMax: - index = testGen.rng.choice([0, 1]) - border[index] = scale[index * 2] + testGen.rng.choice([0, 1, 2]) + index = rng.choice([0, 1]) + border[index] = scale[index * 2] + rng.choice([0, 1, 2]) elif error_name == ErrorIf.BorderSmallerMin: - index = testGen.rng.choice([0, 1]) - border[index] = -16 * scale[index * 2] - testGen.rng.choice([1, 2, 3]) + index = rng.choice([0, 1]) + border[index] = -16 * scale[index * 2] - rng.choice([1, 2, 3]) if error_name == ErrorIf.WrongOutputType: if mode == ResizeMode.NEAREST and dtype == DType.INT8: @@ -192,12 +192,12 @@ class TosaErrorIfArgGen: DType.INT48, DType.FP16, ) - outputDType = testGen.rng.choice(a=incorrect_types) + outputDType = rng.choice(a=incorrect_types) return scale, offset, border, outputDType @staticmethod - def eiPoolingErrorIf(testGen, error_name, stride, pad, kernel): + def eiPoolingErrorIf(rng, error_name, stride, pad, kernel): if ( error_name == ErrorIf.StrideSmallerOne # padding must not exceed the kernel size @@ -207,30 +207,30 @@ class TosaErrorIfArgGen: and pad[3] < kernel[1] ): wrongStride = ( - testGen.rng.choice([0, -1, -2, -3]), - testGen.rng.choice([0, -1, -2, -3]), + rng.choice([0, -1, -2, -3]), + rng.choice([0, -1, -2, -3]), ) return wrongStride, pad, kernel elif error_name == ErrorIf.PadSmallerZero: wrongPad = ( - testGen.rng.choice([-1, -2, -3]), - testGen.rng.choice([-1, -2, -3]), - testGen.rng.choice([-1, -2, -3]), - testGen.rng.choice([-1, -2, -3]), + rng.choice([-1, -2, -3]), + rng.choice([-1, -2, -3]), + rng.choice([-1, -2, -3]), + rng.choice([-1, -2, -3]), ) return stride, wrongPad, kernel elif error_name == ErrorIf.KernelSmallerOne: wrongKernel = ( - testGen.rng.choice([0, -1, -2, -3]), - testGen.rng.choice([0, -1, -2, -3]), + rng.choice([0, -1, -2, -3]), + rng.choice([0, -1, -2, -3]), ) return stride, pad, wrongKernel elif error_name == ErrorIf.PadLargerEqualKernel: wrongPad = ( - testGen.rng.choice([kernel[0], kernel[0] + 1, kernel[0] + 2]), - testGen.rng.choice([kernel[0], kernel[0] + 1, kernel[0] + 2]), - testGen.rng.choice([kernel[1], kernel[1] + 1, kernel[1] + 2]), - testGen.rng.choice([kernel[1], kernel[1] + 1, kernel[1] + 2]), + rng.choice([kernel[0], kernel[0] + 1, kernel[0] + 2]), + rng.choice([kernel[0], kernel[0] + 1, kernel[0] + 2]), + rng.choice([kernel[1], kernel[1] + 1, kernel[1] + 2]), + rng.choice([kernel[1], kernel[1] + 1, kernel[1] + 2]), ) return stride, wrongPad, kernel else: @@ -265,16 +265,16 @@ class TosaErrorIfArgGen: return False @staticmethod - def eiInvalidateInputOutputList(testGen, error_name, input_list, output_list): + def eiInvalidateInputOutputList(rng, error_name, input_list, output_list): # Mess up input/output tensors for ERROR_IF checks if error_name == "WrongInputList": - add_input = testGen.rng.choice([True, False]) + add_input = rng.choice([True, False]) if add_input: input_list.append("eiDummyInput") else: input_list = input_list[:-1] elif error_name == "WrongOutputList": - add_output = testGen.rng.choice([True, False]) + add_output = rng.choice([True, False]) if add_output: output_list.append("eiDummyOutput") else: @@ -291,25 +291,25 @@ class TosaErrorIfArgGen: new_shape = [max(d - 1, 1) for d in new_shape] return new_shape - def eiSliceErrorIf(testGen, error_name, input_shape, start, size): + def eiSliceErrorIf(rng, error_name, input_shape, start, size): if error_name == ErrorIf.StartSmallerZero: newStart = [] for i in range(len(input_shape)): - newStart.append(testGen.rng.choice([-3, -2, -1])) + newStart.append(rng.choice([-3, -2, -1])) return newStart, size elif error_name == ErrorIf.SizeSmallerEqualZero: newSize = [] for i in range(len(input_shape)): - newSize.append(testGen.rng.choice([-3, -2, -1, 0])) + newSize.append(rng.choice([-3, -2, -1, 0])) return start, newSize elif error_name == ErrorIf.StartSizeOutsideBounds: newStart, newSize = [], [] for i in range(len(input_shape)): newStart.append(input_shape[i] - 1) - newSize.append(testGen.rng.choice([2, 3, 4])) + newSize.append(rng.choice([2, 3, 4])) return newStart, newSize elif error_name == ErrorIf.InputSizeStartLengthMismatch: - remove = testGen.rng.choice([True, False]) + remove = rng.choice([True, False]) # Get an empty tensor when diminishing dimension on 1-d tensor. if len(start) == 1 or len(size) == 1: @@ -328,9 +328,7 @@ class TosaErrorIfArgGen: return start, size @staticmethod - def eiCastErrorIf(testGen, input_dtype): - # if input_dtype in [DType.BOOL, DType.FP32]: - # outputDType = [DType.BOOL, DType.INT48, DType.FP32] + def eiCastErrorIf(input_dtype): if input_dtype in [DType.BOOL]: outputDType = [ DType.BOOL, diff --git a/verif/generator/tosa_random_gen.py b/verif/generator/tosa_random_gen.py new file mode 100644 index 0000000..ae8ae5c --- /dev/null +++ b/verif/generator/tosa_random_gen.py @@ -0,0 +1,174 @@ +# Copyright (c) 2024, ARM Limited. +# SPDX-License-Identifier: Apache-2.0 +import hashlib +import logging + +import generator.tosa_utils as gtu +import numpy as np +from tosa.DType import DType + +logging.basicConfig() +logger = logging.getLogger("tosa_verif_build_tests") + + +class TosaRandomGenerator(np.random.Generator): + """Equivalent to numpy.default_rng, with support for TOSA data types""" + + def __init__(self, seed, restrict_range_by_type={}): + """Create random generator with TOSA type support. + + seed: integer seed + restrict_range_by_type: see TosaHashRandomGenerator.__init__() + """ + self._restrict_range_by_type = restrict_range_by_type + self._seed = int(seed) + self._bitgen = np.random.PCG64(self._seed) + super().__init__(self._bitgen) + + @property + def seed(self): + return self._seed + + @property + def hexSeed(self): + return hex(self._seed) + + def dTypeRange(self, dtype, high_inclusive=False): + """Returns range tuple for given dtype. + + dtype: DType + high_inclusive: True for inclusive high values + Returns: dtype value range boundaries tuple (low, high) + The high boundary is excluded in the range unless high_inclusive is True + """ + if dtype in self._restrict_range_by_type: + rng = self._restrict_range_by_type[dtype] + elif dtype == DType.BOOL: + rng = (0, 2) + elif dtype == DType.UINT8: + rng = (0, 256) + elif dtype == DType.UINT16: + rng = (0, 65536) + elif dtype == DType.INT4: + # TOSA specific INT4 weight range from -7 to 7 + rng = (-7, 8) + elif dtype == DType.INT8: + rng = (-128, 128) + elif dtype == DType.INT16: + rng = (-32768, 32768) + elif dtype == DType.INT32: + rng = (-(1 << 31), (1 << 31)) + elif dtype == DType.INT48: + rng = (-(1 << 47), (1 << 47)) + else: + # Float types and SHAPE should be in _restrict_range_by_type dict + raise Exception("Unknown supported dtype: {}".format(dtype)) + + if dtype in (DType.FP16, DType.BF16, DType.FP32, DType.FP8E4M3, DType.FP8E5M2): + # Floating point - range is always inclusive + return rng + else: + # Integer + if not high_inclusive: + # Exclusive high: low <= range < high + return rng + else: + # Inclusive range: low <= range <= high + return (rng[0], rng[1] - 1) + + def randInt(self, low=0, high=256): + return np.int32(self.integers(low=low, high=high, size=1))[0] + + def randNumberDType(self, dtype): + low, high = self.dTypeRange(dtype) + + if dtype == DType.FP32: + return np.float32(self.uniform(low=low, high=high)) + elif dtype == DType.FP16: + return np.float16(self.uniform(low=low, high=high)) + elif dtype == DType.BF16: + rand_f32 = np.float32(self.uniform(low=low, high=high)) + return gtu.vect_f32_to_bf16(rand_f32) + elif dtype == DType.FP8E4M3: + rand_f32 = np.float32(self.uniform(low=low, high=high)) + return gtu.vect_f32_to_fp8e4m3(rand_f32) + elif dtype == DType.FP8E5M2: + rand_f32 = np.float32(self.uniform(low=low, high=high)) + return gtu.vect_f32_to_fp8e5m2(rand_f32) + elif dtype == DType.BOOL: + return self.choice([False, True]) + elif dtype == DType.INT48 or dtype == DType.SHAPE: + # Special size + return np.int64(self.integers(low, high, size=1))[0] + + return np.int32(self.integers(low, high, size=1))[0] + + def randTensor(self, shape, dtype, data_range=None): + if data_range is None: + low, high = self.dTypeRange(dtype) + else: + low, high = data_range + + if dtype == DType.BOOL: + return np.bool_(self.choice(a=[False, True], size=shape)) + elif dtype == DType.INT4: + return np.int8(self.integers(low=low, high=high, size=shape)) + elif dtype == DType.INT8: + return np.int8(self.integers(low=low, high=high, size=shape)) + elif dtype == DType.UINT8: + return np.uint8(self.integers(low=low, high=high, size=shape)) + elif dtype == DType.INT16: + return np.int16(self.integers(low=low, high=high, size=shape)) + elif dtype == DType.UINT16: + return np.uint16(self.integers(low=low, high=high, size=shape)) + elif dtype in (DType.INT48, DType.SHAPE): + return np.int64(self.integers(low=low, high=high, size=shape)) + elif dtype in ( + DType.FP16, + DType.BF16, + DType.FP32, + DType.FP8E4M3, + DType.FP8E5M2, + ): + f_tensor = self.uniform(low=low, high=high, size=shape) + + if dtype == DType.FP16: + return np.float16(f_tensor) + else: + f32_tensor = np.float32(f_tensor) + if dtype == DType.BF16: + # Floor the last 16 bits of each f32 value + return np.float32(gtu.vect_f32_to_bf16(f32_tensor)) + elif dtype == DType.FP8E4M3: + return np.float32(gtu.vect_f32_to_fp8e4m3(f32_tensor)) + elif dtype == DType.FP8E5M2: + return np.float32(gtu.vect_f32_to_fp8e5m2(f32_tensor)) + else: + return f32_tensor + else: + # All other integer types + return np.int32(self.integers(low=low, high=high, size=shape)) + + +class TosaHashRandomGenerator(TosaRandomGenerator): + """Hash seeded TOSA random number generator.""" + + def __init__(self, seed, seed_list, restrict_range_by_type={}): + """Create TOSA random generator seeding it with a hashable list. + + seed: integer starting seed + seed_list: list of hashable items to add to starting seed + restrict_range_by_type: dictionary of DTypes with (low, high) range tuples + This must contain entries for SHAPE and all Floating Point data types. + NOTE: For integers, the high value must be the exclusive value + """ + # Convert seed_list to strings + seed_strings_list = [str(s) for s in seed_list] + # Create a single string and create hash + self._seed_string = "__".join(seed_strings_list) + self._hash = hashlib.md5(bytes(self._seed_string, "utf-8")) + # Add the hash value to the given seed + seed += int(self._hash.hexdigest(), 16) + + logger.debug(f"Seed={seed} Seed string={self._seed_string}") + super().__init__(seed, restrict_range_by_type) diff --git a/verif/generator/tosa_test_gen.py b/verif/generator/tosa_test_gen.py index 3173906..7702753 100644 --- a/verif/generator/tosa_test_gen.py +++ b/verif/generator/tosa_test_gen.py @@ -20,6 +20,8 @@ from generator.tosa_error_if import ErrorIf from generator.tosa_error_if import TosaErrorIfArgGen from generator.tosa_error_if import TosaErrorValidator from generator.tosa_error_if import TosaInvalidValidator +from generator.tosa_random_gen import TosaHashRandomGenerator +from generator.tosa_random_gen import TosaRandomGenerator from schemavalidation.schemavalidation import TestDescSchemaValidator from tosa.DType import DType from tosa.Op import Op @@ -50,10 +52,10 @@ class TosaTestGen: self.basePath = args.output_dir self.random_seed = args.random_seed self.ser = None - self.rng = np.random.default_rng(self.random_seed) self.createDynamicOpLists() self.initOpListDefaults() self.quantGen = TosaQuantGen() + self.global_rng = None # Force makeShape to do a specific starting shape self.targetted_shape = None # JSON schema validation @@ -80,12 +82,18 @@ class TosaTestGen: vals.append(v) return tuple(sorted(vals)) - self.random_float_range = {} + self.random_dtype_range = { + DType.SHAPE: tuple(self.args.tensor_shape_range[0:2]) + } for dtype in (DType.FP32, DType.FP16, DType.BF16, DType.FP8E4M3, DType.FP8E5M2): - self.random_float_range[dtype] = convertFPRange( + self.random_dtype_range[dtype] = convertFPRange( args.tensor_fp_value_range, TosaTensorValuesGen.TVG_FLOAT_HIGH_VALUE[dtype], ) + self.resetGlobalRNG() + + def resetGlobalRNG(self): + self.global_rng = TosaRandomGenerator(self.random_seed, self.random_dtype_range) def createSerializer(self, opName, testPath): self.testPath = os.path.join(opName, testPath) @@ -148,93 +156,7 @@ class TosaTestGen: with path_desc.open("w") as fd: json.dump(desc, fd, indent=1) - def resetRNG(self, seed=None): - if seed is None: - seed = self.random_seed + 1 - self.rng = np.random.default_rng(seed) - - def getDTypeRange(self, dtype, high_inclusive=False): - # Returns dtype value range boundaries (low, high) - # The high boundary is excluded in the range - # unless high_inclusive is True - if dtype in (DType.FP32, DType.FP16, DType.BF16, DType.FP8E4M3, DType.FP8E5M2): - return self.random_float_range[dtype] - elif dtype == DType.BOOL: - rng = (0, 2) - elif dtype == DType.UINT8: - rng = (0, 256) - elif dtype == DType.UINT16: - rng = (0, 65536) - elif dtype == DType.INT4: - # TOSA specific INT4 weight range from -7 to 7 - rng = (-7, 8) - elif dtype == DType.INT8: - rng = (-128, 128) - elif dtype == DType.INT16: - rng = (-32768, 32768) - elif dtype == DType.INT32: - rng = (-(1 << 31), (1 << 31)) - elif dtype == DType.SHAPE: - rng = tuple(self.args.tensor_shape_range[0:2]) - elif dtype == DType.INT48: - rng = (-(1 << 47), (1 << 47)) - else: - raise Exception("Unknown dtype: {}".format(dtype)) - - if not high_inclusive: - # Exclusive high: low <= range < high - return rng - else: - # Inclusive range: low <= range <= high - return (rng[0], rng[1] - 1) - - def getRandTensor(self, shape, dtype, data_range=None): - if data_range is None: - low, high = self.getDTypeRange(dtype) - else: - low, high = data_range - - if dtype == DType.BOOL: - return np.bool_(self.rng.choice(a=[False, True], size=shape)) - elif dtype == DType.INT4: - return np.int8(self.rng.integers(low=low, high=high, size=shape)) - elif dtype == DType.INT8: - return np.int8(self.rng.integers(low=low, high=high, size=shape)) - elif dtype == DType.UINT8: - return np.uint8(self.rng.integers(low=low, high=high, size=shape)) - elif dtype == DType.INT16: - return np.int16(self.rng.integers(low=low, high=high, size=shape)) - elif dtype == DType.UINT16: - return np.uint16(self.rng.integers(low=low, high=high, size=shape)) - elif dtype in (DType.INT48, DType.SHAPE): - return np.int64(self.rng.integers(low=low, high=high, size=shape)) - elif dtype in ( - DType.FP16, - DType.BF16, - DType.FP32, - DType.FP8E4M3, - DType.FP8E5M2, - ): - f_tensor = self.rng.uniform(low=low, high=high, size=shape) - - if dtype == DType.FP16: - return np.float16(f_tensor) - else: - f32_tensor = np.float32(f_tensor) - if dtype == DType.BF16: - # Floor the last 16 bits of each f32 value - return np.float32(gtu.vect_f32_to_bf16(f32_tensor)) - elif dtype == DType.FP8E4M3: - return np.float32(gtu.vect_f32_to_fp8e4m3(f32_tensor)) - elif dtype == DType.FP8E5M2: - return np.float32(gtu.vect_f32_to_fp8e5m2(f32_tensor)) - else: - return f32_tensor - else: - # All other integer types - return np.int32(self.rng.integers(low=low, high=high, size=shape)) - - def buildPlaceholderTensors(self, shape_list, dtype_list): + def buildPlaceholderTensors(self, rng, shape_list, dtype_list): placeholders = [] assert len(shape_list) == len(dtype_list) @@ -242,12 +164,12 @@ class TosaTestGen: arr = None for idx, shape in enumerate(shape_list): if not self.args.lazy_data_gen: - arr = self.getRandTensor(shape, dtype_list[idx]) + arr = rng.randTensor(shape, dtype_list[idx]) placeholders.append(self.ser.addPlaceholder(shape, dtype_list[idx], arr)) return placeholders - def buildConstTensors(self, shape_list, dtype_list): + def buildConstTensors(self, rng, shape_list, dtype_list): consts = [] assert len(shape_list) == len(dtype_list) @@ -255,16 +177,16 @@ class TosaTestGen: arr = None for idx, shape in enumerate(shape_list): if not self.args.lazy_data_gen: - arr = self.getRandTensor(shape, dtype_list[idx]) + arr = rng.randTensor(shape, dtype_list[idx]) consts.append(self.ser.addConst(shape, dtype_list[idx], arr)) return consts - def makeShape(self, rank): + def makeShape(self, rng, rank): if self.targetted_shape: return np.int32(self.targetted_shape) return np.int32( - self.rng.integers( + rng.integers( low=self.args.tensor_shape_range[0], high=self.args.tensor_shape_range[1], size=rank, @@ -274,33 +196,6 @@ class TosaTestGen: def setTargetShape(self, shape): self.targetted_shape = shape - def randInt(self, low=0, high=256): - return np.int32(self.rng.integers(low=low, high=high, size=1))[0] - - def getRandNumberDType(self, dtype): - low, high = self.getDTypeRange(dtype) - - if dtype == DType.FP32: - return np.float32(self.rng.uniform(low=low, high=high)) - elif dtype == DType.FP16: - return np.float16(self.rng.uniform(low=low, high=high)) - elif dtype == DType.BF16: - rand_f32 = np.float32(self.rng.uniform(low=low, high=high)) - return gtu.vect_f32_to_bf16(rand_f32) - elif dtype == DType.FP8E4M3: - rand_f32 = np.float32(self.rng.uniform(low=low, high=high)) - return gtu.vect_f32_to_fp8e4m3(rand_f32) - elif dtype == DType.FP8E5M2: - rand_f32 = np.float32(self.rng.uniform(low=low, high=high)) - return gtu.vect_f32_to_fp8e5m2(rand_f32) - elif dtype == DType.BOOL: - return self.rng.choice([False, True]) - elif dtype == DType.INT48 or dtype == DType.SHAPE: - # Special size - return np.int64(self.rng.integers(low, high, size=1))[0] - - return np.int32(self.rng.integers(low, high, size=1))[0] - def shapeStr(self, shape): sStr = [] @@ -330,8 +225,8 @@ class TosaTestGen: shape[0] = min(shape[0], self.args.max_batch_size) return shape - def makeDimension(self): - return self.randInt( + def makeDimension(self, rng): + return rng.randInt( low=self.args.tensor_shape_range[0], high=self.args.tensor_shape_range[1] ) @@ -445,11 +340,18 @@ class TosaTestGen: return compliance def build_unary( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 1 a = inputs[0] - result_tensor = OutputShaper.unaryOp(self.ser, self.rng, a, error_name) + result_tensor = OutputShaper.unaryOp(self.ser, rng, a, error_name) assert not isinstance(op, int) @@ -457,8 +359,10 @@ class TosaTestGen: if error_name == ErrorIf.WrongOutputType: if result_tensor.dtype not in [DType.INT8, DType.UINT8]: qinfo = [ - TosaQuantGen.getZeroPoint(self, a.dtype), - TosaQuantGen.getZeroPoint(self, result_tensor.dtype), + TosaQuantGen.getZeroPoint(rng, self.args.zeropoint, a.dtype), + TosaQuantGen.getZeroPoint( + rng, self.args.zeropoint, result_tensor.dtype + ), ] # Invalidate Input/Output list for error if checks. @@ -467,7 +371,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -498,13 +402,11 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_binary_broadcast( - self, op, inputs, args_dict, validator_fcns, error_name=None, qinfo=None + self, rng, op, inputs, args_dict, validator_fcns, error_name=None, qinfo=None ): assert len(inputs) == 2 a, b = inputs - result_tensor = OutputShaper.binaryBroadcastOp( - self.ser, self.rng, a, b, error_name - ) + result_tensor = OutputShaper.binaryBroadcastOp(self.ser, rng, a, b, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name, b.name] @@ -512,7 +414,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -539,20 +441,20 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) - def build_binary_nonbroadcast(self, op, a, b, validator_fcns=None, error_name=None): - result_tens = OutputShaper.binaryNonBroadcastOp(self.ser, a, b) - self.ser.addOperator(op["op"], [a.name, b.name], [result_tens.name]) - return result_tens - def build_arithmetic_right_shift( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 2 a, b = inputs round = args_dict["round"] - result_tensor = OutputShaper.binaryBroadcastOp( - self.ser, self.rng, a, b, error_name - ) + result_tensor = OutputShaper.binaryBroadcastOp(self.ser, rng, a, b, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name, b.name] @@ -560,7 +462,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -591,15 +493,20 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_mul( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): # Note that mul is binary operator but it has a shift value tensor assert len(inputs) == 3 a, b, s = inputs - result_tensor = OutputShaper.binaryBroadcastOp( - self.ser, self.rng, a, b, error_name - ) + result_tensor = OutputShaper.binaryBroadcastOp(self.ser, rng, a, b, error_name) # Special for multiply: Force the result to INT32 for INT types if a.dtype not in (DType.FP16, DType.BF16, DType.FP32): @@ -607,7 +514,7 @@ class TosaTestGen: if error_name == ErrorIf.WrongOutputType: all_dtypes = [DType.INT8, DType.INT16, DType.INT48] - outputDType = self.rng.choice(all_dtypes) + outputDType = rng.choice(all_dtypes) result_tensor.setDtype(outputDType) # Invalidate Input/Output list for error if checks. @@ -616,7 +523,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -644,12 +551,19 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_table( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 1 a = inputs[0] table = args_dict["table"] - result_tensor = OutputShaper.tableOp(self.ser, self.rng, a, error_name) + result_tensor = OutputShaper.tableOp(self.ser, rng, a, error_name) attr = ts.TosaSerializerAttribute() attr.TableAttribute(table) @@ -660,7 +574,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -687,14 +601,19 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_select( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 3 cond, a, b = inputs - result_tensor = OutputShaper.selectOp( - self.ser, self.rng, cond, a, b, error_name - ) + result_tensor = OutputShaper.selectOp(self.ser, rng, cond, a, b, error_name) # Invalidate Input/Output list for error if checks. input_list = [cond.name, a.name, b.name] @@ -702,7 +621,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -735,14 +654,19 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_comparison( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 2 a, b = inputs - result_tensor = OutputShaper.binaryComparisonOp( - self.ser, self.rng, a, b, error_name - ) + result_tensor = OutputShaper.binaryComparisonOp(self.ser, rng, a, b, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name, b.name] @@ -750,7 +674,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -783,12 +707,12 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_argmax( - self, op, inputs, args_dict, validator_fcns, error_name, qinfo=None + self, rng, op, inputs, args_dict, validator_fcns, error_name, qinfo=None ): assert len(inputs) == 1 a = inputs[0] axis = args_dict["axis"] - result_tensor = OutputShaper.argmaxOp(self.ser, self.rng, a, axis, error_name) + result_tensor = OutputShaper.argmaxOp(self.ser, rng, a, axis, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name] @@ -796,7 +720,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -828,6 +752,7 @@ class TosaTestGen: def build_pool2d( self, + rng, op, inputs, args_dict, @@ -846,15 +771,17 @@ class TosaTestGen: kernel = args_dict["kernel"] result_tensor = OutputShaper.pool2dOp( - self.ser, self.rng, input, kernel, stride, pad, error_name + self.ser, rng, input, kernel, stride, pad, error_name ) # Ensure new output type has correct qinfo if error_name == ErrorIf.WrongInputType: if input.dtype not in [DType.INT8, DType.UINT8]: qinfo = [ - TosaQuantGen.getZeroPoint(self, input.dtype), - TosaQuantGen.getZeroPoint(self, result_tensor.dtype), + TosaQuantGen.getZeroPoint(rng, self.args.zeropoint, input.dtype), + TosaQuantGen.getZeroPoint( + rng, self.args.zeropoint, result_tensor.dtype + ), ] # Invalidate Input/Output list for error if checks. @@ -863,7 +790,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -903,6 +830,7 @@ class TosaTestGen: def build_conv2d( self, + rng, op, inputs, args_dict, @@ -920,7 +848,7 @@ class TosaTestGen: assert len(padding) == 4 result_tensor = OutputShaper.conv2dOp( self.ser, - self.rng, + rng, ifm, filter, accum_dtype, @@ -936,8 +864,10 @@ class TosaTestGen: DType.UINT8, ): qinfo = [ - TosaQuantGen.getZeroPoint(self, ifm.dtype), - TosaQuantGen.getZeroPoint(self, result_tensor.dtype), + TosaQuantGen.getZeroPoint(rng, self.args.zeropoint, ifm.dtype), + TosaQuantGen.getZeroPoint( + rng, self.args.zeropoint, result_tensor.dtype + ), ] # Invalidate Input/Output list for error_if checks. @@ -945,7 +875,7 @@ class TosaTestGen: output_list = [result_tensor.name] num_operands = sum(op["operands"]) input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -985,6 +915,7 @@ class TosaTestGen: def build_conv3d( self, + rng, op, inputs, args_dict, @@ -1002,7 +933,7 @@ class TosaTestGen: assert len(padding) == 6 result_tensor = OutputShaper.conv3dOp( self.ser, - self.rng, + rng, ifm, filter, accum_dtype, @@ -1018,8 +949,10 @@ class TosaTestGen: DType.UINT8, ): qinfo = [ - TosaQuantGen.getZeroPoint(self, ifm.dtype), - TosaQuantGen.getZeroPoint(self, result_tensor.dtype), + TosaQuantGen.getZeroPoint(rng, self.args.zeropoint, ifm.dtype), + TosaQuantGen.getZeroPoint( + rng, self.args.zeropoint, result_tensor.dtype + ), ] # Invalidate Input/Output list for error_if checks. @@ -1027,7 +960,7 @@ class TosaTestGen: output_list = [result_tensor.name] num_operands = sum(op["operands"]) input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1067,6 +1000,7 @@ class TosaTestGen: def build_transpose_conv2d( self, + rng, op, inputs, args_dict, @@ -1083,7 +1017,7 @@ class TosaTestGen: assert len(out_pad) == 4 result_tensor = OutputShaper.transposeConv2DOp( - self.ser, self.rng, ifm, output_shape, accum_dtype, error_name + self.ser, rng, ifm, output_shape, accum_dtype, error_name ) # Ensure new output type has correct qinfo @@ -1092,8 +1026,10 @@ class TosaTestGen: DType.UINT8, ): qinfo = [ - TosaQuantGen.getZeroPoint(self, ifm.dtype), - TosaQuantGen.getZeroPoint(self, result_tensor.dtype), + TosaQuantGen.getZeroPoint(rng, self.args.zeropoint, ifm.dtype), + TosaQuantGen.getZeroPoint( + rng, self.args.zeropoint, result_tensor.dtype + ), ] # Invalidate Input/Output list for error_if checks. @@ -1101,7 +1037,7 @@ class TosaTestGen: output_list = [result_tensor.name] num_operands = sum(op["operands"]) input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1142,6 +1078,7 @@ class TosaTestGen: def build_depthwise_conv2d( self, + rng, op, inputs, args_dict, @@ -1158,7 +1095,7 @@ class TosaTestGen: result_tensor = OutputShaper.depthwiseConv2dOp( self.ser, - self.rng, + rng, ifm, filter, accum_dtype, @@ -1174,8 +1111,10 @@ class TosaTestGen: DType.UINT8, ): qinfo = [ - TosaQuantGen.getZeroPoint(self, ifm.dtype), - TosaQuantGen.getZeroPoint(self, result_tensor.dtype), + TosaQuantGen.getZeroPoint(rng, self.args.zeropoint, ifm.dtype), + TosaQuantGen.getZeroPoint( + rng, self.args.zeropoint, result_tensor.dtype + ), ] # Invalidate Input/Output list for error_if checks. @@ -1183,7 +1122,7 @@ class TosaTestGen: output_list = [result_tensor.name] num_operands = sum(op["operands"]) input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1223,6 +1162,7 @@ class TosaTestGen: def build_fully_connected( self, + rng, op, inputs, args_dict, @@ -1235,7 +1175,7 @@ class TosaTestGen: accum_dtype = args_dict["acc_type"] result_tensor = OutputShaper.fullyConnectedOp( - self.ser, self.rng, ifm, filter, accum_dtype, error_name + self.ser, rng, ifm, filter, accum_dtype, error_name ) # Invalidate Input/Output list for error if checks. @@ -1244,7 +1184,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1278,13 +1218,20 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_matmul( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 2 a, b = inputs accum_dtype = args_dict["acc_type"] result_tensor = OutputShaper.matmulOp( - self.ser, self.rng, a, b, accum_dtype, error_name + self.ser, rng, a, b, accum_dtype, error_name ) # Invalidate Input/Output list for error if checks. @@ -1293,7 +1240,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1328,12 +1275,12 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_reduce( - self, op, inputs, args_dict, validator_fcns, error_name=None, qinfo=None + self, rng, op, inputs, args_dict, validator_fcns, error_name=None, qinfo=None ): assert len(inputs) == 1 a = inputs[0] axis = args_dict["axis"] - result_tensor = OutputShaper.reduceOp(self.ser, self.rng, a, axis, error_name) + result_tensor = OutputShaper.reduceOp(self.ser, rng, a, axis, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name] @@ -1341,7 +1288,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1377,19 +1324,26 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_clamp( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 1 a = inputs[0] - result_tensor = OutputShaper.unaryOp(self.ser, self.rng, a, error_name) + result_tensor = OutputShaper.unaryOp(self.ser, rng, a, error_name) - v = [self.getRandNumberDType(a.dtype), self.getRandNumberDType(a.dtype)] + v = [rng.randNumberDType(a.dtype), rng.randNumberDType(a.dtype)] if error_name == ErrorIf.MaxSmallerMin: # Make sure the numbers are different to invoke this error while v[0] == v[1]: - v = [self.getRandNumberDType(a.dtype), self.getRandNumberDType(a.dtype)] + v = [rng.randNumberDType(a.dtype), rng.randNumberDType(a.dtype)] max_val = min(v) min_val = max(v) else: @@ -1402,7 +1356,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1449,29 +1403,20 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) - def build_leaky_relu(self, op, a, validator_fcns=None, error_name=None): - result_tens = OutputShaper.unaryOp(self.ser, self.rng, a, error_name) - attr = ts.TosaSerializerAttribute() - - attr.LeakyReluAttribute(self.getRandNumberDType(DType.FP32)) - - self.ser.addOperator(op["op"], [a.name], [result_tens.name], attr) - return result_tens - - # Needs an additional type/input - def build_prelu(self, op, a, validator_fcns=None, error_name=None): - result_tens = OutputShaper.unaryOp(self.ser, self.rng, a, error_name) - - self.ser.addOperator(op["op"], [a.name], [result_tens.name]) - return result_tens - def build_activation( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 1 a = inputs[0] - result_tensor = OutputShaper.unaryOp(self.ser, self.rng, a, error_name) + result_tensor = OutputShaper.unaryOp(self.ser, rng, a, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name] @@ -1479,7 +1424,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1507,7 +1452,14 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_concat( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): if op["op"] == Op.CONCAT_SHAPE: axis = 0 @@ -1517,7 +1469,7 @@ class TosaTestGen: assert type(axis) == int result_tensor = OutputShaper.concatOp( - self.ser, self.rng, axis, inputs, error_name=error_name + self.ser, rng, axis, inputs, error_name=error_name ) input_tensor_names = [] @@ -1530,7 +1482,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1567,6 +1519,7 @@ class TosaTestGen: def build_pad( self, + rng, op, inputs, args_dict, @@ -1581,7 +1534,7 @@ class TosaTestGen: pad_const_int = args_dict["pad_const_int"] pad_const_float = args_dict["pad_const_fp"] - result_tensor = OutputShaper.padOp(self.ser, self.rng, a, padding, error_name) + result_tensor = OutputShaper.padOp(self.ser, rng, a, padding, error_name) # get pad_const_val_as_bytes from either pad_const_float or pad_const_int if gtu.dtypeIsFloat(a.dtype): @@ -1598,7 +1551,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1630,6 +1583,7 @@ class TosaTestGen: def build_dim( self, + rng, op, inputs, args_dict, @@ -1640,7 +1594,7 @@ class TosaTestGen: assert len(inputs) == 1 a = inputs[0] axis = args_dict["axis"] - result_tensor = OutputShaper.dimOp(self.ser, self.rng, a, axis, error_name) + result_tensor = OutputShaper.dimOp(self.ser, rng, a, axis, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name] @@ -1648,7 +1602,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1675,15 +1629,20 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, None) def build_reshape( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 2 a = inputs[0] shape = inputs[1] shape_attr = args_dict["new_shape"] - result_tensor = OutputShaper.reshapeOp( - self.ser, self.rng, a, shape_attr, error_name - ) + result_tensor = OutputShaper.reshapeOp(self.ser, rng, a, shape_attr, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name, shape.name] @@ -1691,7 +1650,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1719,12 +1678,19 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_reverse( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 1 a = inputs[0] axis = args_dict["axis"] - result_tensor = OutputShaper.unaryOp(self.ser, self.rng, a, error_name) + result_tensor = OutputShaper.unaryOp(self.ser, rng, a, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name] @@ -1732,7 +1698,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1759,15 +1725,20 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, None) def build_transpose( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 1 a = inputs[0] perms = args_dict["perms"] - result_tensor = OutputShaper.transposeOp( - self.ser, self.rng, a, perms, error_name - ) + result_tensor = OutputShaper.transposeOp(self.ser, rng, a, perms, error_name) attr = ts.TosaSerializerAttribute() attr.TransposeAttribute(perms) @@ -1778,7 +1749,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1808,7 +1779,14 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_slice( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 3 a, start_var, size_var = inputs @@ -1816,7 +1794,7 @@ class TosaTestGen: size_const = args_dict["size"] result_tensor = OutputShaper.sliceOp( - self.ser, self.rng, a, start_const, size_const, error_name + self.ser, rng, a, start_const, size_const, error_name ) # Invalidate Input/Output list for error if checks. @@ -1825,7 +1803,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1856,14 +1834,21 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_tile( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 2 a = inputs[0] multiples = inputs[1] multiples_attr = args_dict["multiples"] result_tensor = OutputShaper.tileOp( - self.ser, self.rng, a, multiples_attr, error_name + self.ser, rng, a, multiples_attr, error_name ) # Invalidate Input/Output list for error if checks. @@ -1872,7 +1857,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1901,13 +1886,20 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_gather( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 2 values, indices = inputs result_tensor = OutputShaper.gatherOp( - self.ser, self.rng, values, indices, error_name + self.ser, rng, values, indices, error_name ) # Invalidate Input/Output list for error if checks. @@ -1916,7 +1908,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1944,12 +1936,19 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_scatter( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 3 values_in, indices, input = inputs result_tensor = OutputShaper.scatterOp( - self.ser, self.rng, values_in, indices, input, error_name + self.ser, rng, values_in, indices, input, error_name ) # Invalidate Input/Output list for error if checks. @@ -1958,7 +1957,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -1987,6 +1986,7 @@ class TosaTestGen: def build_resize( self, + rng, op, inputs, args_dict, @@ -2008,7 +2008,7 @@ class TosaTestGen: result_tensor = OutputShaper.resizeOp( self.ser, - self.rng, + rng, input, mode, scale, @@ -2030,7 +2030,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -2064,16 +2064,15 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) - def build_identityn(self, op, val, val2, validator_fcns=None, error_name=None): - result_tens = OutputShaper.unaryOp(self.ser, self.rng, val, error_name) - result_tens2 = OutputShaper.unaryOp(self.ser, self.rng, val2, error_name) - self.ser.addOperator( - op, [val.name, val2.name], [result_tens.name, result_tens2.name] - ) - return result_tens - def build_const( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 1 val = inputs[0] @@ -2087,14 +2086,21 @@ class TosaTestGen: # Type Conversion def build_cast( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 1 val = inputs[0] out_dtype = args_dict["out_type"] result_tensor = OutputShaper.typeConversionOp( - self.ser, self.rng, val, out_dtype, error_name + self.ser, rng, val, out_dtype, error_name ) # Invalidate Input/Output list for error if checks. @@ -2103,7 +2109,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) if not TosaErrorValidator.evValidateErrorIfs( @@ -2132,6 +2138,7 @@ class TosaTestGen: def build_rescale( self, + rng, op, inputs, args_dict, @@ -2151,7 +2158,7 @@ class TosaTestGen: multiplier_arr = args_dict["multiplier"] result_tensor = OutputShaper.typeConversionOp( - self.ser, self.rng, val, out_dtype, error_name + self.ser, rng, val, out_dtype, error_name ) if per_channel: @@ -2166,46 +2173,46 @@ class TosaTestGen: output_unsigned = False if val.dtype == DType.INT8: - input_zp = self.randInt(-128, 128) + input_zp = rng.randInt(-128, 128) in_type_width += 1 elif val.dtype == DType.UINT8: - input_zp = self.randInt(0, 256) + input_zp = rng.randInt(0, 256) in_type_width += 1 input_unsigned = True elif error_name in [ ErrorIf.InputZeroPointNotZero, ErrorIf.U16InputZeroPointNotValid, ]: - input_zp = self.randInt(-128, 128) + input_zp = rng.randInt(-128, 128) if input_zp == 0: - input_zp = input_zp + self.rng.integers(1, 10) + input_zp = input_zp + rng.integers(1, 10) in_type_width += 1 elif val.dtype == DType.UINT16: # Must come after ErrorIf.U16InputZeroPointNotValid check - input_zp = self.rng.choice([0, 32768]) + input_zp = rng.choice([0, 32768]) in_type_width += 1 input_unsigned = True else: input_zp = 0 if out_dtype == DType.INT8: - output_zp = self.randInt(-128, 128) + output_zp = rng.randInt(-128, 128) out_type_width += 1 elif out_dtype == DType.UINT8: - output_zp = self.randInt(0, 256) + output_zp = rng.randInt(0, 256) out_type_width += 1 output_unsigned = True elif error_name in [ ErrorIf.OutputZeroPointNotZero, ErrorIf.U16OutputZeroPointNotValid, ]: - output_zp = self.randInt(-128, 128) + output_zp = rng.randInt(-128, 128) if output_zp == 0: - output_zp = output_zp + self.rng.integers(1, 10) + output_zp = output_zp + rng.integers(1, 10) out_type_width += 1 elif out_dtype == DType.UINT16: # Must come after ErrorIf.U16OutputZeroPointNotValid check - output_zp = self.rng.choice([0, 32768]) + output_zp = rng.choice([0, 32768]) out_type_width += 1 output_unsigned = True else: @@ -2255,7 +2262,7 @@ class TosaTestGen: pCount, cCount = op["operands"] num_operands = pCount + cCount input_list, output_list = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_list, output_list + rng, error_name, input_list, output_list ) qinfo = (input_zp, output_zp) @@ -2296,13 +2303,13 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) - def _get_condition_tensor(self, op, cond, error_name): + def _get_condition_tensor(self, rng, op, cond, error_name): if error_name == ErrorIf.CondIfCondNotMatchingBool: - cond_type = gtu.get_wrong_output_type(op, self.rng, DType.BOOL) + cond_type = gtu.get_wrong_output_type(op, rng, DType.BOOL) else: cond_type = DType.BOOL if error_name == ErrorIf.CondIfCondShapeNotSizeOne: - choice = self.rng.choice([1, 2]) + choice = rng.choice([1, 2]) if choice == 1: cond_shape = [2] else: @@ -2315,6 +2322,7 @@ class TosaTestGen: def build_cond_if_const( self, + rng, op, inputs, args_dict, @@ -2331,7 +2339,7 @@ class TosaTestGen: cond = args_dict["condition"] # Condition tensor - cond_tens = self._get_condition_tensor(op, cond, error_name) + cond_tens = self._get_condition_tensor(rng, op, cond, error_name) # Make then/else tensors out_shape = then_tens.shape @@ -2346,14 +2354,14 @@ class TosaTestGen: incorrect_shape = deepcopy(then_tens.shape) for i in range(len(incorrect_shape)): incorrect_shape[i] += ( - self.rng.choice([-3, -2, 2, 3]) + rng.choice([-3, -2, 2, 3]) if incorrect_shape[i] > 3 - else self.rng.choice([1, 2, 4]) + else rng.choice([1, 2, 4]) ) - incorrect_arr = np.int32(self.rng.integers(0, 256, size=incorrect_shape)) + incorrect_arr = np.int32(rng.integers(0, 256, size=incorrect_shape)) - then_arr = np.int32(self.rng.integers(0, 256, size=out_shape)) - else_arr = np.int32(self.rng.integers(0, 256, size=out_shape)) + then_arr = np.int32(rng.integers(0, 256, size=out_shape)) + else_arr = np.int32(rng.integers(0, 256, size=out_shape)) # And the result tensor based on any of the outputs result_tensor = self.ser.addOutput(out_shape, dtype) @@ -2400,6 +2408,7 @@ class TosaTestGen: def build_cond_if_binary( self, + rng, op, inputs, args_dict, @@ -2415,7 +2424,7 @@ class TosaTestGen: cond = args_dict["condition"] # Condition tensor - cond_tens = self._get_condition_tensor(op, cond, error_name) + cond_tens = self._get_condition_tensor(rng, op, cond, error_name) result_tensor = self.ser.addOutput(a.shape, a.dtype) @@ -2433,7 +2442,7 @@ class TosaTestGen: ]: incorrect_shape = a.shape.copy() for i in range(len(incorrect_shape)): - incorrect_shape[i] += self.rng.choice([-3, -2, 2, 3]) + incorrect_shape[i] += rng.choice([-3, -2, 2, 3]) incorrect_block_input = deepcopy(a) incorrect_block_input.shape = incorrect_shape @@ -2503,7 +2512,14 @@ class TosaTestGen: return TosaTestGen.BuildInfo(result_tensor, compliance) def build_while_loop( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 1 a = inputs[0] @@ -2528,7 +2544,7 @@ class TosaTestGen: if error_name == ErrorIf.InputListOutputListMismatch: incorrect_acc = deepcopy(acc) for i in range(len(incorrect_acc.shape)): - incorrect_acc.shape[i] += self.rng.choice([-3, -2, 2, 3]) + incorrect_acc.shape[i] += rng.choice([-3, -2, 2, 3]) acc_out = self.ser.addIntermediate(incorrect_acc.shape, acc.dtype) else: acc_out = self.ser.addIntermediate(acc.shape, acc.dtype) @@ -2549,13 +2565,13 @@ class TosaTestGen: ]: incorrect_iter = deepcopy(iter) for i in range(len(incorrect_iter.shape)): - incorrect_iter.shape[i] += self.rng.choice([-3, -2, 2, 3]) + incorrect_iter.shape[i] += rng.choice([-3, -2, 2, 3]) if len(incorrect_iter.shape) == 0: - incorrect_iter.shape.append(self.rng.choice([-3, -2, 2, 3])) + incorrect_iter.shape.append(rng.choice([-3, -2, 2, 3])) incorrect_acc = deepcopy(acc) for i in range(len(incorrect_acc.shape)): - incorrect_acc.shape[i] += self.rng.choice([-3, -2, 2, 3]) + incorrect_acc.shape[i] += rng.choice([-3, -2, 2, 3]) # COND block (input: iter, output: cond_tens ) self.ser.addBasicBlock(cond_block) @@ -2571,11 +2587,11 @@ class TosaTestGen: zero_tens = self.ser.addConst([], DType.INT32, [np.int32(0)]) if error_name == ErrorIf.CondGraphOutputNotMatchingBool: - cond_type = self.rng.choice([DType.INT8, DType.INT32, DType.FP32]) + cond_type = rng.choice([DType.INT8, DType.INT32, DType.FP32]) else: cond_type = DType.BOOL if error_name == ErrorIf.CondGraphOutputShapeNotSizeOne: - choice = self.rng.choice([1, 2]) + choice = rng.choice([1, 2]) if choice == 1: cond_shape = [3] else: @@ -2635,6 +2651,7 @@ class TosaTestGen: def build_fft2d( self, + rng, op, inputs, args_dict, @@ -2646,7 +2663,7 @@ class TosaTestGen: val1, val2 = inputs inverse = args_dict["inverse"] - results = OutputShaper.fft2dOp(self.ser, self.rng, val1, val2, error_name) + results = OutputShaper.fft2dOp(self.ser, rng, val1, val2, error_name) input_names = [val1.name, val2.name] pCount, cCount = op["operands"] @@ -2657,7 +2674,7 @@ class TosaTestGen: output_dtypes = [res.dtype for res in results] input_names, output_names = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_names, output_names + rng, error_name, input_names, output_names ) if not TosaErrorValidator.evValidateErrorIfs( @@ -2699,6 +2716,7 @@ class TosaTestGen: def build_rfft2d( self, + rng, op, inputs, args_dict, @@ -2708,7 +2726,7 @@ class TosaTestGen: ): assert len(inputs) == 1 val = inputs[0] - results = OutputShaper.rfft2dOp(self.ser, self.rng, val, error_name) + results = OutputShaper.rfft2dOp(self.ser, rng, val, error_name) input_names = [val.name] pCount, cCount = op["operands"] @@ -2719,7 +2737,7 @@ class TosaTestGen: output_dtypes = [res.dtype for res in results] input_names, output_names = TosaErrorIfArgGen.eiInvalidateInputOutputList( - self, error_name, input_names, output_names + rng, error_name, input_names, output_names ) if not TosaErrorValidator.evValidateErrorIfs( @@ -2755,12 +2773,19 @@ class TosaTestGen: return TosaTestGen.BuildInfo(results, compliance) def build_shape_op( - self, op, inputs, args_dict, validator_fcns=None, error_name=None, qinfo=None + self, + rng, + op, + inputs, + args_dict, + validator_fcns=None, + error_name=None, + qinfo=None, ): assert len(inputs) == 2 a, b = inputs - result_tensor = OutputShaper.addShapeOp(self.ser, self.rng, a, b, error_name) + result_tensor = OutputShaper.addShapeOp(self.ser, rng, a, b, error_name) # Invalidate Input/Output list for error if checks. input_list = [a.name, b.name] @@ -2895,8 +2920,9 @@ class TosaTestGen: except KeyError: raise Exception("Cannot find op with name {}".format(opName)) - # Initialize a new random number generator - self.rng = np.random.default_rng(self.random_seed) + if not self.args.stable_rng: + # Initialize a new random number generator per op + self.resetGlobalRNG() _, tgen_fcn, _, agen_fcn = op["build_fcn"] @@ -2933,37 +2959,53 @@ class TosaTestGen: if shape is not None and len(shape) != r: continue self.setTargetShape(shape) - shapeList = tgen_fcn(self, op, r, error_name) + typeStr = self.typeStr(t) + if self.args.stable_rng: + shape_rng = TosaHashRandomGenerator( + self.random_seed, + [opName, r, typeStr], + self.random_dtype_range, + ) + else: + shape_rng = self.global_rng + shapeList = tgen_fcn(self, shape_rng, op, r, error_name) shapeStr = self.shapeStr(shapeList[0]) - typeStr = self.typeStr(t) # Argument lists consists of tuples of the (str, []) string representation and the build function argument list argList = [] if agen_fcn: - argList = agen_fcn(self, opName, shapeList, t, error_name) + if self.args.stable_rng: + arg_rng = TosaHashRandomGenerator( + self.random_seed, + [opName, shapeStr, typeStr], + self.random_dtype_range, + ) + else: + arg_rng = self.global_rng + + argList = agen_fcn( + self, arg_rng, opName, shapeList, t, error_name + ) else: argList = [("", [])] for argStr, args in argList: + # Create the test name string - for example: add_1x2x3_i32 if testType == "positive": - if argStr: - testStr = "{}_{}_{}_{}".format( - opName, shapeStr, typeStr, argStr - ) - else: - testStr = "{}_{}_{}".format( - opName, shapeStr, typeStr - ) - elif testType == "negative": - if argStr: - testStr = "{}_ERRORIF_{}_{}_{}_{}".format( - opName, error_name, shapeStr, typeStr, argStr - ) - else: - testStr = "{}_ERRORIF_{}_{}_{}".format( - opName, error_name, shapeStr, typeStr - ) + name_parts = [opName, shapeStr, typeStr] + else: + assert testType == "negative" + name_parts = [ + opName, + "ERRORIF", + error_name, + shapeStr, + typeStr, + ] + if argStr: + name_parts.append(argStr) + testStr = "_".join(name_parts) testList.append( (opName, testStr, t, error_name, shapeList, args) @@ -3038,8 +3080,18 @@ class TosaTestGen: # Build the random tensor operands and the test + # Set the random number generator + if self.args.stable_rng: + build_rng = TosaHashRandomGenerator( + self.random_seed, [testStr], self.random_dtype_range + ) + else: + build_rng = self.global_rng + if qgen is not None: - qinfo = qgen(self, op, dtype_or_dtypeList, error_name) + qinfo = qgen( + build_rng, self.args.zeropoint, op, dtype_or_dtypeList, error_name + ) else: qinfo = None @@ -3053,13 +3105,16 @@ class TosaTestGen: # New interface with args info in dictionary assert "dg_type" in argsDict - tvgInfo = tvgen_fcn(self, opName, dtypeList, shapeList, argsDict, error_name) + tvgInfo = tvgen_fcn( + self, build_rng, opName, dtypeList, shapeList, argsDict, error_name + ) if tvgInfo.dataGenDict: tensMeta["data_gen"] = tvgInfo.dataGenDict tens = tvgInfo.tensorList result = build_fcn( self, + build_rng, op, tens, argsDict, diff --git a/verif/generator/tosa_verif_build_tests.py b/verif/generator/tosa_verif_build_tests.py index 47c351a..83c06d7 100644 --- a/verif/generator/tosa_verif_build_tests.py +++ b/verif/generator/tosa_verif_build_tests.py @@ -80,6 +80,13 @@ def parseArgs(argv): help="Random seed for test generation", ) + parser.add_argument( + "--stable-random-generation", + dest="stable_rng", + action="store_true", + help="Produces less variation (when the test-generator changes) in the test output using the same options", + ) + filter_group.add_argument( "--filter", dest="filter", @@ -395,7 +402,7 @@ def main(argv=None): else: # Use the random number generator to shuffle the test list # and select the per op tests from it - tests = testList.select(ttg.rng) + tests = testList.select(ttg.global_rng) if args.list_tests: for test in tests: |