From fe392ce8e714e616b5ab5b8a519d3eb84623273d Mon Sep 17 00:00:00 2001 From: Kevin Cheng Date: Mon, 18 Oct 2021 21:51:55 +0000 Subject: Changes for 0.23.0 release - update serialization_lib hash - PAD: 1. make padding as an attribute instead of tensor. 2. add pad_const_int (for non-float type) / pad_const_fp (for float type) - TRANSPOSE: make perm as an attribute instead of tensor - TABLE: make table as attribute instead of tensor - update examples/ tests Signed-off-by: Kevin Cheng Change-Id: Iddc446db4b356ba2f36ea4a79b7220b9cfc2aa4e --- .../flatbuffer-tf/test_add_1x4x4x4_f32.tosa | Bin 516 -> 488 bytes .../flatbuffer-tflite/test_add_1x4x4x4_f32.tosa | Bin 516 -> 488 bytes examples/test_add_1x4x4x4_f32/model.pb | 2 +- examples/test_add_1x4x4x4_f32/model.tflite | Bin 600 -> 596 bytes ...v2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa | Bin 1556 -> 1284 bytes ...v2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11.tosa | Bin 1312 -> 1284 bytes .../model.pb | 2 +- .../model.tflite | Bin 1272 -> 1276 bytes ...v2d_1x1_1x32x32x8_qi8_st11_padSAME_dilat11.tosa | Bin 1264 -> 1236 bytes reference_model/src/ops/data_layout.cc | 57 ++++++++++---- reference_model/src/ops/data_layout.h | 4 +- reference_model/src/ops/ewise_binary.cc | 42 ++++------ reference_model/src/ops/ewise_binary.h | 34 ++++---- thirdparty/serialization_lib | 2 +- verif/tosa_test_gen.py | 86 +++++++++++++-------- 15 files changed, 128 insertions(+), 101 deletions(-) diff --git a/examples/test_add_1x4x4x4_f32/flatbuffer-tf/test_add_1x4x4x4_f32.tosa b/examples/test_add_1x4x4x4_f32/flatbuffer-tf/test_add_1x4x4x4_f32.tosa index 8d004e8..5a9457d 100644 Binary files a/examples/test_add_1x4x4x4_f32/flatbuffer-tf/test_add_1x4x4x4_f32.tosa and b/examples/test_add_1x4x4x4_f32/flatbuffer-tf/test_add_1x4x4x4_f32.tosa differ diff --git a/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/test_add_1x4x4x4_f32.tosa b/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/test_add_1x4x4x4_f32.tosa index 8d004e8..5a9457d 100644 Binary files a/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/test_add_1x4x4x4_f32.tosa and b/examples/test_add_1x4x4x4_f32/flatbuffer-tflite/test_add_1x4x4x4_f32.tosa differ diff --git a/examples/test_add_1x4x4x4_f32/model.pb b/examples/test_add_1x4x4x4_f32/model.pb index 59c6aec..a3c5cae 100644 --- a/examples/test_add_1x4x4x4_f32/model.pb +++ b/examples/test_add_1x4x4x4_f32/model.pb @@ -92,5 +92,5 @@ node { } } versions { - producer: 810 + producer: 925 } diff --git a/examples/test_add_1x4x4x4_f32/model.tflite b/examples/test_add_1x4x4x4_f32/model.tflite index 36a6799..5a88e98 100644 Binary files a/examples/test_add_1x4x4x4_f32/model.tflite and b/examples/test_add_1x4x4x4_f32/model.tflite differ 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 71564f2..36168d7 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 0dc565a..36168d7 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 b21dff3..9d199e4 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: 810 + producer: 925 } diff --git a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.tflite b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.tflite index 8b5bdf6..b2a60f8 100644 Binary files a/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.tflite and b/examples/test_conv2d_1x1_1x32x32x8_f32_st11_padSAME_dilat11/model.tflite differ 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 600590c..05a78b6 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/reference_model/src/ops/data_layout.cc b/reference_model/src/ops/data_layout.cc index 674227b..05a11e0 100644 --- a/reference_model/src/ops/data_layout.cc +++ b/reference_model/src/ops/data_layout.cc @@ -128,10 +128,11 @@ OpPad::OpPad(SubgraphTraverser* sgt_, uint64_t id_) : GraphNode(sgt_, Op_PAD, id_) { - setRequiredOperands(2, 1); + setRequiredOperands(1, 1); setRequiredRank(0, 6); INIT_QINFO(Pad); + INIT_ATTRIBUTE(Pad); } template @@ -159,9 +160,22 @@ int OpPad::checkTensorAttributes() return 1; } - in = dynamic_cast*>(inputs[0]); - out = dynamic_cast*>(outputs[0]); - paddings = dynamic_cast>*>(inputs[1]); + in = dynamic_cast*>(inputs[0]); + out = dynamic_cast*>(outputs[0]); + ASSERT_MEM(in && out); + + // padding in spec is 2D array in shape of [Rank, 2] + // Reference model implement this as 1D array of [Rank * 2], with ordering: + // [Rank0_front, Rank0_back, Rank1_front, Rank1_back, ..., Rank(N-1)_front, Rank(N-1)_back] + ERROR_IF(attribute->padding().size() != (Rank * 2), "OpPad: padding length needs to be (rank(input1) * 2)"); + + for (int i = 0; i < Rank; i++) + { + int32_t pad_front = attribute->padding()[2 * i]; + int32_t pad_back = attribute->padding()[2 * i + 1]; + ERROR_IF((pad_front < 0) || (pad_back < 0), "OpPad: padding can't be smaller than 0"); + paddings_array[i] = std::make_pair(pad_front, pad_back); + } if (this->qinfo && Dtype != DType_INT8) { @@ -174,18 +188,24 @@ int OpPad::checkTensorAttributes() template int OpPad::eval() { - // Move this to - for (int i = 0; i < Rank; i++) + InEigenType pad_value = 0; + + switch (Dtype) { - ERROR_IF((paddings->getTensor()(i, 0) < 0) || (paddings->getTensor()(i, 1) < 0), - "OpPad: padding can't be smaller than 0"); - paddings_array[i] = std::make_pair(paddings->getTensor()(i, 0), paddings->getTensor()(i, 1)); + case DType_BOOL: + case DType_INT8: + case DType_INT16: + case DType_INT32: + pad_value = (InEigenType)attribute->pad_const_int(); + break; + case DType_FLOAT: + pad_value = (InEigenType)attribute->pad_const_fp(); + break; } - InEigenType pad_value = 0; - if (this->qinfo) + if (this->qinfo && Dtype == DType_INT8) { - pad_value = (InEigenType)this->qinfo->input_zp(); + pad_value += (InEigenType)this->qinfo->input_zp(); } this->out->getTensor() = this->in->getTensor().pad(this->paddings_array, pad_value); @@ -602,8 +622,10 @@ OpTranspose::OpTranspose(SubgraphTraverser* sgt_, uint64_t id_) : GraphNode(sgt_, Op_TRANSPOSE, id_) { - setRequiredOperands(2, 1); + setRequiredOperands(1, 1); setRequiredRank(0, 6); + + INIT_ATTRIBUTE(Transpose); } template @@ -634,9 +656,10 @@ int OpTranspose::checkTensorAttributes() return 1; } - in = dynamic_cast*>(inputs[0]); - out = dynamic_cast*>(outputs[0]); - perm_tensor = dynamic_cast>*>(inputs[1]); + in = dynamic_cast*>(inputs[0]); + out = dynamic_cast*>(outputs[0]); + + ASSERT_MEM(in && out); return 0; } @@ -646,7 +669,7 @@ int OpTranspose::eval() { for (int32_t d = 0; d < Rank; d++) { - perm_array[d] = this->perm_tensor->getTensor().data()[d]; + perm_array[d] = attribute->perm()[d]; ERROR_IF(perm_array[d] < 0 or perm_array[d] >= Rank, "OpTranspose: index out of boundary"); } diff --git a/reference_model/src/ops/data_layout.h b/reference_model/src/ops/data_layout.h index 9f44fc7..bad88e4 100644 --- a/reference_model/src/ops/data_layout.h +++ b/reference_model/src/ops/data_layout.h @@ -63,8 +63,8 @@ protected: Eigen::array, Rank> paddings_array; TosaReference::TensorTemplate* in; TosaReference::TensorTemplate* out; - TosaReference::TensorTemplate>* paddings; TosaPadQuantInfo* qinfo; + TosaPadAttribute* attribute; }; template @@ -207,8 +207,8 @@ public: protected: Eigen::array perm_array; + TosaTransposeAttribute* attribute; TosaReference::TensorTemplate* in; - TosaReference::TensorTemplate>* perm_tensor; TosaReference::TensorTemplate* out; }; }; // namespace TosaReference diff --git a/reference_model/src/ops/ewise_binary.cc b/reference_model/src/ops/ewise_binary.cc index 6808604..415cd1c 100644 --- a/reference_model/src/ops/ewise_binary.cc +++ b/reference_model/src/ops/ewise_binary.cc @@ -490,8 +490,10 @@ OpTable::OpTable(SubgraphTraverser* sgt_, uint64_t id_) : GraphNode(sgt_, Op_TABLE, id_) { - setRequiredOperands(2, 1); + setRequiredOperands(1, 1); setRequiredRank(0, 6); + + INIT_ATTRIBUTE(Table); } template @@ -509,36 +511,18 @@ int OpTable::checkTensorAttributes() return 1; } - if (inputs[1]->getRank() != 1) - { - printNodeValidationError("OpTable: Table must be rank 1 tensor"); - return 1; - } + ERROR_IF(inputs[0]->getDtype() != InDtype, "OpTable: Unexpected input type"); + ERROR_IF(attribute->table().size() != TableNumEntries, "OpTable: table attribute size must be %u", TableNumEntries); - if (inputs[0]->getDtype() == DType_INT8) + for (uint32_t i = 0; i < TableNumEntries; i++) { - if (inputs[1]->getElementCount() != 256 || inputs[1]->getDtype() != DType_INT8) - { - printNodeValidationError("OpTable: Table must be INT8[256] if input is INT8"); - return 1; - } - ERROR_IF(outputs[0]->getDtype() != DType_INT8, "OpTable: output tensor must be INT8"); - } - else if (inputs[0]->getDtype() == DType_INT16) - { - if (inputs[1]->getElementCount() != 513 || inputs[1]->getDtype() != DType_INT16) - { - printNodeValidationError("OpTable: Table must be INT16[513] if input is INT16"); - return 1; - } - ERROR_IF(outputs[0]->getDtype() != DType_INT32, "OpTable: output tensor must be INT32"); + table[i] = (TableEigenType)attribute->table()[i]; } - in = dynamic_cast*>(inputs[0]); - table = dynamic_cast*>(inputs[1]); - out = dynamic_cast*>(outputs[0]); + in = dynamic_cast*>(inputs[0]); + out = dynamic_cast*>(outputs[0]); - ASSERT_MEM(in && table && out); + ASSERT_MEM(in && out); return 0; } @@ -552,7 +536,7 @@ int OpTable::eval() this->out->getTensor() = this->in->getTensor().unaryExpr([this](InEigenType in) -> OutEigenType { int32_t input_truncated = std::min(std::max(in, QInMin), QInMax); int32_t index = input_truncated - QInMin; - int32_t value = this->table->getTensor()(index); + int32_t value = table[index]; return value; }); @@ -568,8 +552,8 @@ int OpTable::eval() int32_t frac = (input_truncated)&0x7F; // 7-bit fraction // 3. interpolate, generate 16.7 (23-bit) output - int32_t base = this->table->getTensor()(index); - int32_t next = this->table->getTensor()(index + 1); + int32_t base = table[index]; + int32_t next = table[index + 1]; int32_t value = (base << 7) + (next - base) * frac; return value; diff --git a/reference_model/src/ops/ewise_binary.h b/reference_model/src/ops/ewise_binary.h index fd4d408..373dfb8 100644 --- a/reference_model/src/ops/ewise_binary.h +++ b/reference_model/src/ops/ewise_binary.h @@ -184,26 +184,28 @@ public: virtual int checkTensorAttributes(); virtual int eval(); - static constexpr DType TableDtype = (InDtype == DType_INT8) ? DType_INT8 : DType_INT16; - static constexpr DType OutDtype = (InDtype == DType_INT8) ? DType_INT8 : DType_INT32; - using InEigenType = typename GetEigenType::type; - using TableEigenType = typename GetEigenType::type; - using OutEigenType = typename GetEigenType::type; - using TIn = Eigen::Tensor; - using TTable = Eigen::Tensor; - using TOut = Eigen::Tensor; - static constexpr int32_t IntegerBits = 9; - static constexpr int32_t FractionBits = 7; - static constexpr int32_t NumTableEntries = (1 << IntegerBits); - static constexpr int32_t QInMin = GetQMin::value; - static constexpr int32_t QInMax = GetQMax::value; - static constexpr int32_t QOutMin = GetQMin::value; - static constexpr int32_t QOutMax = GetQMax::value; + static constexpr DType TableDtype = (InDtype == DType_INT8) ? DType_INT8 : DType_INT16; + static constexpr DType OutDtype = (InDtype == DType_INT8) ? DType_INT8 : DType_INT32; + static constexpr uint32_t TableNumEntries = (InDtype == DType_INT8) ? 256 : 513; + using InEigenType = typename GetEigenType::type; + using TableEigenType = typename GetEigenType::type; + using OutEigenType = typename GetEigenType::type; + using TIn = Eigen::Tensor; + using TTable = Eigen::Tensor; + using TOut = Eigen::Tensor; + static constexpr int32_t IntegerBits = 9; + static constexpr int32_t FractionBits = 7; + static constexpr int32_t NumTableEntries = (1 << IntegerBits); + static constexpr int32_t QInMin = GetQMin::value; + static constexpr int32_t QInMax = GetQMax::value; + static constexpr int32_t QOutMin = GetQMin::value; + static constexpr int32_t QOutMax = GetQMax::value; protected: TosaReference::TensorTemplate* in; - TosaReference::TensorTemplate* table; TosaReference::TensorTemplate* out; + TosaTableAttribute* attribute; + std::array table; }; }; // namespace TosaReference diff --git a/thirdparty/serialization_lib b/thirdparty/serialization_lib index e6563f5..38d214c 160000 --- a/thirdparty/serialization_lib +++ b/thirdparty/serialization_lib @@ -1 +1 @@ -Subproject commit e6563f52231c603b409638b22530d016757542c8 +Subproject commit 38d214cfa4491f1956f28d7eff428a8ed07d824c diff --git a/verif/tosa_test_gen.py b/verif/tosa_test_gen.py index 105f016..b9cca18 100644 --- a/verif/tosa_test_gen.py +++ b/verif/tosa_test_gen.py @@ -676,12 +676,21 @@ class TosaArgGen: axis_pad_values = [x for x in itertools.product(pad_values, pad_values)] 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_fp = 0 + elif dtype == DType.FLOAT: + pad_const_int = 0 + pad_const_fp = testGen.getRandNumberDType(dtype) + else: + return [] + for paddings in shape_pad_values: name = "pad" for r in range(rank): before, after = paddings[r] name = f"{name}{before}{after}" - arg_list.append((name, [np.array(paddings)])) + arg_list.append((name, [np.array(paddings), pad_const_int, pad_const_fp])) return arg_list @@ -1176,6 +1185,27 @@ class TosaArgGen: return arg_list + @staticmethod + def agTable(testGen, 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() + else: # INT16 + table = np.int32( + testGen.rng.integers(low=-32768, high=32768, size=[513]) + ).tolist() + + arg_list.append( + ( + "", + [table], + ) + ) + return arg_list + def agCondIf(testGen, opName, shapeList, dtype, error_name=None): # CondIf generates the condition values here. # Convert to tensors in the build function, along with the @@ -1527,13 +1557,8 @@ class TosaErrorValidator: op = kwargs['op'] input_list = kwargs['input_list'] num_operands = kwargs['num_operands'] - # both PAD, TRANSPOSE add an extra const layer in the build function - if op['op'] in [Op.PAD, Op.TRANSPOSE]: - if len(input_list) != num_operands + 1: - error_result = True - else: - if len(input_list) != num_operands: - error_result = True + if len(input_list) != num_operands: + error_result = True info_dict = { "error_name": error_name, @@ -2907,19 +2932,13 @@ class TosaTestGen: self.ser.addOperator(op['op'], [a.name, b.name], [result_tens.name], attr) return result_tens - def build_table(self, op, a): - # Constant size depending on type, random values - if a.dtype == DType.INT16: - table_dtype = DType.INT16 - table_arr = self.getRandTensor([513], table_dtype) - else: - assert a.dtype == DType.INT8 - table_dtype = DType.INT8 - table_arr = self.getRandTensor([256], table_dtype) + def build_table(self, op, a, table): + result_tens = OutputShaper.tableOp(self.ser, a) - table_tens = self.ser.addConst(table_arr.shape, table_dtype, table_arr) - result_tens = OutputShaper.tableOp(self.ser, a, table_dtype) - self.ser.addOperator(op['op'], [a.name, table_tens.name], [result_tens.name], None) + attr = ts.TosaSerializerAttribute() + attr.TableAttribute(table) + + self.ser.addOperator(op['op'], [a.name], [result_tens.name], attr) return result_tens @@ -3219,16 +3238,14 @@ class TosaTestGen: self.ser.addOperator(op['op'], input_tensor_names, [result_tens.name], attr) return result_tens - def build_pad(self, op, a, padding, validator_fcns=None, error_name=None, qinfo=None): + def build_pad(self, op, a, padding, pad_const_int, pad_const_float, validator_fcns=None, error_name=None, qinfo=None): result_tens = OutputShaper.padOp(self.ser, self.rng, a, padding, error_name) - # Need to turn the padding array into a TOSA tensor here. - # This is one of the few tensor operands that does not get - # randomly generated - padding_tens = self.ser.addConst(padding.shape, DType.INT32, padding) + attr = ts.TosaSerializerAttribute() + attr.PadAttribute(padding.flatten(), pad_const_int, pad_const_float) # Invalidate Input/Output list for error if checks. - input_list = [a.name, padding_tens.name] + input_list = [a.name] output_list = [result_tens.name] pCount, cCount = op["operands"] num_operands = pCount + cCount @@ -3252,7 +3269,7 @@ class TosaTestGen: ) self.ser.addOperator( - op['op'], input_list, output_list, None, qinfo + op['op'], input_list, output_list, attr, qinfo ) return result_tens @@ -3299,10 +3316,11 @@ class TosaTestGen: def build_transpose(self, op, a, perms, validator_fcns=None, error_name=None): result_tens = OutputShaper.transposeOp(self.ser, self.rng, a, perms, error_name) - perms_tens = self.ser.addConst([len(perms)], DType.INT32, np.int32(perms)) + attr = ts.TosaSerializerAttribute() + attr.TransposeAttribute(perms) # Invalidate Input/Output list for error if checks. - input_list = [a.name, perms_tens.name] + input_list = [a.name] output_list = [result_tens.name] pCount, cCount = op["operands"] num_operands = pCount + cCount @@ -3325,7 +3343,7 @@ class TosaTestGen: ) - self.ser.addOperator(op['op'], input_list, output_list) + self.ser.addOperator(op['op'], input_list, output_list, attr) return result_tens def build_slice(self, op, a, start, size, validator_fcns=None, error_name=None): @@ -4564,7 +4582,7 @@ class TosaTestGen: # but create the table tensor in the build function, as it may be # a different type from the input "operands": (1, 0), - "build_fcn": (build_table, TosaTensorGen.tgBasic, None), + "build_fcn": (build_table, TosaTensorGen.tgBasic, TosaArgGen.agTable), "types": [DType.INT8, DType.INT16], }, # Elementwise Unary operators @@ -5376,10 +5394,10 @@ class OutputShaper: return ser.addOutput(output_shape, values_in.dtype) @staticmethod - def tableOp(ser, input, table_dtype): + def tableOp(ser, input): # Same shape as the input, but dtype dependent on table dtype - assert table_dtype == DType.INT16 or table_dtype == DType.INT8 - output_dtype = DType.INT32 if table_dtype == DType.INT16 else DType.INT8 + assert input.dtype == DType.INT16 or input.dtype == DType.INT8 + output_dtype = DType.INT32 if input.dtype == DType.INT16 else DType.INT8 return ser.addOutput(input.shape, output_dtype) @staticmethod -- cgit v1.2.1