From 6e1e2bc06bff785e87577f24064bbc846300f8fd Mon Sep 17 00:00:00 2001 From: Tai Ly Date: Fri, 1 Mar 2024 20:59:32 +0000 Subject: [ref model] Change RescaleOp attrs to inputs This patch implements changes required for RescaleOp's multiplier and shift changing from attributes to inputs Signed-off-by: Tai Ly Change-Id: I178919727e3220c749dad0ebce141e695868fee0 --- examples/test_add_1x4x4x4_f32/model.pb | 2 +- ...v2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa | Bin 1676 -> 1676 bytes ...v2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa | Bin 1380 -> 1380 bytes .../model.pb | 2 +- ...v2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa | Bin 1312 -> 1504 bytes .../test_lstm_stateful_13x21x3_f32.tosa | Bin 11932 -> 11920 bytes reference_model/src/ops/type_conversion.cc | 56 ++++++++++++++---- reference_model/src/ops/type_conversion.h | 17 ++++-- verif/generator/tosa_arg_gen.py | 63 +++++++++++++++++++++ verif/generator/tosa_test_gen.py | 47 ++++----------- verif/generator/tosa_utils.py | 8 +++ 11 files changed, 143 insertions(+), 52 deletions(-) diff --git a/examples/test_add_1x4x4x4_f32/model.pb b/examples/test_add_1x4x4x4_f32/model.pb index f1af89b..026dcea 100644 --- a/examples/test_add_1x4x4x4_f32/model.pb +++ b/examples/test_add_1x4x4x4_f32/model.pb @@ -92,5 +92,5 @@ node { } } versions { - producer: 1597 + producer: 1581 } diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa index e3bc565..20e1333 100644 Binary files a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa and b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tf/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa differ diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa index 90e8e86..d55d5d6 100644 Binary files a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa and b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa differ diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.pb b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.pb index bf7ee3a..ce59e78 100644 --- a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.pb +++ b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.pb @@ -137,5 +137,5 @@ node { } } versions { - producer: 1597 + producer: 1581 } diff --git a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa index e9fb643..87bafd1 100644 Binary files a/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa and b/examples/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11/flatbuffer-tflite/test_conv2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa differ diff --git a/examples/test_lstm_stateful_13x21x3_f32/flatbuffer-tflite/test_lstm_stateful_13x21x3_f32.tosa b/examples/test_lstm_stateful_13x21x3_f32/flatbuffer-tflite/test_lstm_stateful_13x21x3_f32.tosa index f9606a1..deaca6e 100644 Binary files a/examples/test_lstm_stateful_13x21x3_f32/flatbuffer-tflite/test_lstm_stateful_13x21x3_f32.tosa and b/examples/test_lstm_stateful_13x21x3_f32/flatbuffer-tflite/test_lstm_stateful_13x21x3_f32.tosa differ diff --git a/reference_model/src/ops/type_conversion.cc b/reference_model/src/ops/type_conversion.cc index 5dbc7bd..d58cfeb 100644 --- a/reference_model/src/ops/type_conversion.cc +++ b/reference_model/src/ops/type_conversion.cc @@ -35,7 +35,7 @@ template OpRescale::OpRescale(SubgraphTraverser* sgt_, TosaAttributeBase* attribute_, uint64_t id_) : GraphNode(sgt_, Op_RESCALE, id_) { - setRequiredOperands(1, 1); + setRequiredOperands(3, 1); INIT_ATTRIBUTE(Rescale); } @@ -68,6 +68,20 @@ int OpRescale::checkTensorAttributes() ASSERT_MEM(in && out); + multiplierI32 = dynamic_cast*>(inputs[1]); + multiplierI16 = dynamic_cast*>(inputs[1]); + shift = dynamic_cast*>(inputs[2]); + ASSERT_MEM(shift); + + if (attribute->scale32()) + { + ASSERT_MEM(multiplierI32); + } + else + { + ASSERT_MEM(multiplierI16); + } + if ((InDtype != TOSA_REF_TYPE_INT8) && (InDtype != TOSA_REF_TYPE_UINT8) && (InDtype != TOSA_REF_TYPE_UINT16) && (attribute->input_zp() != 0)) { @@ -124,15 +138,15 @@ static int64_t zero_extend(int16_t val) template int OpRescale::eval() { - int32_t input_zp = attribute->input_zp(); - int32_t output_zp = attribute->output_zp(); - std::vector multiplier = attribute->multiplier(); - std::vector shift = attribute->shift(); - bool scale32 = attribute->scale32(); - bool double_round = attribute->double_round(); - bool per_channel = attribute->per_channel(); - bool input_unsigned = attribute->input_unsigned(); - bool output_unsigned = attribute->output_unsigned(); + int32_t input_zp = attribute->input_zp(); + int32_t output_zp = attribute->output_zp(); + std::vector multiplier; + std::vector shift; + bool scale32 = attribute->scale32(); + bool double_round = attribute->double_round(); + bool per_channel = attribute->per_channel(); + bool input_unsigned = attribute->input_unsigned(); + bool output_unsigned = attribute->output_unsigned(); // reshape [d0, d1, ..., dn] into [d0 * d1 ..., dn] Eigen::array shape_2d; @@ -153,6 +167,28 @@ int OpRescale::eval() ETensor2 output_2d(shape_2d); + if (scale32) + { + auto multiplier_val = this->multiplierI32->getTensor(); + for (int i = 0; i < multiplier_val.size(); i++) + { + multiplier.push_back(static_cast(multiplier_val(i))); + } + } + else + { + auto multiplier_val = this->multiplierI16->getTensor(); + for (int i = 0; i < multiplier_val.size(); i++) + { + multiplier.push_back(static_cast(multiplier_val(i))); + } + } + auto shift_val = this->shift->getTensor(); + for (int i = 0; i < shift_val.size(); i++) + { + shift.push_back(static_cast(shift_val(i))); + } + if (per_channel) { ETensor2 curr_channel_slice_prescaled; diff --git a/reference_model/src/ops/type_conversion.h b/reference_model/src/ops/type_conversion.h index 75f244d..a06dccc 100644 --- a/reference_model/src/ops/type_conversion.h +++ b/reference_model/src/ops/type_conversion.h @@ -32,10 +32,16 @@ public: virtual int checkTensorAttributes() final; virtual int eval() final; - using InEigenType = typename GetEigenType::type; - using OutEigenType = typename GetEigenType::type; - using TIn = Eigen::Tensor; - using TOut = Eigen::Tensor; + using InEigenType = typename GetEigenType::type; + using OutEigenType = typename GetEigenType::type; + using TIn = Eigen::Tensor; + using TOut = Eigen::Tensor; + using I8EigenType = typename GetEigenType::type; + using I16EigenType = typename GetEigenType::type; + using I32EigenType = typename GetEigenType::type; + using TMultiplierI16 = Eigen::Tensor; + using TMultiplierI32 = Eigen::Tensor; + using TShift = Eigen::Tensor; static constexpr int32_t QMin = GetQMin::value; static constexpr int32_t QMax = GetQMax::value; @@ -44,6 +50,9 @@ protected: TosaRescaleAttribute* attribute; TosaReference::TensorTemplate* in; TosaReference::TensorTemplate* out; + TosaReference::TensorTemplate* multiplierI16; + TosaReference::TensorTemplate* multiplierI32; + TosaReference::TensorTemplate* shift; }; template diff --git a/verif/generator/tosa_arg_gen.py b/verif/generator/tosa_arg_gen.py index 592c491..cbfffae 100644 --- a/verif/generator/tosa_arg_gen.py +++ b/verif/generator/tosa_arg_gen.py @@ -744,6 +744,10 @@ class TosaTensorValuesGen: arr = np.int64(argsDict["fixed_data"][idx]) elif dtype == DType.INT8: arr = np.int8(argsDict["fixed_data"][idx]) + elif dtype == DType.INT16: + arr = np.int16(argsDict["fixed_data"][idx]) + elif dtype == DType.INT32: + arr = np.int32(argsDict["fixed_data"][idx]) else: assert False, "Unsupported fixed_data type" else: @@ -1059,6 +1063,26 @@ class TosaTensorValuesGen: testGen, opName, dtypeList, shapeList, argsDict, error_name ) + @staticmethod + def tvgRescale(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): + scale32 = argsDict["scale"] + multiplier_arr = argsDict["multiplier"] + shift_arr = argsDict["shift"] + + if scale32: + dtypeList[1] = DType.INT32 + else: + dtypeList[1] = DType.INT16 + shapeList[1] = [len(multiplier_arr)] + dtypeList[2] = DType.INT8 + shapeList[2] = [len(shift_arr)] + # Create a new list for the pre-generated data in argsDict["fixed_data"] + argsDict["fixed_data"] = [None, multiplier_arr, shift_arr] + + return TosaTensorValuesGen.tvgLazyGenDefault( + testGen, opName, dtypeList, shapeList, argsDict, error_name + ) + @staticmethod def tvgPad(testGen, opName, dtypeList, shapeList, argsDict, error_name=None): # argsDict["pad"] is 2D array, need to flatten it to get list of values @@ -2842,6 +2866,43 @@ class TosaArgGen: # Illegal condition. ERROR_IF(!scale32 && double_round) continue + if per_channel: + nc = shapeList[0][-1] + else: + nc = 1 + + in_type_width = gtu.dtypeWidth(inDtype) + out_type_width = gtu.dtypeWidth(outDtype) + + # Calculate scale based on: + # scale = a *(2^output_width)/(2^input_width)) + + a = np.float32(testGen.rng.random(size=[nc])) + scale_arr = a * np.float32( + (1 << out_type_width) / (1 << in_type_width) + ) + + if scale32: + # Cap the scaling at 2^31 - 1 for scale32 + scale_arr = np.clip( + scale_arr, 1.0 / (1 << 31), (1 << 31) - 1 + ) + else: + # Cap the scaling at 2^15 - 1 for scale16 + scale_arr = np.clip(scale_arr, 1.0 / (1 << 31), 32767.0) + + # print('{} {} -> {}'.format(out_type_width, in_type_width, scale_arr)) + + multiplier_arr = np.int32(np.zeros(shape=[nc])) + shift_arr = np.int32(np.zeros(shape=[nc])) + for i in range(nc): + ( + multiplier_arr[i], + shift_arr[i], + ) = TosaQuantGen.computeMultiplierAndShift( + scale_arr[i], scale32 + ) + arg_list.append( ( "out{}_sc{}_dr{}_pc{}".format( @@ -2855,6 +2916,8 @@ class TosaArgGen: "scale": scale32, "double_round": double_round, "per_channel": per_channel, + "multiplier": multiplier_arr, + "shift": shift_arr, }, ) ) diff --git a/verif/generator/tosa_test_gen.py b/verif/generator/tosa_test_gen.py index 978e735..415858c 100644 --- a/verif/generator/tosa_test_gen.py +++ b/verif/generator/tosa_test_gen.py @@ -317,13 +317,6 @@ class TosaTestGen: "Unknown dtype, cannot convert to string: {}".format(dtype) ) - def typeWidth(self, dtype): - """Get the datatype width for data types""" - if dtype in gtu.DTYPE_ATTRIBUTES: - return gtu.DTYPE_ATTRIBUTES[dtype]["width"] - else: - raise Exception(f"Unknown dtype, cannot determine width: {dtype}") - def constrictBatchSize(self, shape): # Limit the batch size unless an explicit target shape set if self.args.max_batch_size and not self.args.target_shapes: @@ -2130,12 +2123,15 @@ class TosaTestGen: error_name=None, qinfo=None, ): - assert len(inputs) == 1 + assert len(inputs) == 3 val = inputs[0] + multiplier_val = inputs[1] + shift_val = inputs[2] out_dtype = args_dict["output_dtype"] scale32 = args_dict["scale"] double_round = args_dict["double_round"] per_channel = args_dict["per_channel"] + shift_arr = args_dict["shift"] result_tensor = OutputShaper.typeConversionOp( self.ser, self.rng, val, out_dtype, error_name @@ -2146,8 +2142,8 @@ class TosaTestGen: else: nc = 1 - in_type_width = self.typeWidth(val.dtype) - out_type_width = self.typeWidth(out_dtype) + in_type_width = gtu.dtypeWidth(val.dtype) + out_type_width = gtu.dtypeWidth(out_dtype) input_unsigned = False output_unsigned = False @@ -2198,31 +2194,10 @@ class TosaTestGen: else: output_zp = 0 - # Calculate scale based on: - # scale = a *(2^output_width)/(2^input_width)) - - a = np.float32(self.rng.random(size=[nc])) - scale_arr = a * np.float32((1 << out_type_width) / (1 << in_type_width)) - - if scale32: - pass - # Cap the scaling at 2^31 - 1 for scale32 - scale_arr = np.clip(scale_arr, 1.0 / (1 << 31), (1 << 31) - 1) - else: - # Cap the scaling at 2^15 - 1 for scale16 - scale_arr = np.clip(scale_arr, 1.0 / (1 << 31), 32767.0) - - # print('{} {} -> {}'.format(out_type_width, in_type_width, scale_arr)) - - multiplier_arr = np.int32(np.zeros(shape=[nc])) - shift_arr = np.int32(np.zeros(shape=[nc])) min_shift_value_arr = np.int64(np.zeros(shape=[nc])) max_shift_value_arr = np.int64(np.zeros(shape=[nc])) for i in range(nc): - multiplier_arr[i], shift_arr[i] = TosaQuantGen.computeMultiplierAndShift( - scale_arr[i], scale32 - ) min_shift_value_arr[i] = -1 << (shift_arr[i] - 1) max_shift_value_arr[i] = (1 << (shift_arr[i] - 1)) - 1 @@ -2256,7 +2231,7 @@ class TosaTestGen: ) # Invalidate Input/Output list for error if checks. - input_list = [val.name] + input_list = [val.name, multiplier_val.name, shift_val.name] output_list = [result_tensor.name] pCount, cCount = op["operands"] num_operands = pCount + cCount @@ -2287,8 +2262,8 @@ class TosaTestGen: attr.RescaleAttribute( input_zp, output_zp, - multiplier_arr, - shift_arr, + [], + [], scale32, double_round, per_channel, @@ -4809,11 +4784,11 @@ class TosaTestGen: }, "rescale": { "op": Op.RESCALE, - "operands": (1, 0), + "operands": (3, 0), "build_fcn": ( build_rescale, TosaTensorGen.tgBasic, - TosaTensorValuesGen.tvgLazyGenDefault, + TosaTensorValuesGen.tvgRescale, TosaArgGen.agRescale, ), "types": [ diff --git a/verif/generator/tosa_utils.py b/verif/generator/tosa_utils.py index 31a0ff0..384463f 100644 --- a/verif/generator/tosa_utils.py +++ b/verif/generator/tosa_utils.py @@ -55,6 +55,14 @@ class DataGenType(IntEnum): FIXED_DATA = 5 +def dtypeWidth(dtype): + """Get the datatype width for data types""" + if dtype in DTYPE_ATTRIBUTES: + return DTYPE_ATTRIBUTES[dtype]["width"] + else: + raise Exception(f"Unknown dtype, cannot determine width: {dtype}") + + def dtypeIsSupportedByCompliance(dtype): """Types supported by the new data generation and compliance flow.""" if isinstance(dtype, list) or isinstance(dtype, tuple): -- cgit v1.2.1