From a793f4645d2c04543572de4d0bc84bf0a3689604 Mon Sep 17 00:00:00 2001 From: Jerry Ge Date: Tue, 11 Apr 2023 00:05:02 +0000 Subject: Add level checking to TOSA Ref model Signed-off-by: Jerry Ge Change-Id: I5689d7c6b902a319a68fa4628b59e0bcc23aeca4 --- reference_model/include/func_config.h | 18 ++- reference_model/include/func_debug.h | 13 +- reference_model/src/command_line_utils.h | 4 +- reference_model/src/main.cpp | 13 ++ reference_model/src/ops/activation_funcs.cc | 12 ++ reference_model/src/ops/comparison.cc | 12 ++ reference_model/src/ops/data_layout.cc | 29 ++++ reference_model/src/ops/ewise_binary.cc | 8 + reference_model/src/ops/ewise_ternary.cc | 4 + reference_model/src/ops/ewise_unary.cc | 4 + reference_model/src/ops/image.cc | 5 + reference_model/src/ops/tensor_ops.cc | 168 +++++++++++++++------ reference_model/src/ops/type_conversion.cc | 8 + .../tosa_verif_framework_compiler_runner.py | 10 ++ verif/runner/tosa_verif_run_tests.py | 8 + 15 files changed, 269 insertions(+), 47 deletions(-) diff --git a/reference_model/include/func_config.h b/reference_model/include/func_config.h index d9b51d5..c1f8ef6 100644 --- a/reference_model/include/func_config.h +++ b/reference_model/include/func_config.h @@ -1,5 +1,5 @@ -// Copyright (c) 2020-2022, ARM Limited. +// Copyright (c) 2020-2023, ARM Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,6 +19,18 @@ #include #include +struct tosa_level_t { + int32_t MAX_RANK = 0; + int32_t MAX_KERNEL = 0; + int32_t MAX_STRIDE = 0; + int32_t MAX_SCALE = 0; + + bool operator!=(const tosa_level_t &rhs) { + return !(MAX_RANK == rhs.MAX_RANK && MAX_KERNEL == rhs.MAX_KERNEL && + MAX_STRIDE == rhs.MAX_STRIDE && MAX_SCALE == rhs.MAX_SCALE); + } +}; + struct func_config_t { std::string operator_fbs = "tosa.fbs"; @@ -37,6 +49,10 @@ struct func_config_t uint32_t dump_intermediates = 0; std::string fp_format = "0.5"; bool float_is_big_endian = false; // Set in arith_util.h by float_is_big_endian() + + tosa_level_t tosa_level; + static constexpr tosa_level_t EIGHTK = { 6, 8192, 8192, 64 }; + static constexpr tosa_level_t NONE = { 0, 0, 0, 0 }; }; #endif diff --git a/reference_model/include/func_debug.h b/reference_model/include/func_debug.h index d762026..3794a35 100644 --- a/reference_model/include/func_debug.h +++ b/reference_model/include/func_debug.h @@ -1,5 +1,5 @@ -// Copyright (c) 2020, ARM Limited. +// Copyright (c) 2020-2023, ARM Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -114,6 +114,17 @@ struct func_debug_t } #endif +#ifndef LEVEL_CHECK +#define LEVEL_CHECK(COND, fmt, ...) \ + if (g_func_config.tosa_level != func_config_t::NONE && (!(COND))) \ + { \ + fprintf(g_func_debug.func_debug_file, COL_FATAL("LEVEL_CHECK() fails AT %s:%d %s(): (%s)\n"), __FILE__, __LINE__, \ + __func__, #COND); \ + fprintf(g_func_debug.func_debug_file, COL_FATAL(fmt) "\n", ##__VA_ARGS__); \ + this->parent_sgt->setGraphStatus(GraphStatus::TOSA_UNPREDICTABLE); \ + } +#endif + #ifndef ERROR_IF #define ERROR_IF(COND, fmt, ...) \ if ((COND)) \ diff --git a/reference_model/src/command_line_utils.h b/reference_model/src/command_line_utils.h index 1bd1639..4e6e555 100644 --- a/reference_model/src/command_line_utils.h +++ b/reference_model/src/command_line_utils.h @@ -1,5 +1,5 @@ -// Copyright (c) 2020-2022, ARM Limited. +// Copyright (c) 2020-2023, ARM Limited. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -56,6 +56,8 @@ int func_model_parse_cmd_line( ("output_tensors", "Output tensors to a file (0/1)", cxxopts::value(func_config.output_tensors)) ("tosa_profile", "Set TOSA profile (0 = Base Inference, 1 = Main Inference, 2 = Main Training)", cxxopts::value(func_config.tosa_profile)) + ("tosa_level", "Set TOSA level (NONE, EIGHTK)", + cxxopts::value(func_config.tosa_level)) ("dump_intermediates", "Dump intermediate tensors (0/1)", cxxopts::value(func_config.dump_intermediates)) ("v,version", "print model version") ("i,input_tensor_file", "specify input tensor files", cxxopts::value>()) diff --git a/reference_model/src/main.cpp b/reference_model/src/main.cpp index 0375a48..aad07cb 100644 --- a/reference_model/src/main.cpp +++ b/reference_model/src/main.cpp @@ -36,6 +36,7 @@ int initTestDesc(json& test_desc); int readInputTensors(SubgraphTraverser& gt, json test_desc); int writeFinalTensors(SubgraphTraverser& gt, json test_desc); int loadGraph(TosaSerializationHandler& tsh, json test_desc); +void parse_value(const std::string& text, tosa_level_t& value); int main(int argc, char** argv) { @@ -454,3 +455,15 @@ int initTestDesc(json& test_desc) return 0; } + +void parse_value(const std::string& text, tosa_level_t& value) +{ + + if (text == "NONE") + value = func_config_t::NONE; + else if (text == "EIGHTK") + value = func_config_t::EIGHTK; + else + throw cxxopts::argument_incorrect_type("TOSA_LEVEL"); + return; +} \ No newline at end of file diff --git a/reference_model/src/ops/activation_funcs.cc b/reference_model/src/ops/activation_funcs.cc index dc85088..24bd077 100644 --- a/reference_model/src/ops/activation_funcs.cc +++ b/reference_model/src/ops/activation_funcs.cc @@ -26,6 +26,10 @@ using namespace tosa; template int OpClamp::register_fcn() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + switch (Dtype) { case DType_FP16: @@ -64,6 +68,10 @@ OpClamp::~OpClamp() template int OpSigmoid::register_fcn() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + switch (Dtype) { case DType_FP16: @@ -83,6 +91,10 @@ int OpSigmoid::register_fcn() template int OpTanh::register_fcn() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + switch (Dtype) { case DType_FP16: diff --git a/reference_model/src/ops/comparison.cc b/reference_model/src/ops/comparison.cc index 5b78a4f..a5711eb 100644 --- a/reference_model/src/ops/comparison.cc +++ b/reference_model/src/ops/comparison.cc @@ -25,6 +25,10 @@ using namespace tosa; template int OpEqual::register_fcn() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + switch (Dtype) { case DType_FP16: @@ -43,6 +47,10 @@ int OpEqual::register_fcn() template int OpGreater::register_fcn() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + switch (Dtype) { case DType_FP16: @@ -61,6 +69,10 @@ int OpGreater::register_fcn() template int OpGreaterEqual::register_fcn() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + switch (Dtype) { case DType_FP16: diff --git a/reference_model/src/ops/data_layout.cc b/reference_model/src/ops/data_layout.cc index ce5b5af..a189466 100644 --- a/reference_model/src/ops/data_layout.cc +++ b/reference_model/src/ops/data_layout.cc @@ -42,6 +42,10 @@ OpConcat::~OpConcat() template int OpConcat::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; @@ -140,6 +144,10 @@ OpPad::~OpPad() template int OpPad::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; @@ -227,6 +235,11 @@ OpReshape::~OpReshape() template int OpReshape::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(InRank <= tosa_level.MAX_RANK, "InRank should be smaller than or equal to MAX_RANK"); + LEVEL_CHECK(OutRank <= tosa_level.MAX_RANK, "OutRank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; @@ -322,6 +335,10 @@ OpReverse::~OpReverse() template int OpReverse::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; @@ -389,6 +406,10 @@ OpSlice::~OpSlice() template int OpSlice::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; @@ -458,6 +479,10 @@ OpTileBase::~OpTileBase() template int OpTileBase::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; @@ -655,6 +680,10 @@ OpTranspose::~OpTranspose() template int OpTranspose::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; diff --git a/reference_model/src/ops/ewise_binary.cc b/reference_model/src/ops/ewise_binary.cc index 16386af..6aa0c0f 100644 --- a/reference_model/src/ops/ewise_binary.cc +++ b/reference_model/src/ops/ewise_binary.cc @@ -44,6 +44,10 @@ BinaryNodeBase::~BinaryNodeBase() template int BinaryNodeBase::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; @@ -540,6 +544,10 @@ OpTable::~OpTable() template int OpTable::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; diff --git a/reference_model/src/ops/ewise_ternary.cc b/reference_model/src/ops/ewise_ternary.cc index db5c240..4d53ae4 100644 --- a/reference_model/src/ops/ewise_ternary.cc +++ b/reference_model/src/ops/ewise_ternary.cc @@ -36,6 +36,10 @@ OpSelectBase::~OpSelectBase() template int OpSelectBase::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; diff --git a/reference_model/src/ops/ewise_unary.cc b/reference_model/src/ops/ewise_unary.cc index 8b79e58..8dc37e2 100644 --- a/reference_model/src/ops/ewise_unary.cc +++ b/reference_model/src/ops/ewise_unary.cc @@ -42,6 +42,10 @@ UnaryNode::~UnaryNode() template int UnaryNode::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; diff --git a/reference_model/src/ops/image.cc b/reference_model/src/ops/image.cc index 90427e4..190b354 100644 --- a/reference_model/src/ops/image.cc +++ b/reference_model/src/ops/image.cc @@ -111,6 +111,11 @@ int OpResize::eval() int16_t border_y = border[0]; int16_t border_x = border[1]; + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(scale_y_n / scale_y_d <= tosa_level.MAX_SCALE, "scale_y_n / scale_y_d should be smaller than or equal to MAX_SCALE"); + LEVEL_CHECK(scale_x_n / scale_x_d <= tosa_level.MAX_SCALE, "scale_x_n / scale_x_d should be smaller than or equal to MAX_SCALE"); + ERROR_IF(std::max({ in_height, in_width, out_height, out_width }) >= 16384, "OpResize: exceeds maximum dimension"); ERROR_IF(in_batch != out_batch, "OpResize: output tensor batch mismatch"); diff --git a/reference_model/src/ops/tensor_ops.cc b/reference_model/src/ops/tensor_ops.cc index af808e8..ab3919d 100644 --- a/reference_model/src/ops/tensor_ops.cc +++ b/reference_model/src/ops/tensor_ops.cc @@ -515,21 +515,32 @@ int OpAvgPool2d::eval() int pad_bottom = this->attribute->pad()[1]; int pad_left = this->attribute->pad()[2]; int pad_right = this->attribute->pad()[3]; - int kernel_h = this->attribute->kernel()[0]; - int kernel_w = this->attribute->kernel()[1]; - int stride_h = this->attribute->stride()[0]; - int stride_w = this->attribute->stride()[1]; + int kernel_y = this->attribute->kernel()[0]; + int kernel_x = this->attribute->kernel()[1]; + int stride_y = this->attribute->stride()[0]; + int stride_x = this->attribute->stride()[1]; + + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(kernel_y <= tosa_level.MAX_KERNEL, "kernel_y should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(kernel_x <= tosa_level.MAX_KERNEL, "kernel_x should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(stride_y <= tosa_level.MAX_STRIDE, "stride_y should be smaller than or equal to MAX_STRIDE"); + LEVEL_CHECK(stride_x <= tosa_level.MAX_STRIDE, "stride_x should be smaller than or equal to MAX_STRIDE"); + LEVEL_CHECK(pad_top <= tosa_level.MAX_KERNEL, "pad_top should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_bottom <= tosa_level.MAX_KERNEL, "pad_bottom should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_left <= tosa_level.MAX_KERNEL, "pad_left should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_right <= tosa_level.MAX_KERNEL, "pad_right should be smaller than or equal to MAX_KERNEL"); tosa::DType accum_dtype = (tosa::DType)this->attribute->accum_dtype(); DEBUG_INFO(OP, "perform AvgPool2d, input.shape=[%d,%d,%d,%d], output.shape=[%d,%d,%d,%d], kernel=[%d,%d], " "stride=[%d,%d], pad=[%d,%d,%d,%d], accum_dtype=%s", - in_batch, in_height, in_width, in_channels, out_batch, out_height, out_width, out_channels, kernel_h, - kernel_w, stride_h, stride_w, pad_top, pad_bottom, pad_left, pad_right, EnumNamesDType()[accum_dtype]); + in_batch, in_height, in_width, in_channels, out_batch, out_height, out_width, out_channels, kernel_y, + kernel_x, stride_y, stride_x, pad_top, pad_bottom, pad_left, pad_right, EnumNamesDType()[accum_dtype]); Eigen::array im2col_input_dims; - im2col_input_dims[0] = kernel_h * kernel_w; + im2col_input_dims[0] = kernel_y * kernel_x; im2col_input_dims[1] = out_batch * out_height * out_width * out_channels; Eigen::array col2im_output_dims; @@ -560,7 +571,7 @@ int OpAvgPool2d::eval() // transpose to [KH, KW, N, H * W, C] // reshape to [KH * KW, N * H * W * C] ETensor2 input_extract_patches = - input_padded.extract_image_patches(kernel_h, kernel_w, stride_h, stride_w, 1, 1, Eigen::PADDING_VALID) + input_padded.extract_image_patches(kernel_y, kernel_x, stride_y, stride_x, 1, 1, Eigen::PADDING_VALID) .shuffle(Eigen::array{ 1, 2, 0, 3, 4 }) .reshape(im2col_input_dims); @@ -571,7 +582,7 @@ int OpAvgPool2d::eval() // sum pool for (size_t i = 0; i < this->out->getElementCount(); i++) { - for (int32_t j = 0; j < kernel_h * kernel_w; j++) + for (int32_t j = 0; j < kernel_y * kernel_x; j++) { out_1d(i) += (AccEigenType)input_extract_patches(j, i); } @@ -582,8 +593,8 @@ int OpAvgPool2d::eval() // calculate 1d height/width div_map (number of elements this pooling window covers) // and outer product to get 2d div_map, then reshape/broadcast to [N, H, W, C] - ETensor1 div_map_h = calculate_div_map_1d(in_height, out_height, kernel_h, stride_h, pad_top, pad_bottom); - ETensor1 div_map_w = calculate_div_map_1d(in_width, out_width, kernel_w, stride_w, pad_left, pad_right); + ETensor1 div_map_h = calculate_div_map_1d(in_height, out_height, kernel_y, stride_x, pad_top, pad_bottom); + ETensor1 div_map_w = calculate_div_map_1d(in_width, out_width, kernel_x, stride_x, pad_left, pad_right); Eigen::array, 1> contract_dims = { Eigen::IndexPair(1, 0) }; Eigen::array bcast{ out_batch, 1, 1, out_channels }; @@ -709,16 +720,27 @@ int OpConv2d::eval() int pad_left = this->attribute->pad()[2]; int pad_right = this->attribute->pad()[3]; - int stride_h = this->attribute->stride()[0]; - int stride_w = this->attribute->stride()[1]; - int dilation_h = this->attribute->dilation()[0]; - int dilation_w = this->attribute->dilation()[1]; + int stride_y = this->attribute->stride()[0]; + int stride_x = this->attribute->stride()[1]; + int dilation_y = this->attribute->dilation()[0]; + int dilation_x = this->attribute->dilation()[1]; + + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(dilation_y * f_height <= tosa_level.MAX_KERNEL, "dilation_y * KH should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(dilation_x * f_width <= tosa_level.MAX_KERNEL, "dilation_x * KW should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_top <= tosa_level.MAX_KERNEL, "pad_top should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_bottom <= tosa_level.MAX_KERNEL, "pad_bottom should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_left <= tosa_level.MAX_KERNEL, "pad_left should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_right <= tosa_level.MAX_KERNEL, "pad_right should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(stride_y <= tosa_level.MAX_STRIDE, "stride_y should be smaller than or equal to MAX_STRIDE"); + LEVEL_CHECK(stride_x <= tosa_level.MAX_STRIDE, "stride_x should be smaller than or equal to MAX_STRIDE"); DEBUG_INFO(OP, "perform OpConv2d, input.shape=[%d,%d,%d,%d], weight.shape=[%d,%d,%d,%d], output.shape=[%d,%d,%d,%d], " "stride=[%d,%d], dilation=[%d,%d], pad=[%d,%d,%d,%d]", in_batch, in_height, in_width, in_channels, f_height, f_width, f_in_channels, f_out_channels, out_batch, - out_height, out_width, out_channels, stride_h, stride_w, dilation_h, dilation_w, pad_top, + out_height, out_width, out_channels, stride_y, stride_x, dilation_y, dilation_x, pad_top, pad_bottom, pad_left, pad_right); // GEMM-conv2d, left matrix is input, right matrix is weight @@ -771,7 +793,7 @@ int OpConv2d::eval() // need to transpose to [N, H * W, KH, KW, C] ETensor5 input_extract_patches = input_padded - .extract_image_patches(f_height, f_width, stride_h, stride_w, dilation_h, dilation_w, Eigen::PADDING_VALID) + .extract_image_patches(f_height, f_width, stride_y, stride_x, dilation_y, dilation_x, Eigen::PADDING_VALID) .shuffle(Eigen::array{ 0, 3, 1, 2, 4 }); // reshape input to [N * H * W, KH * KW * C] @@ -898,20 +920,35 @@ int OpConv3d::eval() int pad_right = this->attribute->pad()[5]; int stride_d = this->attribute->stride()[0]; - int stride_h = this->attribute->stride()[1]; - int stride_w = this->attribute->stride()[2]; + int stride_y = this->attribute->stride()[1]; + int stride_x = this->attribute->stride()[2]; int dilation_d = this->attribute->dilation()[0]; - int dilation_h = this->attribute->dilation()[1]; - int dilation_w = this->attribute->dilation()[2]; + int dilation_y = this->attribute->dilation()[1]; + int dilation_x = this->attribute->dilation()[2]; + + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(dilation_d * f_depth <= tosa_level.MAX_KERNEL, "dilation_d * KD should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(dilation_y * f_height <= tosa_level.MAX_KERNEL, "dilation_y * KH should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(dilation_x * f_width <= tosa_level.MAX_KERNEL, "dilation_x * KW should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_d0 <= tosa_level.MAX_KERNEL, "pad_d0 should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_d1 <= tosa_level.MAX_KERNEL, "pad_d1 should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_top <= tosa_level.MAX_KERNEL, "pad_top should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_bottom <= tosa_level.MAX_KERNEL, "pad_bottom should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_left <= tosa_level.MAX_KERNEL, "pad_left should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_right <= tosa_level.MAX_KERNEL, "pad_right should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(stride_y <= tosa_level.MAX_STRIDE, "stride_y should be smaller than or equal to MAX_STRIDE"); + LEVEL_CHECK(stride_x <= tosa_level.MAX_STRIDE, "stride_x should be smaller than or equal to MAX_STRIDE"); + LEVEL_CHECK(stride_d <= tosa_level.MAX_STRIDE, "stride_d should be smaller than or equal to MAX_STRIDE"); DEBUG_INFO( OP, "perform OpConv3d, input.shape=[%d,%d,%d,%d,%d], weight.shape=[%d,%d,%d,%d,%d], output.shape=[%d,%d,%d,%d,%d], " "stride=[%d,%d,%d], dilation=[%d,%d,%d], pad=[%d,%d,%d,%d,%d,%d]", in_batch, in_depth, in_height, in_width, in_channels, f_out_channels, f_depth, f_height, f_width, f_in_channels, - out_batch, out_depth, out_height, out_width, out_channels, stride_d, stride_h, stride_w, dilation_d, dilation_h, - dilation_w, pad_d0, pad_d1, pad_top, pad_bottom, pad_left, pad_right); + out_batch, out_depth, out_height, out_width, out_channels, stride_d, stride_y, stride_x, dilation_d, dilation_y, + dilation_x, pad_d0, pad_d1, pad_top, pad_bottom, pad_left, pad_right); Eigen::array, 5> pad; pad[0] = std::make_pair(0, 0); @@ -964,10 +1001,10 @@ int OpConv3d::eval() d_idx = od * stride_d + fd * dilation_d; for (int fh = 0; fh < f_height; fh++) { - h_idx = oh * stride_h + fh * dilation_h; + h_idx = oh * stride_y + fh * dilation_y; for (int fw = 0; fw < f_width; fw++) { - w_idx = ow * stride_w + fw * dilation_w; + w_idx = ow * stride_x + fw * dilation_x; for (int ic = 0; ic < in_channels; ic++) { acc += ((AccEigenType)input_padded(ob, d_idx, h_idx, w_idx, ic) * @@ -1081,16 +1118,27 @@ int OpDepthwiseConv2d::eval() int pad_left = this->attribute->pad()[2]; int pad_right = this->attribute->pad()[3]; - int stride_h = this->attribute->stride()[0]; - int stride_w = this->attribute->stride()[1]; - int dilation_h = this->attribute->dilation()[0]; - int dilation_w = this->attribute->dilation()[1]; + int stride_y = this->attribute->stride()[0]; + int stride_x = this->attribute->stride()[1]; + int dilation_y = this->attribute->dilation()[0]; + int dilation_x = this->attribute->dilation()[1]; + + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(dilation_y * f_height <= tosa_level.MAX_KERNEL, "dilation_y * KH should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(dilation_x * f_width <= tosa_level.MAX_KERNEL, "dilation_x * KW should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_top <= tosa_level.MAX_KERNEL, "pad_top should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_bottom <= tosa_level.MAX_KERNEL, "pad_bottom should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_left <= tosa_level.MAX_KERNEL, "pad_left should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_right <= tosa_level.MAX_KERNEL, "pad_right should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(stride_y <= tosa_level.MAX_STRIDE, "stride_y should be smaller than or equal to MAX_STRIDE"); + LEVEL_CHECK(stride_x <= tosa_level.MAX_STRIDE, "stride_x should be smaller than or equal to MAX_STRIDE"); DEBUG_INFO(OP, "perform OpDepthwiseConv2d, input.shape=[%d,%d,%d,%d], weight.shape=[%d,%d,%d,%d], " "output.shape=[%d,%d,%d,%d], stride=[%d,%d], dilation=[%d,%d], pad=[%d,%d,%d,%d]", in_batch, in_height, in_width, in_channels, f_height, f_width, f_in_channels, f_multiplier, out_batch, - out_height, out_width, out_channels, stride_h, stride_w, dilation_h, dilation_w, pad_top, + out_height, out_width, out_channels, stride_y, stride_x, dilation_y, dilation_x, pad_top, pad_bottom, pad_left, pad_right); Eigen::array, 4> pad; @@ -1115,7 +1163,7 @@ int OpDepthwiseConv2d::eval() // 1. extract_image_patches() output [N, KH, KW, OH * OW, IC] ETensor5 input_extract_patches = input_padded.extract_image_patches( - f_height, f_width, stride_h, stride_w, dilation_h, dilation_w, Eigen::PADDING_VALID); + f_height, f_width, stride_y, stride_x, dilation_y, dilation_x, Eigen::PADDING_VALID); Eigen::array reshape_dim; reshape_dim.fill(1); @@ -1466,19 +1514,30 @@ int OpMaxPool2d::eval() int pad_left = this->attribute->pad()[2]; int pad_right = this->attribute->pad()[3]; - int kernel_h = this->attribute->kernel()[0]; - int kernel_w = this->attribute->kernel()[1]; - int stride_h = this->attribute->stride()[0]; - int stride_w = this->attribute->stride()[1]; + int kernel_y = this->attribute->kernel()[0]; + int kernel_x = this->attribute->kernel()[1]; + int stride_y = this->attribute->stride()[0]; + int stride_x = this->attribute->stride()[1]; + + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(kernel_y <= tosa_level.MAX_KERNEL, "kernel_y should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(kernel_x <= tosa_level.MAX_KERNEL, "kernel_x should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(stride_y <= tosa_level.MAX_STRIDE, "stride_y should be smaller than or equal to MAX_STRIDE"); + LEVEL_CHECK(stride_x <= tosa_level.MAX_STRIDE, "stride_x should be smaller than or equal to MAX_STRIDE"); + LEVEL_CHECK(pad_top <= tosa_level.MAX_KERNEL, "pad_top should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_bottom <= tosa_level.MAX_KERNEL, "pad_bottom should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_left <= tosa_level.MAX_KERNEL, "pad_left should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(pad_right <= tosa_level.MAX_KERNEL, "pad_right should be smaller than or equal to MAX_KERNEL"); DEBUG_INFO(OP, "perform MaxPool2d, input.shape=[%d,%d,%d,%d], output.shape=[%d,%d,%d,%d], kernel=[%d,%d], " "stride=[%d,%d], pad=[%d,%d,%d,%d]", - in_batch, in_height, in_width, in_channels, out_batch, out_height, out_width, out_channels, kernel_h, - kernel_w, stride_h, stride_w, pad_top, pad_bottom, pad_left, pad_right); + in_batch, in_height, in_width, in_channels, out_batch, out_height, out_width, out_channels, kernel_y, + kernel_x, stride_y, stride_x, pad_top, pad_bottom, pad_left, pad_right); Eigen::array im2col_input_dims; - im2col_input_dims[0] = kernel_h * kernel_w; + im2col_input_dims[0] = kernel_y * kernel_x; im2col_input_dims[1] = out_batch * out_height * out_width * out_channels; Eigen::array col2im_output_dims; @@ -1504,7 +1563,7 @@ int OpMaxPool2d::eval() // to or smaller than the actual maximum in the KH x KW patch. ETensor2 input_extract_patches = input_padded - .extract_image_patches(kernel_h, kernel_w, stride_h, stride_w, 1, 1, Eigen::PADDING_VALID, + .extract_image_patches(kernel_y, kernel_x, stride_y, stride_x, 1, 1, Eigen::PADDING_VALID, std::numeric_limits::lowest()) .shuffle(Eigen::array{ 1, 2, 0, 3, 4 }) .reshape(im2col_input_dims); @@ -1603,6 +1662,11 @@ int OpFFT2d::eval() int out_imag_height = this->out_imag->getShape()[1]; int out_imag_width = this->out_imag->getShape()[2]; + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(in_real_height <= tosa_level.MAX_KERNEL, "H should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(in_real_width <= tosa_level.MAX_KERNEL, "W should be smaller than or equal to MAX_KERNEL"); + DEBUG_INFO(OP, "perform OpFFT2d, input.shapes=[[%d,%d,%d],[%d,%d,%d]], output.shapes=[[%d,%d,%d],[%d,%d,%d]]", in_real_batch, in_real_height, in_real_width, @@ -1710,6 +1774,11 @@ int OpRFFT2d::eval() int32_t out_imag_height = out_imag->getShape()[1]; int32_t out_imag_width = out_imag->getShape()[2]; + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(in_height <= tosa_level.MAX_KERNEL, "H should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(in_width <= tosa_level.MAX_KERNEL, "W should be smaller than or equal to MAX_KERNEL"); + DEBUG_INFO(OP, "perform OpRFFT2d, input.shape=[%d,%d,%d], output_real.shape=[%d,%d,%d], " "output_imag.shape=[%d,%d,%d]", @@ -1885,8 +1954,8 @@ int OpTransposeConv2d::eval() int out_pad_left = this->attribute->out_pad()[2]; int out_pad_right = this->attribute->out_pad()[3]; - int stride_h = this->attribute->stride()[0]; - int stride_w = this->attribute->stride()[1]; + int stride_y = this->attribute->stride()[0]; + int stride_x = this->attribute->stride()[1]; ERROR_IF(in_batch != out_batch, "OpTransposeConv2d: tensor batch mismatch %d != %d", in_batch, out_batch); ERROR_IF(f_in_channels != in_channels, "OpTransposeConv2d: tensor input channel mismatch %d != %d", f_in_channels, @@ -1896,11 +1965,22 @@ int OpTransposeConv2d::eval() ERROR_IF(b_out_channels != out_channels, "OpDepthwiseConv2d: bias channels mismatch %d != %d", b_out_channels, out_channels); + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(f_height <= tosa_level.MAX_KERNEL, "KH should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(f_width <= tosa_level.MAX_KERNEL, "KW should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(out_pad_top <= tosa_level.MAX_KERNEL, "out_pad_top should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(out_pad_bottom <= tosa_level.MAX_KERNEL, "out_pad_bottom should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(out_pad_left <= tosa_level.MAX_KERNEL, "out_pad_left should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(out_pad_right <= tosa_level.MAX_KERNEL, "out_pad_right should be smaller than or equal to MAX_KERNEL"); + LEVEL_CHECK(stride_y <= tosa_level.MAX_STRIDE, "stride_y should be smaller than or equal to MAX_STRIDE"); + LEVEL_CHECK(stride_x <= tosa_level.MAX_STRIDE, "stride_x should be smaller than or equal to MAX_STRIDE"); + DEBUG_INFO(OP, "perform OpTransposeConv2d, input.shape=[%d,%d,%d,%d], weight.shape=[%d,%d,%d,%d], " "output.shape=[%d,%d,%d,%d], stride=[%d,%d], out_pad=[%d,%d,%d,%d]", in_batch, in_height, in_width, in_channels, f_height, f_width, f_out_channels, f_in_channels, - out_batch, out_height, out_width, out_channels, stride_h, stride_w, out_pad_top, + out_batch, out_height, out_width, out_channels, stride_y, stride_x, out_pad_top, out_pad_bottom, out_pad_left, out_pad_right); TIn input_val = this->input->getTensor(); @@ -1934,8 +2014,8 @@ int OpTransposeConv2d::eval() { for (int iw = 0; iw < in_width; iw++) { - out_x_origin = iw * stride_w + out_pad_left; - out_y_origin = ih * stride_h + out_pad_top; + out_x_origin = iw * stride_x + out_pad_left; + out_y_origin = ih * stride_y + out_pad_top; for (int ic = 0; ic < in_channels; ic++) { for (int fh = 0; fh < f_height; fh++) diff --git a/reference_model/src/ops/type_conversion.cc b/reference_model/src/ops/type_conversion.cc index a3140c3..9034add 100644 --- a/reference_model/src/ops/type_conversion.cc +++ b/reference_model/src/ops/type_conversion.cc @@ -45,6 +45,10 @@ OpRescale::~OpRescale() template int OpRescale::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; @@ -250,6 +254,10 @@ OpCast::~OpCast() template int OpCast::checkTensorAttributes() { + // Check Tosa Level + auto tosa_level = g_func_config.tosa_level; + LEVEL_CHECK(Rank <= tosa_level.MAX_RANK, "Rank should be smaller than or equal to MAX_RANK"); + if (validateRequiredOperands()) return 1; diff --git a/verif/frameworks/tosa_verif_framework_compiler_runner.py b/verif/frameworks/tosa_verif_framework_compiler_runner.py index 71723ae..0d98c17 100755 --- a/verif/frameworks/tosa_verif_framework_compiler_runner.py +++ b/verif/frameworks/tosa_verif_framework_compiler_runner.py @@ -73,6 +73,14 @@ def parse_args(): type=float, help="Comparison tolerance b value", ) + parser.add_argument( + "--tosa_level", + dest="tosa_level", + default="EIGHTK", + type=str, + help="A TOSA level defines operator parameter ranges that an implementation shall support." + "Config tosa_level for running the reference model only. Default is EIGHTK", + ) parser.add_argument( "--no-compiler", dest="no_compiler", @@ -552,6 +560,8 @@ def run_test(args, test, framework): "-q", ] + ref_model_cmd + ref_model_cmd = ref_model_cmd + ["--tosa_level={}".format(args.tosa_level)] + # Clean out any ref_model result first try: os.remove(os.path.join(test, flatbuffer_dir, "ref_model_*.npy")) diff --git a/verif/runner/tosa_verif_run_tests.py b/verif/runner/tosa_verif_run_tests.py index ddb32a4..6b5d77e 100644 --- a/verif/runner/tosa_verif_run_tests.py +++ b/verif/runner/tosa_verif_run_tests.py @@ -139,6 +139,14 @@ def parseArgs(argv): choices=["tosa-bi", "tosa-mi"], help="Filter tests based on profile", ) + parser.add_argument( + "--tosa_level", + dest="tosa_level", + default="EIGHTK", + type=str, + help="A TOSA level defines operator parameter ranges that an implementation shall support." + "Config tosa_level for running the reference model only. Default is EIGHTK", + ) args = parser.parse_args(argv) -- cgit v1.2.1